STOMP and WebSocket messaging related logging updates
This change removes most logging at INFO level and also ensures the amount of information logged at DEBUG level is useful, brief, and not duplicated. Also added is custom logging for STOMP frames to ensure very readable and consise output. Issue: SPR-11934
This commit is contained in:
@@ -40,7 +40,8 @@ import org.springframework.web.socket.WebSocketSession;
|
||||
*/
|
||||
public abstract class AbstractWebSocketSession<T> implements NativeWebSocketSession {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
protected static final Log logger = LogFactory.getLog(NativeWebSocketSession.class);
|
||||
|
||||
|
||||
private T nativeSession;
|
||||
|
||||
@@ -133,8 +134,8 @@ public abstract class AbstractWebSocketSession<T> implements NativeWebSocketSess
|
||||
@Override
|
||||
public final void close(CloseStatus status) throws IOException {
|
||||
checkNativeSessionInitialized();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Closing " + this);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Closing " + this);
|
||||
}
|
||||
closeInternal(status);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -122,8 +122,8 @@ public abstract class ConnectionManagerSupport implements SmartLifecycle {
|
||||
|
||||
protected void startInternal() {
|
||||
synchronized (lifecycleMonitor) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Starting " + this.getClass().getSimpleName());
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Starting " + this.getClass().getSimpleName());
|
||||
}
|
||||
this.isRunning = true;
|
||||
openConnection();
|
||||
@@ -136,8 +136,8 @@ public abstract class ConnectionManagerSupport implements SmartLifecycle {
|
||||
public final void stop() {
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
if (isRunning()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Stopping " + this.getClass().getSimpleName());
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Stopping " + this.getClass().getSimpleName());
|
||||
}
|
||||
try {
|
||||
stopInternal();
|
||||
|
||||
@@ -128,8 +128,8 @@ public class JettyWebSocketClient extends AbstractWebSocketClient implements Sma
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
if (!isRunning()) {
|
||||
try {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Starting Jetty WebSocketClient");
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Starting Jetty WebSocketClient");
|
||||
}
|
||||
this.client.start();
|
||||
}
|
||||
@@ -145,8 +145,8 @@ public class JettyWebSocketClient extends AbstractWebSocketClient implements Sma
|
||||
synchronized (this.lifecycleMonitor) {
|
||||
if (isRunning()) {
|
||||
try {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Stopping Jetty WebSocketClient");
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Stopping Jetty WebSocketClient");
|
||||
}
|
||||
this.client.stop();
|
||||
}
|
||||
|
||||
@@ -176,14 +176,14 @@ public class StandardWebSocketClient extends AbstractWebSocketClient {
|
||||
@Override
|
||||
public void beforeRequest(Map<String, List<String>> requestHeaders) {
|
||||
requestHeaders.putAll(this.headers);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Handshake request headers: " + requestHeaders);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Handshake request headers: " + requestHeaders);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void afterResponse(HandshakeResponse response) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Handshake response headers: " + response.getHeaders());
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Handshake response headers: " + response.getHeaders());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class WebSocketMessageBrokerStats {
|
||||
|
||||
private ScheduledFuture<?> loggingTask;
|
||||
|
||||
private long loggingPeriod = 15 * 60 * 1000;
|
||||
private long loggingPeriod = 30 * 60 * 1000;
|
||||
|
||||
|
||||
public void setSubProtocolWebSocketHandler(SubProtocolWebSocketHandler webSocketHandler) {
|
||||
@@ -102,7 +102,7 @@ public class WebSocketMessageBrokerStats {
|
||||
|
||||
public void setSockJsTaskScheduler(ThreadPoolTaskScheduler sockJsTaskScheduler) {
|
||||
this.sockJsTaskScheduler = sockJsTaskScheduler.getScheduledThreadPoolExecutor();
|
||||
this.loggingTask = initLoggingTask(3 * 60 * 1000);
|
||||
this.loggingTask = initLoggingTask(1 * 60 * 1000);
|
||||
}
|
||||
|
||||
private ScheduledFuture<?> initLoggingTask(long initialDelay) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -60,9 +60,6 @@ public class BeanCreatingHandlerProvider<T> implements BeanFactoryAware {
|
||||
}
|
||||
|
||||
public T getHandler() {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Creating instance for handler type " + this.handlerType);
|
||||
}
|
||||
if (this.beanFactory == null) {
|
||||
logger.warn("No BeanFactory available, attempting to use default constructor");
|
||||
return BeanUtils.instantiate(this.handlerType);
|
||||
@@ -74,16 +71,13 @@ public class BeanCreatingHandlerProvider<T> implements BeanFactoryAware {
|
||||
|
||||
public void destroy(T handler) {
|
||||
if (this.beanFactory != null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Destroying handler instance " + handler);
|
||||
}
|
||||
this.beanFactory.destroyBean(handler);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BeanCreatingHandlerProvider [handlerClass=" + this.handlerType + "]";
|
||||
return "BeanCreatingHandlerProvider[handlerType=" + this.handlerType + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ import org.springframework.web.socket.WebSocketSession;
|
||||
*/
|
||||
public class ConcurrentWebSocketSessionDecorator extends WebSocketSessionDecorator {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ConcurrentWebSocketSessionDecorator.class);
|
||||
private static final Log logger = LogFactory.getLog("_" + ConcurrentWebSocketSessionDecorator.class.getName());
|
||||
|
||||
|
||||
private final Queue<WebSocketMessage<?>> buffer = new LinkedBlockingQueue<WebSocketMessage<?>>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,7 +31,7 @@ import org.springframework.web.socket.WebSocketSession;
|
||||
*/
|
||||
public class LoggingWebSocketHandlerDecorator extends WebSocketHandlerDecorator {
|
||||
|
||||
private final Log logger = LogFactory.getLog(LoggingWebSocketHandlerDecorator.class);
|
||||
private static final Log logger = LogFactory.getLog(LoggingWebSocketHandlerDecorator.class);
|
||||
|
||||
|
||||
public LoggingWebSocketHandlerDecorator(WebSocketHandler delegate) {
|
||||
@@ -41,8 +41,8 @@ public class LoggingWebSocketHandlerDecorator extends WebSocketHandlerDecorator
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Connection established " + session);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("New " + session);
|
||||
}
|
||||
super.afterConnectionEstablished(session);
|
||||
}
|
||||
@@ -65,8 +65,8 @@ public class LoggingWebSocketHandlerDecorator extends WebSocketHandlerDecorator
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Connection closed with " + closeStatus + " in " + session + ", ");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(session + " closed with " + closeStatus);
|
||||
}
|
||||
super.afterConnectionClosed(session, closeStatus);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,6 +50,7 @@ public class PerConnectionWebSocketHandler implements WebSocketHandler, BeanFact
|
||||
|
||||
private static final Log logger = LogFactory.getLog(PerConnectionWebSocketHandler.class);
|
||||
|
||||
|
||||
private final BeanCreatingHandlerProvider<WebSocketHandler> provider;
|
||||
|
||||
private final Map<WebSocketSession, WebSocketHandler> handlers =
|
||||
@@ -113,7 +114,7 @@ public class PerConnectionWebSocketHandler implements WebSocketHandler, BeanFact
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
logger.warn("Error while destroying handler", t);
|
||||
logger.warn("Error while destroying " + handler, t);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +125,7 @@ public class PerConnectionWebSocketHandler implements WebSocketHandler, BeanFact
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PerConnectionWebSocketHandlerProxy [handlerType=" + this.provider.getHandlerType() + "]";
|
||||
return "PerConnectionWebSocketHandlerProxy[handlerType=" + this.provider.getHandlerType() + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -198,8 +198,9 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
|
||||
messages = decoder.decode(byteBuffer);
|
||||
if (messages.isEmpty()) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Incomplete STOMP frame content received, bufferSize=" +
|
||||
decoder.getBufferSize() + ", bufferSizeLimit=" + decoder.getBufferSizeLimit() + ".");
|
||||
logger.trace("Incomplete STOMP frame content received in session " +
|
||||
session + ", bufferSize=" + decoder.getBufferSize() +
|
||||
", bufferSizeLimit=" + decoder.getBufferSizeLimit() + ".");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -219,9 +220,7 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
|
||||
MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(headerAccessor.isHeartbeat() ?
|
||||
"Received heartbeat from broker in session " + session.getId() + "." :
|
||||
"Received message from broker in session " + session.getId() + ": " + message + ".");
|
||||
logger.trace("From client: " + headerAccessor.getShortLogMessage(message.getPayload()));
|
||||
}
|
||||
|
||||
headerAccessor.setSessionId(session.getId());
|
||||
@@ -264,9 +263,6 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
|
||||
|
||||
private void publishEvent(ApplicationEvent event) {
|
||||
try {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Publishing " + event);
|
||||
}
|
||||
this.eventPublisher.publishEvent(event);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
@@ -300,9 +296,7 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
|
||||
StompCommand command = stompAccessor.getCommand();
|
||||
if (StompCommand.MESSAGE.equals(command)) {
|
||||
if (stompAccessor.getSubscriptionId() == null) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("No STOMP \"subscription\" header in " + message);
|
||||
}
|
||||
logger.warn("No STOMP \"subscription\" header in " + message);
|
||||
}
|
||||
String origDestination = stompAccessor.getFirstNativeHeader(SimpMessageHeaderAccessor.ORIGINAL_DESTINATION);
|
||||
if (origDestination != null) {
|
||||
@@ -418,10 +412,6 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
|
||||
if (heartbeat[1] > 0) {
|
||||
session = WebSocketSessionDecorator.unwrap(session);
|
||||
if (session instanceof SockJsSession) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("STOMP heartbeats enabled. " +
|
||||
"Turning off SockJS heartbeats in " + session.getId() + ".");
|
||||
}
|
||||
((SockJsSession) session).disableHeartbeat();
|
||||
}
|
||||
}
|
||||
@@ -482,6 +472,10 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
|
||||
return MessageBuilder.createMessage(EMPTY_PAYLOAD, headerAccessor.getMessageHeaders());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StompSubProtocolHandler" + getSupportedProtocols();
|
||||
}
|
||||
|
||||
private class Stats {
|
||||
|
||||
|
||||
@@ -265,9 +265,6 @@ public class SubProtocolWebSocketHandler implements WebSocketHandler,
|
||||
this.stats.incrementSessionCount(session);
|
||||
session = new ConcurrentWebSocketSessionDecorator(session, getSendTimeLimit(), getSendBufferSizeLimit());
|
||||
this.sessions.put(session.getId(), new WebSocketSessionHolder(session));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Started session " + session.getId() + " (" + this.sessions.size() + " sessions)");
|
||||
}
|
||||
findProtocolHandler(session).afterSessionStarted(session, this.clientInboundChannel);
|
||||
}
|
||||
|
||||
@@ -422,7 +419,7 @@ public class SubProtocolWebSocketHandler implements WebSocketHandler,
|
||||
|
||||
private void clearSession(WebSocketSession session, CloseStatus closeStatus) throws Exception {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Clearing session " + session.getId() + " (" + this.sessions.size() + " remain)");
|
||||
logger.debug("Clearing session " + session.getId());
|
||||
}
|
||||
if (this.sessions.remove(session.getId()) != null) {
|
||||
this.stats.decrementSessionCount(session);
|
||||
@@ -435,6 +432,10 @@ public class SubProtocolWebSocketHandler implements WebSocketHandler,
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SubProtocolWebSocketHandler" + getProtocolHandlers();
|
||||
}
|
||||
|
||||
private static class WebSocketSessionHolder {
|
||||
|
||||
|
||||
@@ -156,24 +156,23 @@ public class DefaultHandshakeHandler implements HandshakeHandler {
|
||||
WebSocketHandler wsHandler, Map<String, Object> attributes) throws HandshakeFailureException {
|
||||
|
||||
WebSocketHttpHeaders headers = new WebSocketHttpHeaders(request.getHeaders());
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Initiating handshake for " + request.getURI() + ", headers=" + headers);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Processing request " + request.getURI() + " with headers=" + headers);
|
||||
}
|
||||
|
||||
try {
|
||||
if (!HttpMethod.GET.equals(request.getMethod())) {
|
||||
response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED);
|
||||
response.getHeaders().setAllow(Collections.singleton(HttpMethod.GET));
|
||||
logger.debug("Only HTTP GET is allowed, current method is " + request.getMethod());
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Handshake failed due to unexpected HTTP method: " + request.getMethod());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!"WebSocket".equalsIgnoreCase(headers.getUpgrade())) {
|
||||
handleInvalidUpgradeHeader(request, response);
|
||||
return false;
|
||||
}
|
||||
if (!headers.getConnection().contains("Upgrade") &&
|
||||
!headers.getConnection().contains("upgrade")) {
|
||||
if (!headers.getConnection().contains("Upgrade") && !headers.getConnection().contains("upgrade")) {
|
||||
handleInvalidConnectHeader(request, response);
|
||||
return false;
|
||||
}
|
||||
@@ -187,7 +186,9 @@ public class DefaultHandshakeHandler implements HandshakeHandler {
|
||||
}
|
||||
String wsKey = headers.getSecWebSocketKey();
|
||||
if (wsKey == null) {
|
||||
logger.debug("Missing \"Sec-WebSocket-Key\" header");
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Missing \"Sec-WebSocket-Key\" header");
|
||||
}
|
||||
response.setStatusCode(HttpStatus.BAD_REQUEST);
|
||||
return false;
|
||||
}
|
||||
@@ -198,33 +199,30 @@ public class DefaultHandshakeHandler implements HandshakeHandler {
|
||||
}
|
||||
|
||||
String subProtocol = selectProtocol(headers.getSecWebSocketProtocol(), wsHandler);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Selected sub-protocol: '" + subProtocol + "'");
|
||||
}
|
||||
|
||||
List<WebSocketExtension> requested = headers.getSecWebSocketExtensions();
|
||||
List<WebSocketExtension> supported = this.requestUpgradeStrategy.getSupportedExtensions(request);
|
||||
List<WebSocketExtension> extensions = filterRequestedExtensions(request, requested, supported);
|
||||
|
||||
Principal user = determineUser(request, wsHandler, attributes);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Upgrading request, sub-protocol=" + subProtocol + ", extensions=" + extensions);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Upgrading to WebSocket");
|
||||
}
|
||||
|
||||
this.requestUpgradeStrategy.upgrade(request, response, subProtocol, extensions, user, wsHandler, attributes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void handleInvalidUpgradeHeader(ServerHttpRequest request, ServerHttpResponse response) throws IOException {
|
||||
logger.debug("Invalid Upgrade header " + request.getHeaders().getUpgrade());
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Handshake failed due to invalid Upgrade header: " + request.getHeaders().getUpgrade());
|
||||
}
|
||||
response.setStatusCode(HttpStatus.BAD_REQUEST);
|
||||
response.getBody().write("Can \"Upgrade\" only to \"WebSocket\".".getBytes("UTF-8"));
|
||||
}
|
||||
|
||||
protected void handleInvalidConnectHeader(ServerHttpRequest request, ServerHttpResponse response) throws IOException {
|
||||
logger.debug("Invalid Connection header " + request.getHeaders().getConnection());
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Handshake failed due to invalid Connection header " + request.getHeaders().getConnection());
|
||||
}
|
||||
response.setStatusCode(HttpStatus.BAD_REQUEST);
|
||||
response.getBody().write("\"Connection\" must be \"upgrade\".".getBytes("UTF-8"));
|
||||
}
|
||||
@@ -232,17 +230,11 @@ public class DefaultHandshakeHandler implements HandshakeHandler {
|
||||
protected boolean isWebSocketVersionSupported(WebSocketHttpHeaders httpHeaders) {
|
||||
String version = httpHeaders.getSecWebSocketVersion();
|
||||
String[] supportedVersions = getSupportedVersions();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Requested version=" + version + ", supported=" + Arrays.toString(supportedVersions));
|
||||
}
|
||||
for (String supportedVersion : supportedVersions) {
|
||||
if (supportedVersion.trim().equals(version)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Version " + version + " is not a supported WebSocket version");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -251,12 +243,14 @@ public class DefaultHandshakeHandler implements HandshakeHandler {
|
||||
}
|
||||
|
||||
protected void handleWebSocketVersionNotSupported(ServerHttpRequest request, ServerHttpResponse response) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("WebSocket version not supported: " + request.getHeaders().get("Sec-WebSocket-Version"));
|
||||
if (logger.isErrorEnabled()) {
|
||||
String version = request.getHeaders().getFirst("Sec-WebSocket-Version");
|
||||
logger.error("Handshake failed due to unsupported WebSocket version: " + version +
|
||||
". Supported versions: " + Arrays.toString(getSupportedVersions()));
|
||||
}
|
||||
response.setStatusCode(HttpStatus.UPGRADE_REQUIRED);
|
||||
response.getHeaders().put(WebSocketHttpHeaders.SEC_WEBSOCKET_VERSION, Arrays.asList(
|
||||
StringUtils.arrayToCommaDelimitedString(getSupportedVersions())));
|
||||
response.getHeaders().put(WebSocketHttpHeaders.SEC_WEBSOCKET_VERSION,
|
||||
Arrays.asList(StringUtils.arrayToCommaDelimitedString(getSupportedVersions())));
|
||||
}
|
||||
|
||||
protected boolean isValidOrigin(ServerHttpRequest request) {
|
||||
@@ -277,11 +271,6 @@ public class DefaultHandshakeHandler implements HandshakeHandler {
|
||||
protected String selectProtocol(List<String> requestedProtocols, WebSocketHandler webSocketHandler) {
|
||||
if (requestedProtocols != null) {
|
||||
List<String> handlerProtocols = determineHandlerSupportedProtocols(webSocketHandler);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Requested sub-protocol(s): " + requestedProtocols +
|
||||
", WebSocketHandler supported sub-protocol(s): " + handlerProtocols +
|
||||
", configured sub-protocol(s): " + this.supportedProtocols);
|
||||
}
|
||||
for (String protocol : requestedProtocols) {
|
||||
if (handlerProtocols.contains(protocol.toLowerCase())) {
|
||||
return protocol;
|
||||
@@ -322,11 +311,6 @@ public class DefaultHandshakeHandler implements HandshakeHandler {
|
||||
protected List<WebSocketExtension> filterRequestedExtensions(ServerHttpRequest request,
|
||||
List<WebSocketExtension> requested, List<WebSocketExtension> supported) {
|
||||
|
||||
if (requested != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Requested extension(s): " + requested + ", supported extension(s): " + supported);
|
||||
}
|
||||
}
|
||||
return requested;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -57,6 +57,9 @@ public class HandshakeInterceptorChain {
|
||||
for (int i = 0; i < this.interceptors.size(); i++) {
|
||||
HandshakeInterceptor interceptor = this.interceptors.get(i);
|
||||
if (!interceptor.beforeHandshake(request, response, this.wsHandler, attributes)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(interceptor + " return false precluding handshake.");
|
||||
}
|
||||
applyAfterHandshake(request, response, null);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,6 @@ import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
@@ -41,8 +38,6 @@ import org.springframework.web.socket.server.HandshakeInterceptor;
|
||||
*/
|
||||
public class HttpSessionHandshakeInterceptor implements HandshakeInterceptor {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(HttpSessionHandshakeInterceptor.class);
|
||||
|
||||
private Collection<String> attributeNames;
|
||||
|
||||
|
||||
@@ -74,16 +69,8 @@ public class HttpSessionHandshakeInterceptor implements HandshakeInterceptor {
|
||||
while (names.hasMoreElements()) {
|
||||
String name = names.nextElement();
|
||||
if (CollectionUtils.isEmpty(this.attributeNames) || this.attributeNames.contains(name)) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Adding HTTP session attribute to handshake attributes: " + name);
|
||||
}
|
||||
attributes.put(name, session.getAttribute(name));
|
||||
}
|
||||
else {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Skipped HTTP session attribute");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,6 +25,8 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
import org.springframework.http.server.ServerHttpResponse;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
@@ -52,6 +54,9 @@ import org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator;
|
||||
*/
|
||||
public class WebSocketHttpRequestHandler implements HttpRequestHandler {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(WebSocketHttpRequestHandler.class);
|
||||
|
||||
|
||||
private final HandshakeHandler handshakeHandler;
|
||||
|
||||
private final WebSocketHandler wsHandler;
|
||||
@@ -113,6 +118,9 @@ public class WebSocketHttpRequestHandler implements HttpRequestHandler {
|
||||
HandshakeFailureException failure = null;
|
||||
|
||||
try {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(servletRequest.getMethod() + " " + servletRequest.getRequestURI());
|
||||
}
|
||||
Map<String, Object> attributes = new HashMap<String, Object>();
|
||||
if (!chain.applyBeforeHandshake(request, response, attributes)) {
|
||||
return;
|
||||
|
||||
@@ -157,8 +157,8 @@ public abstract class AbstractClientSockJsSession implements WebSocketSession {
|
||||
@Override
|
||||
public final void close(CloseStatus status) {
|
||||
Assert.isTrue(status != null && isUserSetStatus(status), "Invalid close status: " + status);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Closing session with " + status + " in " + this);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Closing session with " + status + " in " + this);
|
||||
}
|
||||
closeInternal(status);
|
||||
}
|
||||
@@ -213,8 +213,8 @@ public abstract class AbstractClientSockJsSession implements WebSocketSession {
|
||||
}
|
||||
|
||||
private void handleOpenFrame() {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Processing SockJS open frame in " + this);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Processing SockJS open frame in " + this);
|
||||
}
|
||||
if (State.NEW.equals(state)) {
|
||||
this.state = State.OPEN;
|
||||
@@ -280,8 +280,8 @@ public abstract class AbstractClientSockJsSession implements WebSocketSession {
|
||||
if (data.length == 2) {
|
||||
closeStatus = new CloseStatus(Integer.valueOf(data[0]), data[1]);
|
||||
}
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Processing SockJS close frame with " + closeStatus + " in " + this);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Processing SockJS close frame with " + closeStatus + " in " + this);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
@@ -311,8 +311,8 @@ public abstract class AbstractClientSockJsSession implements WebSocketSession {
|
||||
this.closeStatus = (this.closeStatus != null ? this.closeStatus : closeStatus);
|
||||
Assert.state(this.closeStatus != null, "CloseStatus not available");
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Transport closed with " + this.closeStatus + " in " + this);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Transport closed with " + this.closeStatus + " in " + this);
|
||||
}
|
||||
|
||||
this.state = State.CLOSED;
|
||||
|
||||
@@ -104,8 +104,8 @@ public abstract class AbstractXhrTransport implements XhrTransport {
|
||||
}
|
||||
throw new HttpServerErrorException(response.getStatusCode());
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SockJS Info request (url=" + infoUrl + ") response: " + response);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("SockJS Info request (url=" + infoUrl + ") response: " + response);
|
||||
}
|
||||
return response.getBody();
|
||||
}
|
||||
@@ -114,8 +114,8 @@ public abstract class AbstractXhrTransport implements XhrTransport {
|
||||
|
||||
@Override
|
||||
public void executeSendRequest(URI url, TextMessage message) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Starting XHR send, url=" + url);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Starting XHR send, url=" + url);
|
||||
}
|
||||
ResponseEntity<String> response = executeSendRequestInternal(url, this.xhrSendRequestHeaders, message);
|
||||
if (response.getStatusCode() != HttpStatus.NO_CONTENT) {
|
||||
@@ -124,8 +124,8 @@ public abstract class AbstractXhrTransport implements XhrTransport {
|
||||
}
|
||||
throw new HttpServerErrorException(response.getStatusCode());
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("XHR send request (url=" + url + ") response: " + response);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("XHR send request (url=" + url + ") response: " + response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,8 @@ public abstract class AbstractXhrTransport implements XhrTransport {
|
||||
|
||||
URI receiveUrl = request.getTransportUrl();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Opening XHR session, receive url=" + receiveUrl);
|
||||
logger.debug("Starting XHR " +
|
||||
(isXhrStreamingDisabled() ? "Polling" : "Streaming") + "session url=" + receiveUrl);
|
||||
}
|
||||
|
||||
HttpHeaders handshakeHeaders = new HttpHeaders();
|
||||
|
||||
@@ -133,8 +133,8 @@ class DefaultTransportRequest implements TransportRequest {
|
||||
|
||||
|
||||
public void connect(WebSocketHandler handler, SettableListenableFuture<WebSocketSession> future) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Starting " + this);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Starting " + this);
|
||||
}
|
||||
ConnectCallback connectCallback = new ConnectCallback(handler, future);
|
||||
scheduleConnectTimeoutTask(connectCallback);
|
||||
@@ -144,14 +144,14 @@ class DefaultTransportRequest implements TransportRequest {
|
||||
|
||||
private void scheduleConnectTimeoutTask(ConnectCallback connectHandler) {
|
||||
if (this.timeoutScheduler != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Scheduling connect to time out after " + this.timeoutValue + " milliseconds");
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Scheduling connect to time out after " + this.timeoutValue + " ms.");
|
||||
}
|
||||
Date timeoutDate = new Date(System.currentTimeMillis() + this.timeoutValue);
|
||||
this.timeoutScheduler.schedule(connectHandler, timeoutDate);
|
||||
}
|
||||
else if (logger.isDebugEnabled()) {
|
||||
logger.debug("Connect timeout task not scheduled. Is SockJsClient configured with a TaskScheduler?");
|
||||
else if (logger.isTraceEnabled()) {
|
||||
logger.trace("Connect timeout task not scheduled (no TaskScheduler configured).");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -136,8 +136,8 @@ public class JettyXhrTransport extends AbstractXhrTransport implements XhrTransp
|
||||
}
|
||||
|
||||
private void executeReceiveRequest(URI url, HttpHeaders headers, SockJsResponseListener listener) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Starting XHR receive request, url=" + url);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Starting XHR receive request, url=" + url);
|
||||
}
|
||||
Request httpRequest = this.httpClient.newRequest(url).method(HttpMethod.POST);
|
||||
addHttpHeaders(httpRequest, headers);
|
||||
@@ -182,9 +182,9 @@ public class JettyXhrTransport extends AbstractXhrTransport implements XhrTransp
|
||||
|
||||
@Override
|
||||
public void onHeaders(Response response) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
// Convert to HttpHeaders to avoid "\n"
|
||||
logger.debug("XHR receive headers: " + toHttpHeaders(response.getHeaders()));
|
||||
logger.trace("XHR receive headers: " + toHttpHeaders(response.getHeaders()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ public class JettyXhrTransport extends AbstractXhrTransport implements XhrTransp
|
||||
while (true) {
|
||||
if (this.sockJsSession.isDisconnected()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SockJS sockJsSession closed. Closing ClientHttpResponse.");
|
||||
logger.debug("SockJS sockJsSession closed, closing response.");
|
||||
}
|
||||
response.abort(new SockJsException("Session closed.", this.sockJsSession.getId(), null));
|
||||
return;
|
||||
@@ -228,8 +228,8 @@ public class JettyXhrTransport extends AbstractXhrTransport implements XhrTransp
|
||||
if (this.outputStream.size() > 0) {
|
||||
handleFrame();
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("XHR receive request completed.");
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("XHR receive request completed.");
|
||||
}
|
||||
executeReceiveRequest(this.transportUrl, this.receiveHeaders, this);
|
||||
}
|
||||
|
||||
@@ -125,8 +125,8 @@ public class RestTemplateXhrTransport extends AbstractXhrTransport implements Xh
|
||||
break;
|
||||
}
|
||||
try {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Starting XHR receive request, url=" + receiveUrl);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Starting XHR receive request, url=" + receiveUrl);
|
||||
}
|
||||
getRestTemplate().execute(receiveUrl, HttpMethod.POST, requestCallback, responseExtractor);
|
||||
requestCallback = requestCallbackAfterHandshake;
|
||||
@@ -215,15 +215,15 @@ public class RestTemplateXhrTransport extends AbstractXhrTransport implements Xh
|
||||
if (!HttpStatus.OK.equals(response.getStatusCode())) {
|
||||
throw new HttpServerErrorException(response.getStatusCode());
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("XHR receive headers: " + response.getHeaders());
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("XHR receive headers: " + response.getHeaders());
|
||||
}
|
||||
InputStream is = response.getBody();
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
while (true) {
|
||||
if (this.sockJsSession.isDisconnected()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SockJS sockJsSession closed. Closing ClientHttpResponse.");
|
||||
logger.debug("SockJS sockJsSession closed, closing response.");
|
||||
}
|
||||
response.close();
|
||||
break;
|
||||
@@ -233,8 +233,8 @@ public class RestTemplateXhrTransport extends AbstractXhrTransport implements Xh
|
||||
if (os.size() > 0) {
|
||||
handleFrame(os);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("XHR receive completed");
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("XHR receive completed");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public class WebSocketTransport implements Transport {
|
||||
URI url = request.getTransportUrl();
|
||||
WebSocketHttpHeaders headers = new WebSocketHttpHeaders(request.getHandshakeHeaders());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Opening WebSocket connection, url=" + url);
|
||||
logger.debug("Starting WebSocket session url=" + url);
|
||||
}
|
||||
this.webSocketClient.doHandshake(handler, headers, url).addCallback(
|
||||
new ListenableFutureCallback<WebSocketSession>() {
|
||||
|
||||
@@ -268,54 +268,64 @@ public abstract class AbstractSockJsService implements SockJsService {
|
||||
String sockJsPath, WebSocketHandler wsHandler) throws SockJsException {
|
||||
|
||||
if (sockJsPath == null) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Expected SockJS path. Failing request: " + request.getURI());
|
||||
}
|
||||
logger.error("Expected SockJS path. Failing request: " + request.getURI());
|
||||
response.setStatusCode(HttpStatus.NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(request.getMethod() + " with SockJS path [" + sockJsPath + "]");
|
||||
}
|
||||
try {
|
||||
request.getHeaders();
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Invalid media type ignored: " + ex.getMediaType());
|
||||
}
|
||||
// As per SockJS protocol content-type can be ignored (it's always json)
|
||||
}
|
||||
|
||||
String requestInfo = logger.isDebugEnabled() ? request.getMethod() + " " + request.getURI() : "";
|
||||
try {
|
||||
if (sockJsPath.equals("") || sockJsPath.equals("/")) {
|
||||
logger.debug(requestInfo);
|
||||
response.getHeaders().setContentType(new MediaType("text", "plain", Charset.forName("UTF-8")));
|
||||
response.getBody().write("Welcome to SockJS!\n".getBytes("UTF-8"));
|
||||
}
|
||||
else if (sockJsPath.equals("/info")) {
|
||||
logger.debug(requestInfo);
|
||||
this.infoHandler.handle(request, response);
|
||||
}
|
||||
else if (sockJsPath.matches("/iframe[0-9-.a-z_]*.html")) {
|
||||
logger.debug(requestInfo);
|
||||
this.iframeHandler.handle(request, response);
|
||||
}
|
||||
else if (sockJsPath.equals("/websocket")) {
|
||||
if (isWebSocketEnabled()) {
|
||||
logger.debug(requestInfo);
|
||||
handleRawWebSocketRequest(request, response, wsHandler);
|
||||
}
|
||||
else if (logger.isDebugEnabled()) {
|
||||
logger.debug("WebSocket disabled, ignoring " + requestInfo);
|
||||
}
|
||||
}
|
||||
else {
|
||||
String[] pathSegments = StringUtils.tokenizeToStringArray(sockJsPath.substring(1), "/");
|
||||
if (pathSegments.length != 3) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Expected \"/{server}/{session}/{transport}\" but got \"" + sockJsPath + "\"");
|
||||
}
|
||||
logger.error("Ignoring invalid transport request " + requestInfo);
|
||||
response.setStatusCode(HttpStatus.NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
String serverId = pathSegments[0];
|
||||
String sessionId = pathSegments[1];
|
||||
String transport = pathSegments[2];
|
||||
<<<<<<< HEAD
|
||||
if (!validateRequest(serverId, sessionId, transport)) {
|
||||
=======
|
||||
|
||||
if (!isWebSocketEnabled() && transport.equals("websocket")) {
|
||||
logger.debug("WebSocket transport is disabled, ignoring " + requestInfo);
|
||||
response.setStatusCode(HttpStatus.NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
else if (!validateRequest(serverId, sessionId, transport)) {
|
||||
logger.error("Ignoring transport request " + requestInfo);
|
||||
>>>>>>> STOMP and WebSocket messaging related logging updates
|
||||
response.setStatusCode(HttpStatus.NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
@@ -330,21 +340,23 @@ public abstract class AbstractSockJsService implements SockJsService {
|
||||
|
||||
protected boolean validateRequest(String serverId, String sessionId, String transport) {
|
||||
if (!StringUtils.hasText(serverId) || !StringUtils.hasText(sessionId) || !StringUtils.hasText(transport)) {
|
||||
logger.error("Empty server, session, or transport value");
|
||||
logger.error("No server, session, or transport path segment");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Server and session id's must not contain "."
|
||||
if (serverId.contains(".") || sessionId.contains(".")) {
|
||||
<<<<<<< HEAD
|
||||
logger.error("Server or session contain a \".\"");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isWebSocketEnabled() && transport.equals("websocket")) {
|
||||
logger.debug("Ignoring WebSocket request (transport disabled via SockJsService property)");
|
||||
=======
|
||||
logger.error("Either server or session contains a \".\" which is not allowed by SockJS protocol.");
|
||||
>>>>>>> STOMP and WebSocket messaging related logging updates
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -368,7 +380,6 @@ public abstract class AbstractSockJsService implements SockJsService {
|
||||
try {
|
||||
// Perhaps a CORS Filter has already added this?
|
||||
if (!CollectionUtils.isEmpty(responseHeaders.get("Access-Control-Allow-Origin"))) {
|
||||
logger.trace("Skip adding CORS headers, response already contains \"Access-Control-Allow-Origin\"");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -43,6 +43,8 @@ import org.springframework.web.socket.sockjs.SockJsService;
|
||||
*/
|
||||
public class SockJsHttpRequestHandler implements HttpRequestHandler {
|
||||
|
||||
// No logging: HTTP transports too verbose and we don't know enough to log anything of value
|
||||
|
||||
private final SockJsService sockJsService;
|
||||
|
||||
private final WebSocketHandler webSocketHandler;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,6 +27,8 @@ import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
@@ -192,16 +194,14 @@ public class TransportHandlingSockJsService extends AbstractSockJsService implem
|
||||
|
||||
TransportType transportType = TransportType.fromValue(transport);
|
||||
if (transportType == null) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Unknown transport type: " + transportType);
|
||||
}
|
||||
logger.error("Unknown transport type for " + request.getURI());
|
||||
response.setStatusCode(HttpStatus.NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
TransportHandler transportHandler = this.handlers.get(transportType);
|
||||
if (transportHandler == null) {
|
||||
logger.error("Transport handler not found");
|
||||
logger.error("No TransportHandler for " + request.getURI());
|
||||
response.setStatusCode(HttpStatus.NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
@@ -239,7 +239,9 @@ public class TransportHandlingSockJsService extends AbstractSockJsService implem
|
||||
else {
|
||||
response.setStatusCode(HttpStatus.NOT_FOUND);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Session not found, sessionId=" + sessionId);
|
||||
logger.debug("Session not found, sessionId=" + sessionId +
|
||||
". The session may have been closed " +
|
||||
"(e.g. missed heart-beat) while a message was coming in.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -277,17 +279,11 @@ public class TransportHandlingSockJsService extends AbstractSockJsService implem
|
||||
if (session != null) {
|
||||
return session;
|
||||
}
|
||||
|
||||
if (this.sessionCleanupTask == null) {
|
||||
scheduleSessionTask();
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Creating new SockJS session, sessionId=" + sessionId);
|
||||
}
|
||||
session = sessionFactory.createSession(sessionId, handler, attributes);
|
||||
this.sessions.put(sessionId, session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
@@ -297,31 +293,24 @@ public class TransportHandlingSockJsService extends AbstractSockJsService implem
|
||||
if (this.sessionCleanupTask != null) {
|
||||
return;
|
||||
}
|
||||
final List<String> removedSessionIds = new ArrayList<String>();
|
||||
this.sessionCleanupTask = getTaskScheduler().scheduleAtFixedRate(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
int count = sessions.size();
|
||||
if (logger.isTraceEnabled() && (count != 0)) {
|
||||
logger.trace("Checking " + count + " session(s) for timeouts [" + getName() + "]");
|
||||
}
|
||||
for (SockJsSession session : sessions.values()) {
|
||||
for (SockJsSession session : sessions.values()) {
|
||||
try {
|
||||
if (session.getTimeSinceLastActive() > getDisconnectDelay()) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Removing " + session + " for [" + getName() + "]");
|
||||
}
|
||||
session.close();
|
||||
sessions.remove(session.getId());
|
||||
session.close();
|
||||
}
|
||||
}
|
||||
if (logger.isTraceEnabled() && count > 0) {
|
||||
logger.trace(sessions.size() + " remaining session(s) [" + getName() + "]");
|
||||
catch (Throwable ex) {
|
||||
logger.error("Failed to close " + session, ex);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (logger.isErrorEnabled()) {
|
||||
logger.error("Failed to complete session timeout checks for [" + getName() + "]", ex);
|
||||
}
|
||||
if (logger.isDebugEnabled() && !removedSessionIds.isEmpty()) {
|
||||
logger.debug("Closed " + removedSessionIds.size() + " sessions " + removedSessionIds);
|
||||
removedSessionIds.clear();
|
||||
}
|
||||
}
|
||||
}, getDisconnectDelay());
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.web.socket.sockjs.transport.session.AbstractHttpSockJ
|
||||
*/
|
||||
public abstract class AbstractHttpReceivingTransportHandler extends AbstractTransportHandler {
|
||||
|
||||
|
||||
@Override
|
||||
public final void handleRequest(ServerHttpRequest request, ServerHttpResponse response,
|
||||
WebSocketHandler wsHandler, SockJsSession wsSession) throws SockJsException {
|
||||
@@ -70,16 +71,13 @@ public abstract class AbstractHttpReceivingTransportHandler extends AbstractTran
|
||||
handleReadError(response, "Failed to read message(s)", sockJsSession.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
if (messages == null) {
|
||||
handleReadError(response, "Payload expected.", sockJsSession.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Received message(s): " + Arrays.asList(messages));
|
||||
}
|
||||
|
||||
response.setStatusCode(getResponseStatus());
|
||||
response.getHeaders().setContentType(new MediaType("text", "plain", UTF8_CHARSET));
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -63,12 +63,14 @@ public abstract class AbstractHttpSendingTransportHandler extends AbstractTransp
|
||||
|
||||
if (sockJsSession.isNew()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Opening " + getTransportType() + " connection.");
|
||||
logger.debug(request.getMethod() + " " + request.getURI());
|
||||
}
|
||||
sockJsSession.handleInitialRequest(request, response, getFrameFormat(request));
|
||||
}
|
||||
else if (sockJsSession.isClosed()) {
|
||||
logger.debug("Connection already closed (but not removed yet).");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Connection already closed (but not removed yet) for " + sockJsSession);
|
||||
}
|
||||
SockJsFrame frame = SockJsFrame.closeFrameGoAway();
|
||||
try {
|
||||
response.getBody().write(frame.getContentBytes());
|
||||
@@ -76,7 +78,6 @@ public abstract class AbstractHttpSendingTransportHandler extends AbstractTransp
|
||||
catch (IOException ex) {
|
||||
throw new SockJsException("Failed to send " + frame, sockJsSession.getId(), ex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (!sockJsSession.isActive()) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
@@ -86,7 +87,7 @@ public abstract class AbstractHttpSendingTransportHandler extends AbstractTransp
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Another " + getTransportType() + " connection still open: " + sockJsSession);
|
||||
logger.debug("Another " + getTransportType() + " connection still open for " + sockJsSession);
|
||||
}
|
||||
String formattedFrame = getFrameFormat(request).format(SockJsFrame.closeFrameAnotherConnectionOpen());
|
||||
try {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -32,6 +32,7 @@ public abstract class AbstractTransportHandler implements TransportHandler {
|
||||
|
||||
protected static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
|
||||
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private SockJsServiceConfig serviceConfig;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -90,7 +90,7 @@ public class DefaultSockJsService extends TransportHandlingSockJsService {
|
||||
catch (Exception ex) {
|
||||
Log logger = LogFactory.getLog(DefaultSockJsService.class);
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Failed to create default WebSocketTransportHandler", ex);
|
||||
logger.warn("Failed to create a default WebSocketTransportHandler", ex);
|
||||
}
|
||||
}
|
||||
if (overrides != null) {
|
||||
|
||||
@@ -55,6 +55,7 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
|
||||
/**
|
||||
* Log category to use on network IO exceptions after a client has gone away.
|
||||
*
|
||||
@@ -65,7 +66,7 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
||||
*
|
||||
* <p>We make a best effort to identify such network failures, on a per-server
|
||||
* basis, and log them under a separate log category. A simple one-line message
|
||||
* is logged at INFO level, while a full stack trace is shown at TRACE level.
|
||||
* is logged at DEBUG level, while a full stack trace is shown at TRACE level.
|
||||
*
|
||||
* @see #disconnectedClientLogger
|
||||
*/
|
||||
@@ -268,8 +269,8 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
||||
@Override
|
||||
public final void close(CloseStatus status) throws IOException {
|
||||
if (isOpen()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Closing SockJS session " + getId() + " with " + status);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Closing SockJS session " + getId() + " with " + status);
|
||||
}
|
||||
this.state = State.CLOSED;
|
||||
try {
|
||||
@@ -362,8 +363,8 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
||||
if (disconnectedClientLogger.isTraceEnabled()) {
|
||||
disconnectedClientLogger.trace("Looks like the client has gone away", failure);
|
||||
}
|
||||
else if (disconnectedClientLogger.isInfoEnabled()) {
|
||||
disconnectedClientLogger.info("Looks like the client has gone away: " +
|
||||
else if (disconnectedClientLogger.isDebugEnabled()) {
|
||||
disconnectedClientLogger.debug("Looks like the client has gone away: " +
|
||||
nestedException.getMessage() + " (For full stack trace, set the '" +
|
||||
DISCONNECTED_CLIENT_LOG_CATEGORY + "' log category to TRACE level)");
|
||||
}
|
||||
@@ -426,7 +427,7 @@ public abstract class AbstractSockJsSession implements SockJsSession {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "[id=" + getId() + ", uri=" + getUri() + "]";
|
||||
return getClass().getSimpleName() + "[id=" + getId() + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -180,7 +180,6 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession implemen
|
||||
public void handleMessage(TextMessage message, WebSocketSession wsSession) throws Exception {
|
||||
String payload = message.getPayload();
|
||||
if (StringUtils.isEmpty(payload)) {
|
||||
logger.trace("Ignoring empty message");
|
||||
return;
|
||||
}
|
||||
String[] messages;
|
||||
@@ -217,7 +216,7 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession implemen
|
||||
@Override
|
||||
protected void writeFrameInternal(SockJsFrame frame) throws IOException {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Write " + frame);
|
||||
logger.trace("Writing " + frame);
|
||||
}
|
||||
TextMessage message = new TextMessage(frame.getContent());
|
||||
this.webSocketSession.sendMessage(message);
|
||||
@@ -233,13 +232,4 @@ public class WebSocketServerSockJsSession extends AbstractSockJsSession implemen
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (getNativeSession() != null) {
|
||||
return super.toString();
|
||||
}
|
||||
else {
|
||||
return "WebSocketServerSockJsSession[id=" + getId() + ", uri=null]";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,8 @@ public class HttpSendingTransportHandlerTests extends AbstractHttpRequestTests
|
||||
|
||||
this.sockJsConfig = new StubSockJsServiceConfig();
|
||||
this.sockJsConfig.setTaskScheduler(this.taskScheduler);
|
||||
|
||||
setRequest("POST", "/");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,6 +102,7 @@ public class HttpSendingTransportHandlerTests extends AbstractHttpRequestTests
|
||||
assertEquals("\"callback\" parameter required", this.servletResponse.getContentAsString());
|
||||
|
||||
resetRequestAndResponse();
|
||||
setRequest("POST", "/");
|
||||
this.servletRequest.setQueryString("c=callback");
|
||||
this.servletRequest.addParameter("c", "callback");
|
||||
transportHandler.handleRequest(this.request, this.response, this.webSocketHandler, session);
|
||||
@@ -136,6 +139,7 @@ public class HttpSendingTransportHandlerTests extends AbstractHttpRequestTests
|
||||
assertEquals("\"callback\" parameter required", this.servletResponse.getContentAsString());
|
||||
|
||||
resetRequestAndResponse();
|
||||
setRequest("POST", "/");
|
||||
this.servletRequest.setQueryString("c=callback");
|
||||
this.servletRequest.addParameter("c", "callback");
|
||||
transportHandler.handleRequest(this.request, this.response, this.webSocketHandler, session);
|
||||
|
||||
Reference in New Issue
Block a user