diff --git a/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java index 669835afc15..c765fd34926 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServerHttpRequest.java @@ -16,6 +16,8 @@ package org.springframework.http.server; +import java.security.Principal; + import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpRequest; import org.springframework.util.MultiValueMap; @@ -33,4 +35,21 @@ public interface ServerHttpRequest extends HttpRequest, HttpInputMessage { */ MultiValueMap getQueryParams(); + /** + * Return a {@link java.security.Principal} instance containing the name of the + * authenticated user. If the user has not been authenticated, the method returns + * null. + */ + Principal getPrincipal(); + + /** + * Return the host name of the endpoint on the other end. + */ + String getRemoteHostName(); + + /** + * Return the IP address of the endpoint on the other end. + */ + String getRemoteAddress(); + } diff --git a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java index 5f4f90e9a86..2236df64cd1 100644 --- a/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/ServletServerHttpRequest.java @@ -26,6 +26,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; import java.nio.charset.Charset; +import java.security.Principal; import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; @@ -131,6 +132,21 @@ public class ServletServerHttpRequest implements ServerHttpRequest { return this.headers; } + @Override + public Principal getPrincipal() { + return this.servletRequest.getUserPrincipal(); + } + + @Override + public String getRemoteHostName() { + return this.servletRequest.getRemoteHost(); + } + + @Override + public String getRemoteAddress() { + return this.servletRequest.getRemoteAddr(); + } + public Cookies getCookies() { if (this.cookies == null) { this.cookies = new Cookies(); diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java b/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java index 30514835ad1..671f4d993bd 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/AbstractSockJsSession.java @@ -18,6 +18,7 @@ package org.springframework.sockjs; import java.io.IOException; import java.net.URI; +import java.security.Principal; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -25,7 +26,7 @@ import org.springframework.util.Assert; import org.springframework.websocket.CloseStatus; import org.springframework.websocket.TextMessage; import org.springframework.websocket.WebSocketHandler; -import org.springframework.websocket.WebSocketSession; +import org.springframework.websocket.adapter.ConfigurableWebSocketSession; /** @@ -34,12 +35,20 @@ import org.springframework.websocket.WebSocketSession; * @author Rossen Stoyanchev * @since 4.0 */ -public abstract class AbstractSockJsSession implements WebSocketSession { +public abstract class AbstractSockJsSession implements ConfigurableWebSocketSession { protected final Log logger = LogFactory.getLog(getClass()); - private final String sessionId; + private final String id; + + private URI uri; + + private String remoteHostName; + + private String remoteAddress; + + private Principal principal; private WebSocketHandler handler; @@ -57,24 +66,51 @@ public abstract class AbstractSockJsSession implements WebSocketSession { public AbstractSockJsSession(String sessionId, WebSocketHandler webSocketHandler) { Assert.notNull(sessionId, "sessionId is required"); Assert.notNull(webSocketHandler, "webSocketHandler is required"); - this.sessionId = sessionId; + this.id = sessionId; this.handler = webSocketHandler; } public String getId() { - return this.sessionId; + return this.id; + } + + @Override + public URI getUri() { + return this.uri; + } + + @Override + public void setUri(URI uri) { + this.uri = uri; } @Override public boolean isSecure() { - // TODO - return false; + return "wss".equals(this.uri.getSchemeSpecificPart()); } - @Override - public URI getURI() { - // TODO - return null; + public String getRemoteHostName() { + return this.remoteHostName; + } + + public void setRemoteHostName(String remoteHostName) { + this.remoteHostName = remoteHostName; + } + + public String getRemoteAddress() { + return this.remoteAddress; + } + + public void setRemoteAddress(String remoteAddress) { + this.remoteAddress = remoteAddress; + } + + public Principal getPrincipal() { + return this.principal; + } + + public void setPrincipal(Principal principal) { + this.principal = principal; } public boolean isNew() { @@ -213,7 +249,7 @@ public abstract class AbstractSockJsSession implements WebSocketSession { @Override public String toString() { - return "SockJS session id=" + this.sessionId; + return "SockJS session id=" + this.id; } diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/SockJsSessionFactory.java b/spring-websocket/src/main/java/org/springframework/sockjs/SockJsSessionFactory.java index 977cc9f0a31..f565808dd7c 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/SockJsSessionFactory.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/SockJsSessionFactory.java @@ -17,7 +17,6 @@ package org.springframework.sockjs; import org.springframework.websocket.WebSocketHandler; -import org.springframework.websocket.WebSocketSession; /** * A factory for creating a SockJS session. @@ -26,7 +25,7 @@ import org.springframework.websocket.WebSocketSession; * @author Rossen Stoyanchev * @since 4.0 */ -public interface SockJsSessionFactory{ +public interface SockJsSessionFactory { /** * Create a new SockJS session. @@ -34,6 +33,6 @@ public interface SockJsSessionFactory{ * @param webSocketHandler the underlying {@link WebSocketHandler} * @return a new non-null session */ - S createSession(String sessionId, WebSocketHandler webSocketHandler); + AbstractSockJsSession createSession(String sessionId, WebSocketHandler webSocketHandler); } diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/server/AbstractSockJsService.java b/spring-websocket/src/main/java/org/springframework/sockjs/server/AbstractSockJsService.java index 16fdfc4214a..15107e5a058 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/server/AbstractSockJsService.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/server/AbstractSockJsService.java @@ -51,7 +51,7 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf private static final int ONE_YEAR = 365 * 24 * 60 * 60; - private String name = getClass().getSimpleName() + "@" + ObjectUtils.getIdentityHexString(this); + private String name = "SockJS Service " + ObjectUtils.getIdentityHexString(this); private String clientLibraryUrl = "https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.4.min.js"; diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/server/TransportType.java b/spring-websocket/src/main/java/org/springframework/sockjs/server/TransportType.java index a71775534c5..f3c9e5c6e20 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/server/TransportType.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/server/TransportType.java @@ -68,7 +68,7 @@ public enum TransportType { return this.httpMethod; } - public boolean setsNoCacheHeader() { + public boolean setsNoCache() { return this.headerHints.contains("no_cache"); } @@ -76,7 +76,7 @@ public enum TransportType { return this.headerHints.contains("cors"); } - public boolean setsJsessionIdCookie() { + public boolean setsJsessionId() { return this.headerHints.contains("jsessionid"); } diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/server/support/DefaultSockJsService.java b/spring-websocket/src/main/java/org/springframework/sockjs/server/support/DefaultSockJsService.java index 92dddbed595..53edca9c5dc 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/server/support/DefaultSockJsService.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/server/support/DefaultSockJsService.java @@ -54,6 +54,7 @@ import org.springframework.util.CollectionUtils; import org.springframework.websocket.WebSocketHandler; import org.springframework.websocket.server.DefaultHandshakeHandler; import org.springframework.websocket.server.HandshakeHandler; +import org.springframework.websocket.server.support.ServerWebSocketSessionInitializer; /** @@ -69,6 +70,8 @@ public class DefaultSockJsService extends AbstractSockJsService { private final Map sessions = new ConcurrentHashMap(); + private final ServerWebSocketSessionInitializer sessionInitializer = new ServerWebSocketSessionInitializer(); + private ScheduledFuture sessionCleanupTask; @@ -187,14 +190,15 @@ public class DefaultSockJsService extends AbstractSockJsService { return; } - AbstractSockJsSession session = getSockJsSession(sessionId, webSocketHandler, transportHandler); + AbstractSockJsSession session = getSockJsSession(sessionId, webSocketHandler, + transportHandler, request, response); if (session != null) { - if (transportType.setsNoCacheHeader()) { + if (transportType.setsNoCache()) { addNoCacheHeaders(response); } - if (transportType.setsJsessionIdCookie() && isJsessionIdCookieRequired()) { + if (transportType.setsJsessionId() && isJsessionIdCookieRequired()) { Cookie cookie = request.getCookies().getCookie("JSESSIONID"); String jsid = (cookie != null) ? cookie.getValue() : "dummy"; // TODO: bypass use of Cookie object (causes Jetty to set Expires header) @@ -209,8 +213,8 @@ public class DefaultSockJsService extends AbstractSockJsService { transportHandler.handleRequest(request, response, webSocketHandler, session); } - public AbstractSockJsSession getSockJsSession(String sessionId, - WebSocketHandler webSocketHandler, TransportHandler transportHandler) { + protected AbstractSockJsSession getSockJsSession(String sessionId, WebSocketHandler handler, + TransportHandler transportHandler, ServerHttpRequest request, ServerHttpResponse response) { AbstractSockJsSession session = this.sessions.get(sessionId); if (session != null) { @@ -218,7 +222,7 @@ public class DefaultSockJsService extends AbstractSockJsService { } if (transportHandler instanceof SockJsSessionFactory) { - SockJsSessionFactory sessionFactory = (SockJsSessionFactory) transportHandler; + SockJsSessionFactory sessionFactory = (SockJsSessionFactory) transportHandler; synchronized (this.sessions) { session = this.sessions.get(sessionId); @@ -229,7 +233,8 @@ public class DefaultSockJsService extends AbstractSockJsService { scheduleSessionTask(); } logger.debug("Creating new session with session id \"" + sessionId + "\""); - session = (AbstractSockJsSession) sessionFactory.createSession(sessionId, webSocketHandler); + session = sessionFactory.createSession(sessionId, handler); + this.sessionInitializer.initialize(request, response, session); this.sessions.put(sessionId, session); return session; } diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/AbstractHttpSendingTransportHandler.java b/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/AbstractHttpSendingTransportHandler.java index f0c92e72f8e..681f3c66ce6 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/AbstractHttpSendingTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/AbstractHttpSendingTransportHandler.java @@ -39,7 +39,7 @@ import org.springframework.websocket.WebSocketHandler; * @since 4.0 */ public abstract class AbstractHttpSendingTransportHandler - implements ConfigurableTransportHandler, SockJsSessionFactory { + implements ConfigurableTransportHandler, SockJsSessionFactory { protected final Log logger = LogFactory.getLog(this.getClass()); diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/SockJsWebSocketHandler.java b/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/SockJsWebSocketHandler.java index e1978fe226b..a5f41dd5c86 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/SockJsWebSocketHandler.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/SockJsWebSocketHandler.java @@ -16,22 +16,16 @@ package org.springframework.sockjs.server.transport; -import java.io.IOException; import java.util.concurrent.atomic.AtomicInteger; -import org.springframework.sockjs.server.AbstractServerSockJsSession; import org.springframework.sockjs.server.SockJsConfiguration; -import org.springframework.sockjs.server.SockJsFrame; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; import org.springframework.websocket.CloseStatus; import org.springframework.websocket.TextMessage; import org.springframework.websocket.WebSocketHandler; import org.springframework.websocket.WebSocketSession; import org.springframework.websocket.adapter.TextWebSocketHandlerAdapter; -import com.fasterxml.jackson.databind.ObjectMapper; - /** * A wrapper around a {@link WebSocketHandler} instance that parses and adds SockJS @@ -52,21 +46,20 @@ public class SockJsWebSocketHandler extends TextWebSocketHandlerAdapter { private final SockJsConfiguration sockJsConfig; - private final WebSocketHandler webSocketHandler; - - private WebSocketServerSockJsSession sockJsSession; + private WebSocketServerSockJsSession session; private final AtomicInteger sessionCount = new AtomicInteger(0); - // TODO: JSON library used must be configurable - private final ObjectMapper objectMapper = new ObjectMapper(); + public SockJsWebSocketHandler(SockJsConfiguration config, + WebSocketHandler webSocketHandler, WebSocketServerSockJsSession session) { - public SockJsWebSocketHandler(SockJsConfiguration config, WebSocketHandler webSocketHandler) { Assert.notNull(config, "sockJsConfig is required"); Assert.notNull(webSocketHandler, "webSocketHandler is required"); + Assert.notNull(session, "session is required"); + this.sockJsConfig = config; - this.webSocketHandler = webSocketHandler; + this.session = session; } protected SockJsConfiguration getSockJsConfig() { @@ -76,100 +69,22 @@ public class SockJsWebSocketHandler extends TextWebSocketHandlerAdapter { @Override public void afterConnectionEstablished(WebSocketSession wsSession) throws Exception { Assert.isTrue(this.sessionCount.compareAndSet(0, 1), "Unexpected connection"); - this.sockJsSession = new WebSocketServerSockJsSession(getSockJsSessionId(wsSession), getSockJsConfig()); - this.sockJsSession.initWebSocketSession(wsSession); + this.session.initWebSocketSession(wsSession); } @Override public void handleTextMessage(WebSocketSession wsSession, TextMessage message) throws Exception { - this.sockJsSession.handleMessage(message, wsSession); + this.session.handleMessage(message, wsSession); } @Override public void afterConnectionClosed(WebSocketSession wsSession, CloseStatus status) throws Exception { - this.sockJsSession.delegateConnectionClosed(status); + this.session.delegateConnectionClosed(status); } @Override public void handleTransportError(WebSocketSession webSocketSession, Throwable exception) throws Exception { - this.sockJsSession.delegateError(exception); - } - - private static String getSockJsSessionId(WebSocketSession wsSession) { - Assert.notNull(wsSession, "wsSession is required"); - String path = wsSession.getURI().getPath(); - String[] segments = StringUtils.tokenizeToStringArray(path, "/"); - Assert.isTrue(segments.length > 3, "SockJS request should have at least 3 path segments: " + path); - return segments[segments.length-2]; - } - - - private class WebSocketServerSockJsSession extends AbstractServerSockJsSession { - - private WebSocketSession wsSession; - - - public WebSocketServerSockJsSession(String sessionId, SockJsConfiguration config) { - super(sessionId, config, SockJsWebSocketHandler.this.webSocketHandler); - } - - public void initWebSocketSession(WebSocketSession wsSession) throws Exception { - this.wsSession = wsSession; - try { - TextMessage message = new TextMessage(SockJsFrame.openFrame().getContent()); - this.wsSession.sendMessage(message); - } - catch (IOException ex) { - tryCloseWithSockJsTransportError(ex, null); - return; - } - scheduleHeartbeat(); - delegateConnectionEstablished(); - } - - @Override - public boolean isActive() { - return this.wsSession.isOpen(); - } - - 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; - try { - messages = objectMapper.readValue(payload, String[].class); - } - catch (IOException ex) { - logger.error("Broken data received. Terminating WebSocket connection abruptly", ex); - tryCloseWithSockJsTransportError(ex, CloseStatus.BAD_DATA); - return; - } - delegateMessages(messages); - } - - @Override - public void sendMessageInternal(String message) throws IOException { - cancelHeartbeat(); - writeFrame(SockJsFrame.messageFrame(message)); - scheduleHeartbeat(); - } - - @Override - protected void writeFrameInternal(SockJsFrame frame) throws IOException { - if (logger.isTraceEnabled()) { - logger.trace("Write " + frame); - } - TextMessage message = new TextMessage(frame.getContent()); - this.wsSession.sendMessage(message); - } - - @Override - protected void disconnect(CloseStatus status) throws IOException { - this.wsSession.close(status); - } + this.session.delegateError(exception); } } diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/WebSocketServerSockJsSession.java b/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/WebSocketServerSockJsSession.java new file mode 100644 index 00000000000..5e45d6a269c --- /dev/null +++ b/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/WebSocketServerSockJsSession.java @@ -0,0 +1,107 @@ +/* + * Copyright 2002-2013 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.sockjs.server.transport; + +import java.io.IOException; + +import org.springframework.sockjs.server.AbstractServerSockJsSession; +import org.springframework.sockjs.server.SockJsConfiguration; +import org.springframework.sockjs.server.SockJsFrame; +import org.springframework.util.StringUtils; +import org.springframework.websocket.CloseStatus; +import org.springframework.websocket.TextMessage; +import org.springframework.websocket.WebSocketHandler; +import org.springframework.websocket.WebSocketSession; + +import com.fasterxml.jackson.databind.ObjectMapper; + + +/** + * @author Rossen Stoyanchev + * @since 4.0 + */ +public class WebSocketServerSockJsSession extends AbstractServerSockJsSession { + + private WebSocketSession webSocketSession; + + // TODO: JSON library used must be configurable + private final ObjectMapper objectMapper = new ObjectMapper(); + + + public WebSocketServerSockJsSession(String sessionId, SockJsConfiguration config, WebSocketHandler handler) { + super(sessionId, config, handler); + } + + public void initWebSocketSession(WebSocketSession session) throws Exception { + this.webSocketSession = session; + try { + TextMessage message = new TextMessage(SockJsFrame.openFrame().getContent()); + this.webSocketSession.sendMessage(message); + } + catch (IOException ex) { + tryCloseWithSockJsTransportError(ex, null); + return; + } + scheduleHeartbeat(); + delegateConnectionEstablished(); + } + + @Override + public boolean isActive() { + return this.webSocketSession.isOpen(); + } + + 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; + try { + messages = objectMapper.readValue(payload, String[].class); + } + catch (IOException ex) { + logger.error("Broken data received. Terminating WebSocket connection abruptly", ex); + tryCloseWithSockJsTransportError(ex, CloseStatus.BAD_DATA); + return; + } + delegateMessages(messages); + } + + @Override + public void sendMessageInternal(String message) throws IOException { + cancelHeartbeat(); + writeFrame(SockJsFrame.messageFrame(message)); + scheduleHeartbeat(); + } + + @Override + protected void writeFrameInternal(SockJsFrame frame) throws IOException { + if (logger.isTraceEnabled()) { + logger.trace("Write " + frame); + } + TextMessage message = new TextMessage(frame.getContent()); + this.webSocketSession.sendMessage(message); + } + + @Override + protected void disconnect(CloseStatus status) throws IOException { + this.webSocketSession.close(status); + } +} + diff --git a/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/WebSocketTransportHandler.java b/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/WebSocketTransportHandler.java index 81d82c48330..de077f2e176 100644 --- a/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/WebSocketTransportHandler.java +++ b/spring-websocket/src/main/java/org/springframework/sockjs/server/transport/WebSocketTransportHandler.java @@ -21,6 +21,7 @@ import java.io.IOException; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.sockjs.AbstractSockJsSession; +import org.springframework.sockjs.SockJsSessionFactory; import org.springframework.sockjs.server.ConfigurableTransportHandler; import org.springframework.sockjs.server.SockJsConfiguration; import org.springframework.sockjs.server.TransportErrorException; @@ -39,7 +40,8 @@ import org.springframework.websocket.server.HandshakeHandler; * @author Rossen Stoyanchev * @since 4.0 */ -public class WebSocketTransportHandler implements ConfigurableTransportHandler, HandshakeHandler { +public class WebSocketTransportHandler implements ConfigurableTransportHandler, + HandshakeHandler, SockJsSessionFactory { private final HandshakeHandler handshakeHandler; @@ -61,12 +63,18 @@ public class WebSocketTransportHandler implements ConfigurableTransportHandler, this.sockJsConfig = sockJsConfig; } + @Override + public AbstractSockJsSession createSession(String sessionId, WebSocketHandler webSocketHandler) { + return new WebSocketServerSockJsSession(sessionId, this.sockJsConfig, webSocketHandler); + } + @Override public void handleRequest(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler webSocketHandler, AbstractSockJsSession session) throws TransportErrorException { try { - WebSocketHandler sockJsWrapper = new SockJsWebSocketHandler(this.sockJsConfig, webSocketHandler); + WebSocketServerSockJsSession wsSession = (WebSocketServerSockJsSession) session; + WebSocketHandler sockJsWrapper = new SockJsWebSocketHandler(this.sockJsConfig, webSocketHandler, wsSession); this.handshakeHandler.doHandshake(request, response, sockJsWrapper); } catch (Throwable t) { diff --git a/spring-websocket/src/main/java/org/springframework/websocket/WebSocketSession.java b/spring-websocket/src/main/java/org/springframework/websocket/WebSocketSession.java index e1ef76b61d5..19b4cc56dd7 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/WebSocketSession.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/WebSocketSession.java @@ -17,7 +17,9 @@ package org.springframework.websocket; import java.io.IOException; +import java.net.InetSocketAddress; import java.net.URI; +import java.security.Principal; /** * Allows sending messages over a WebSocket connection as well as closing it. @@ -33,9 +35,9 @@ public interface WebSocketSession { String getId(); /** - * Return whether the connection is still open. + * Return the URI used to open the WebSocket connection. */ - boolean isOpen(); + URI getUri(); /** * Return whether the underlying socket is using a secure transport. @@ -43,9 +45,26 @@ public interface WebSocketSession { boolean isSecure(); /** - * Return the URI used to open the WebSocket connection. + * Return a {@link java.security.Principal} instance containing the name of the + * authenticated user. If the user has not been authenticated, the method returns + * null. */ - URI getURI(); + Principal getPrincipal(); + + /** + * Return the host name of the endpoint on the other end. + */ + String getRemoteHostName(); + + /** + * Return the IP address of the endpoint on the other end. + */ + String getRemoteAddress(); + + /** + * Return whether the connection is still open. + */ + boolean isOpen(); /** * Send a WebSocket message either {@link TextMessage} or diff --git a/spring-websocket/src/main/java/org/springframework/websocket/adapter/AbstractWebSocketSesssionAdapter.java b/spring-websocket/src/main/java/org/springframework/websocket/adapter/AbstractWebSocketSesssionAdapter.java index 122f2264c53..4b44badd96d 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/adapter/AbstractWebSocketSesssionAdapter.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/adapter/AbstractWebSocketSesssionAdapter.java @@ -1,5 +1,4 @@ /* - * Copyright 2002-2013 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. @@ -34,11 +33,13 @@ import org.springframework.websocket.WebSocketSession; * @author Rossen Stoyanchev * @since 4.0 */ -public abstract class AbstractWebSocketSesssionAdapter implements WebSocketSession { +public abstract class AbstractWebSocketSesssionAdapter implements ConfigurableWebSocketSession { protected final Log logger = LogFactory.getLog(getClass()); + public abstract void initSession(T session); + @Override public final void sendMessage(WebSocketMessage message) throws IOException { if (logger.isTraceEnabled()) { diff --git a/spring-websocket/src/main/java/org/springframework/websocket/adapter/ConfigurableWebSocketSession.java b/spring-websocket/src/main/java/org/springframework/websocket/adapter/ConfigurableWebSocketSession.java new file mode 100644 index 00000000000..63f724e558d --- /dev/null +++ b/spring-websocket/src/main/java/org/springframework/websocket/adapter/ConfigurableWebSocketSession.java @@ -0,0 +1,39 @@ +/* + * Copyright 2002-2013 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.websocket.adapter; + +import java.net.URI; +import java.security.Principal; + +import org.springframework.websocket.WebSocketSession; + + +/** + * @author Rossen Stoyanchev + * @since 4.0 + */ +public interface ConfigurableWebSocketSession extends WebSocketSession { + + void setUri(URI uri); + + void setRemoteHostName(String name); + + void setRemoteAddress(String address); + + void setPrincipal(Principal principal); + +} diff --git a/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketListenerAdapter.java b/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketListenerAdapter.java index 04458b35601..4720d257844 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketListenerAdapter.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketListenerAdapter.java @@ -25,7 +25,6 @@ import org.springframework.websocket.BinaryMessage; import org.springframework.websocket.CloseStatus; import org.springframework.websocket.TextMessage; import org.springframework.websocket.WebSocketHandler; -import org.springframework.websocket.WebSocketSession; import org.springframework.websocket.support.ExceptionWebSocketHandlerDecorator; /** @@ -40,18 +39,20 @@ public class JettyWebSocketListenerAdapter implements WebSocketListener { private final WebSocketHandler webSocketHandler; - private WebSocketSession wsSession; + private JettyWebSocketSessionAdapter wsSession; - public JettyWebSocketListenerAdapter(WebSocketHandler webSocketHandler) { + public JettyWebSocketListenerAdapter(WebSocketHandler webSocketHandler, JettyWebSocketSessionAdapter wsSession) { Assert.notNull(webSocketHandler, "webSocketHandler is required"); + Assert.notNull(wsSession, "wsSession is required"); this.webSocketHandler = webSocketHandler; + this.wsSession = wsSession; } @Override public void onWebSocketConnect(Session session) { - this.wsSession = new JettyWebSocketSessionAdapter(session); + this.wsSession.initSession(session); try { this.webSocketHandler.afterConnectionEstablished(this.wsSession); } diff --git a/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketSessionAdapter.java b/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketSessionAdapter.java index c48f1b7db3f..d7eeb411ed7 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketSessionAdapter.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/adapter/JettyWebSocketSessionAdapter.java @@ -17,9 +17,12 @@ package org.springframework.websocket.adapter; import java.io.IOException; +import java.net.InetSocketAddress; import java.net.URI; +import java.security.Principal; import org.eclipse.jetty.websocket.api.Session; +import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.websocket.BinaryMessage; import org.springframework.websocket.CloseStatus; @@ -31,38 +34,78 @@ import org.springframework.websocket.WebSocketSession; * Adapts Jetty's {@link Session} to Spring's {@link WebSocketSession}. * * @author Phillip Webb + * @author Rossen Stoyanchev * @since 4.0 */ -public class JettyWebSocketSessionAdapter extends AbstractWebSocketSesssionAdapter { +public class JettyWebSocketSessionAdapter + extends AbstractWebSocketSesssionAdapter { private Session session; + private Principal principal; - public JettyWebSocketSessionAdapter(Session session) { + + @Override + public void initSession(Session session) { + Assert.notNull(session, "session is required"); this.session = session; } - @Override public String getId() { return ObjectUtils.getIdentityHexString(this.session); } - @Override - public boolean isOpen() { - return this.session.isOpen(); - } - @Override public boolean isSecure() { return this.session.isSecure(); } @Override - public URI getURI() { + public URI getUri() { return this.session.getUpgradeRequest().getRequestURI(); } + @Override + public void setUri(URI uri) { + } + + @Override + public Principal getPrincipal() { + return this.principal; + } + + @Override + public void setPrincipal(Principal principal) { + this.principal = principal; + } + + @Override + public String getRemoteHostName() { + return this.session.getRemoteAddress().getHostName(); + } + + @Override + public void setRemoteHostName(String address) { + // ignore + } + + @Override + public String getRemoteAddress() { + InetSocketAddress address = this.session.getRemoteAddress(); + return address.isUnresolved() ? null : address.getAddress().getHostAddress(); + } + + @Override + public void setRemoteAddress(String address) { + // ignore + } + + @Override + public boolean isOpen() { + return this.session.isOpen(); + } + @Override protected void sendTextMessage(TextMessage message) throws IOException { this.session.getRemote().sendString(message.getPayload()); diff --git a/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardEndpointAdapter.java b/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardEndpointAdapter.java index 4f6f731281e..f7fd00b720a 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardEndpointAdapter.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardEndpointAdapter.java @@ -30,12 +30,11 @@ import org.springframework.websocket.BinaryMessage; import org.springframework.websocket.CloseStatus; import org.springframework.websocket.TextMessage; import org.springframework.websocket.WebSocketHandler; -import org.springframework.websocket.WebSocketSession; import org.springframework.websocket.support.ExceptionWebSocketHandlerDecorator; /** - * An {@link Endpoint} that delegates to a {@link WebSocketHandler}. + * A wrapper around a {@link WebSocketHandler} that adapts it to {@link Endpoint}. * * @author Rossen Stoyanchev * @since 4.0 @@ -46,19 +45,22 @@ public class StandardEndpointAdapter extends Endpoint { private final WebSocketHandler handler; - private WebSocketSession wsSession; + private final StandardWebSocketSessionAdapter wsSession; - public StandardEndpointAdapter(WebSocketHandler webSocketHandler) { - Assert.notNull(webSocketHandler, "webSocketHandler is required"); - this.handler = webSocketHandler; + public StandardEndpointAdapter(WebSocketHandler handler, StandardWebSocketSessionAdapter wsSession) { + Assert.notNull(handler, "handler is required"); + Assert.notNull(wsSession, "wsSession is required"); + this.handler = handler; + this.wsSession = wsSession; } @Override public void onOpen(final javax.websocket.Session session, EndpointConfig config) { - this.wsSession = new StandardWebSocketSessionAdapter(session); + this.wsSession.initSession(session); + try { this.handler.afterConnectionEstablished(this.wsSession); } diff --git a/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardWebSocketSessionAdapter.java b/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardWebSocketSessionAdapter.java index 811ebd93c59..ad98adb90db 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardWebSocketSessionAdapter.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/adapter/StandardWebSocketSessionAdapter.java @@ -18,6 +18,7 @@ package org.springframework.websocket.adapter; import java.io.IOException; import java.net.URI; +import java.security.Principal; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; @@ -35,35 +36,76 @@ import org.springframework.websocket.WebSocketSession; * @author Rossen Stoyanchev * @since 4.0 */ -public class StandardWebSocketSessionAdapter extends AbstractWebSocketSesssionAdapter { +public class StandardWebSocketSessionAdapter extends AbstractWebSocketSesssionAdapter { - private final javax.websocket.Session session; + private javax.websocket.Session session; + + private URI uri; + + private String remoteHostName; + + private String remoteAddress; - public StandardWebSocketSessionAdapter(javax.websocket.Session session) { + public void initSession(javax.websocket.Session session) { Assert.notNull(session, "session is required"); this.session = session; } - @Override public String getId() { return this.session.getId(); } @Override - public boolean isOpen() { - return this.session.isOpen(); + public URI getUri() { + return this.uri; } + @Override + public void setUri(URI uri) { + this.uri = uri; + } + + @Override public boolean isSecure() { return this.session.isSecure(); } @Override - public URI getURI() { - return this.session.getRequestURI(); + public Principal getPrincipal() { + return this.session.getUserPrincipal(); + } + + @Override + public void setPrincipal(Principal principal) { + // ignore + } + + @Override + public String getRemoteHostName() { + return this.remoteHostName; + } + + @Override + public void setRemoteHostName(String name) { + this.remoteHostName = name; + } + + @Override + public String getRemoteAddress() { + return this.remoteAddress; + } + + @Override + public void setRemoteAddress(String address) { + this.remoteAddress = address; + } + + @Override + public boolean isOpen() { + return this.session.isOpen(); } @Override diff --git a/spring-websocket/src/main/java/org/springframework/websocket/client/endpoint/StandardWebSocketClient.java b/spring-websocket/src/main/java/org/springframework/websocket/client/endpoint/StandardWebSocketClient.java index 100ef641649..8a1333c0fa3 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/client/endpoint/StandardWebSocketClient.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/client/endpoint/StandardWebSocketClient.java @@ -28,12 +28,12 @@ import javax.websocket.ClientEndpointConfig.Configurator; import javax.websocket.ContainerProvider; import javax.websocket.Endpoint; import javax.websocket.HandshakeResponse; -import javax.websocket.Session; import javax.websocket.WebSocketContainer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.http.HttpHeaders; +import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.websocket.WebSocketHandler; import org.springframework.websocket.WebSocketSession; @@ -67,15 +67,26 @@ public class StandardWebSocketClient implements WebSocketClient { public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, String uriTemplate, Object... uriVariables) throws WebSocketConnectFailureException { - URI uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode().toUri(); - return doHandshake(webSocketHandler, null, uri); + UriComponents uriComponents = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode(); + return doHandshake(webSocketHandler, null, uriComponents); } @Override public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, final HttpHeaders httpHeaders, URI uri) throws WebSocketConnectFailureException { - Endpoint endpoint = new StandardEndpointAdapter(webSocketHandler); + return doHandshake(webSocketHandler, httpHeaders, UriComponentsBuilder.fromUri(uri).build()); + } + + public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, + final HttpHeaders httpHeaders, UriComponents uriComponents) throws WebSocketConnectFailureException { + + URI uri = uriComponents.toUri(); + + StandardWebSocketSessionAdapter session = new StandardWebSocketSessionAdapter(); + session.setUri(uri); + session.setRemoteHostName(uriComponents.getHost()); + Endpoint endpoint = new StandardEndpointAdapter(webSocketHandler, session); ClientEndpointConfig.Builder configBuidler = ClientEndpointConfig.Builder.create(); if (httpHeaders != null) { @@ -109,8 +120,9 @@ public class StandardWebSocketClient implements WebSocketClient { } try { - Session session = this.webSocketContainer.connectToServer(endpoint, configBuidler.build(), uri); - return new StandardWebSocketSessionAdapter(session); + // TODO: do not block + this.webSocketContainer.connectToServer(endpoint, configBuidler.build(), uri); + return session; } catch (Exception e) { throw new WebSocketConnectFailureException("Failed to connect to " + uri, e); diff --git a/spring-websocket/src/main/java/org/springframework/websocket/client/jetty/JettyWebSocketClient.java b/spring-websocket/src/main/java/org/springframework/websocket/client/jetty/JettyWebSocketClient.java index ae1cc25cc93..0f96c948361 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/client/jetty/JettyWebSocketClient.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/client/jetty/JettyWebSocketClient.java @@ -17,13 +17,12 @@ package org.springframework.websocket.client.jetty; import java.net.URI; -import java.util.concurrent.Future; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.eclipse.jetty.websocket.api.Session; import org.springframework.context.SmartLifecycle; import org.springframework.http.HttpHeaders; +import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.websocket.WebSocketHandler; import org.springframework.websocket.WebSocketSession; @@ -126,23 +125,34 @@ public class JettyWebSocketClient implements WebSocketClient, SmartLifecycle { public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, String uriTemplate, Object... uriVariables) throws WebSocketConnectFailureException { - URI uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode().toUri(); - return doHandshake(webSocketHandler, null, uri); + UriComponents uriComponents = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode(); + return doHandshake(webSocketHandler, null, uriComponents); } @Override public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, HttpHeaders headers, URI uri) throws WebSocketConnectFailureException { + return doHandshake(webSocketHandler, headers, UriComponentsBuilder.fromUri(uri).build()); + } + + public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, HttpHeaders headers, UriComponents uriComponents) + throws WebSocketConnectFailureException { + // TODO: populate headers - JettyWebSocketListenerAdapter listener = new JettyWebSocketListenerAdapter(webSocketHandler); + URI uri = uriComponents.toUri(); + + JettyWebSocketSessionAdapter session = new JettyWebSocketSessionAdapter(); + session.setUri(uri); + session.setRemoteHostName(uriComponents.getHost()); + + JettyWebSocketListenerAdapter listener = new JettyWebSocketListenerAdapter(webSocketHandler, session); try { - // block for now - Future future = this.client.connect(listener, uri); - Session session = future.get(); - return new JettyWebSocketSessionAdapter(session); + // TODO: do not block + this.client.connect(listener, uri).get(); + return session; } catch (Exception e) { throw new WebSocketConnectFailureException("Failed to connect to " + uri, e); diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/support/AbstractEndpointUpgradeStrategy.java b/spring-websocket/src/main/java/org/springframework/websocket/server/support/AbstractEndpointUpgradeStrategy.java index 096ab251e88..324ac4e79f7 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/server/support/AbstractEndpointUpgradeStrategy.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/support/AbstractEndpointUpgradeStrategy.java @@ -26,6 +26,8 @@ import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.websocket.WebSocketHandler; import org.springframework.websocket.adapter.StandardEndpointAdapter; +import org.springframework.websocket.adapter.StandardWebSocketSessionAdapter; +import org.springframework.websocket.server.HandshakeFailureException; import org.springframework.websocket.server.RequestUpgradeStrategy; /** @@ -39,15 +41,20 @@ public abstract class AbstractEndpointUpgradeStrategy implements RequestUpgradeS protected final Log logger = LogFactory.getLog(getClass()); + private final ServerWebSocketSessionInitializer wsSessionInitializer = new ServerWebSocketSessionInitializer(); + @Override public void upgrade(ServerHttpRequest request, ServerHttpResponse response, - String protocol, WebSocketHandler webSocketHandler) throws IOException { + String protocol, WebSocketHandler handler) throws IOException, HandshakeFailureException { - upgradeInternal(request, response, protocol, new StandardEndpointAdapter(webSocketHandler)); + StandardWebSocketSessionAdapter session = new StandardWebSocketSessionAdapter(); + this.wsSessionInitializer.initialize(request, response, session); + StandardEndpointAdapter endpoint = new StandardEndpointAdapter(handler, session); + upgradeInternal(request, response, protocol, endpoint); } protected abstract void upgradeInternal(ServerHttpRequest request, ServerHttpResponse response, - String selectedProtocol, Endpoint endpoint) throws IOException; + String selectedProtocol, Endpoint endpoint) throws IOException, HandshakeFailureException; } diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/support/JettyRequestUpgradeStrategy.java b/spring-websocket/src/main/java/org/springframework/websocket/server/support/JettyRequestUpgradeStrategy.java index b536138e240..707e8580332 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/server/support/JettyRequestUpgradeStrategy.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/support/JettyRequestUpgradeStrategy.java @@ -34,6 +34,7 @@ import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.util.Assert; import org.springframework.websocket.WebSocketHandler; import org.springframework.websocket.adapter.JettyWebSocketListenerAdapter; +import org.springframework.websocket.adapter.JettyWebSocketSessionAdapter; import org.springframework.websocket.server.HandshakeFailureException; import org.springframework.websocket.server.RequestUpgradeStrategy; @@ -53,11 +54,13 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy { // FIXME when to call factory.cleanup(); - private static final String HANDLER_PROVIDER_ATTR_NAME = JettyRequestUpgradeStrategy.class.getName() + private static final String WEBSOCKET_LISTENER_ATTR_NAME = JettyRequestUpgradeStrategy.class.getName() + ".HANDLER_PROVIDER"; private WebSocketServerFactory factory; + private final ServerWebSocketSessionInitializer wsSessionInitializer = new ServerWebSocketSessionInitializer(); + public JettyRequestUpgradeStrategy() { this.factory = new WebSocketServerFactory(); @@ -65,17 +68,14 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy { @Override public Object createWebSocket(UpgradeRequest request, UpgradeResponse response) { Assert.isInstanceOf(ServletWebSocketRequest.class, request); - ServletWebSocketRequest servletRequest = (ServletWebSocketRequest) request; - WebSocketHandler webSocketHandler = - (WebSocketHandler) servletRequest.getServletAttributes().get(HANDLER_PROVIDER_ATTR_NAME); - return new JettyWebSocketListenerAdapter(webSocketHandler); + return ((ServletWebSocketRequest) request).getServletAttributes().get(WEBSOCKET_LISTENER_ATTR_NAME); } }); try { this.factory.init(); } catch (Exception ex) { - throw new IllegalStateException(ex); + throw new IllegalStateException("Unable to initialize Jetty WebSocketServerFactory", ex); } } @@ -95,17 +95,18 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy { Assert.isInstanceOf(ServletServerHttpResponse.class, response); HttpServletResponse servletResponse = ((ServletServerHttpResponse) response).getServletResponse(); - upgrade(servletRequest, servletResponse, selectedProtocol, webSocketHandler); - } + if (!this.factory.isUpgradeRequest(servletRequest, servletResponse)) { + // should never happen + throw new HandshakeFailureException("Not a WebSocket request"); + } - private void upgrade(HttpServletRequest request, HttpServletResponse response, - String selectedProtocol, final WebSocketHandler webSocketHandler) throws IOException { + JettyWebSocketSessionAdapter session = new JettyWebSocketSessionAdapter(); + this.wsSessionInitializer.initialize(request, response, session); + JettyWebSocketListenerAdapter listener = new JettyWebSocketListenerAdapter(webSocketHandler, session); - Assert.state(this.factory.isUpgradeRequest(request, response), "Expected websocket upgrade request"); + servletRequest.setAttribute(WEBSOCKET_LISTENER_ATTR_NAME, listener); - request.setAttribute(HANDLER_PROVIDER_ATTR_NAME, webSocketHandler); - - if (!this.factory.acceptWebSocket(request, response)) { + if (!this.factory.acceptWebSocket(servletRequest, servletResponse)) { // should never happen throw new HandshakeFailureException("WebSocket request not accepted by Jetty"); } diff --git a/spring-websocket/src/main/java/org/springframework/websocket/server/support/ServerWebSocketSessionInitializer.java b/spring-websocket/src/main/java/org/springframework/websocket/server/support/ServerWebSocketSessionInitializer.java new file mode 100644 index 00000000000..412bd5841bb --- /dev/null +++ b/spring-websocket/src/main/java/org/springframework/websocket/server/support/ServerWebSocketSessionInitializer.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2013 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.websocket.server.support; + +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.websocket.adapter.ConfigurableWebSocketSession; + + +/** + * @author Rossen Stoyanchev + * @since 4.0 + */ +public class ServerWebSocketSessionInitializer { + + + public void initialize(ServerHttpRequest request, ServerHttpResponse response, ConfigurableWebSocketSession session) { + session.setUri(request.getURI()); + session.setRemoteHostName(request.getRemoteHostName()); + session.setRemoteAddress(request.getRemoteAddress()); + session.setPrincipal(request.getPrincipal()); + } + +} diff --git a/spring-websocket/src/main/java/org/springframework/websocket/support/LoggingWebSocketHandlerDecorator.java b/spring-websocket/src/main/java/org/springframework/websocket/support/LoggingWebSocketHandlerDecorator.java index 6dbad07312f..7e4fa8bd8c3 100644 --- a/spring-websocket/src/main/java/org/springframework/websocket/support/LoggingWebSocketHandlerDecorator.java +++ b/spring-websocket/src/main/java/org/springframework/websocket/support/LoggingWebSocketHandlerDecorator.java @@ -41,7 +41,7 @@ public class LoggingWebSocketHandlerDecorator extends WebSocketHandlerDecorator @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { if (logger.isDebugEnabled()) { - logger.debug("Connection established, " + session + ", uri=" + session.getURI()); + logger.debug("Connection established, " + session + ", uri=" + session.getUri()); } super.afterConnectionEstablished(session); }