Add WebSocketSession attributes + initialization
In addition to adding the attributes, there is now mechanism for initializing WebSocketSession instances from attributes of the handshake request.
This commit is contained in:
parent
166ca7a5a3
commit
2a7935a913
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.http.server;
|
package org.springframework.http.server;
|
||||||
|
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
import org.springframework.http.HttpInputMessage;
|
import org.springframework.http.HttpInputMessage;
|
||||||
import org.springframework.http.HttpRequest;
|
import org.springframework.http.HttpRequest;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
@ -33,4 +35,21 @@ public interface ServerHttpRequest extends HttpRequest, HttpInputMessage {
|
||||||
*/
|
*/
|
||||||
MultiValueMap<String, String> getQueryParams();
|
MultiValueMap<String, String> 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
|
||||||
|
* <code>null</code>.
|
||||||
|
*/
|
||||||
|
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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.security.Principal;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
@ -131,6 +132,21 @@ public class ServletServerHttpRequest implements ServerHttpRequest {
|
||||||
return this.headers;
|
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() {
|
public Cookies getCookies() {
|
||||||
if (this.cookies == null) {
|
if (this.cookies == null) {
|
||||||
this.cookies = new Cookies();
|
this.cookies = new Cookies();
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package org.springframework.sockjs;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
@ -25,7 +26,7 @@ import org.springframework.util.Assert;
|
||||||
import org.springframework.websocket.CloseStatus;
|
import org.springframework.websocket.CloseStatus;
|
||||||
import org.springframework.websocket.TextMessage;
|
import org.springframework.websocket.TextMessage;
|
||||||
import org.springframework.websocket.WebSocketHandler;
|
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
|
* @author Rossen Stoyanchev
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractSockJsSession implements WebSocketSession {
|
public abstract class AbstractSockJsSession implements ConfigurableWebSocketSession {
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
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;
|
private WebSocketHandler handler;
|
||||||
|
|
||||||
|
|
@ -57,24 +66,51 @@ public abstract class AbstractSockJsSession implements WebSocketSession {
|
||||||
public AbstractSockJsSession(String sessionId, WebSocketHandler webSocketHandler) {
|
public AbstractSockJsSession(String sessionId, WebSocketHandler webSocketHandler) {
|
||||||
Assert.notNull(sessionId, "sessionId is required");
|
Assert.notNull(sessionId, "sessionId is required");
|
||||||
Assert.notNull(webSocketHandler, "webSocketHandler is required");
|
Assert.notNull(webSocketHandler, "webSocketHandler is required");
|
||||||
this.sessionId = sessionId;
|
this.id = sessionId;
|
||||||
this.handler = webSocketHandler;
|
this.handler = webSocketHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getId() {
|
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
|
@Override
|
||||||
public boolean isSecure() {
|
public boolean isSecure() {
|
||||||
// TODO
|
return "wss".equals(this.uri.getSchemeSpecificPart());
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public String getRemoteHostName() {
|
||||||
public URI getURI() {
|
return this.remoteHostName;
|
||||||
// TODO
|
}
|
||||||
return null;
|
|
||||||
|
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() {
|
public boolean isNew() {
|
||||||
|
|
@ -213,7 +249,7 @@ public abstract class AbstractSockJsSession implements WebSocketSession {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SockJS session id=" + this.sessionId;
|
return "SockJS session id=" + this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package org.springframework.sockjs;
|
package org.springframework.sockjs;
|
||||||
|
|
||||||
import org.springframework.websocket.WebSocketHandler;
|
import org.springframework.websocket.WebSocketHandler;
|
||||||
import org.springframework.websocket.WebSocketSession;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A factory for creating a SockJS session.
|
* A factory for creating a SockJS session.
|
||||||
|
|
@ -26,7 +25,7 @@ import org.springframework.websocket.WebSocketSession;
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
public interface SockJsSessionFactory<S extends WebSocketSession>{
|
public interface SockJsSessionFactory {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new SockJS session.
|
* Create a new SockJS session.
|
||||||
|
|
@ -34,6 +33,6 @@ public interface SockJsSessionFactory<S extends WebSocketSession>{
|
||||||
* @param webSocketHandler the underlying {@link WebSocketHandler}
|
* @param webSocketHandler the underlying {@link WebSocketHandler}
|
||||||
* @return a new non-null session
|
* @return a new non-null session
|
||||||
*/
|
*/
|
||||||
S createSession(String sessionId, WebSocketHandler webSocketHandler);
|
AbstractSockJsSession createSession(String sessionId, WebSocketHandler webSocketHandler);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ public abstract class AbstractSockJsService implements SockJsService, SockJsConf
|
||||||
private static final int ONE_YEAR = 365 * 24 * 60 * 60;
|
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";
|
private String clientLibraryUrl = "https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.4.min.js";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ public enum TransportType {
|
||||||
return this.httpMethod;
|
return this.httpMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setsNoCacheHeader() {
|
public boolean setsNoCache() {
|
||||||
return this.headerHints.contains("no_cache");
|
return this.headerHints.contains("no_cache");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ public enum TransportType {
|
||||||
return this.headerHints.contains("cors");
|
return this.headerHints.contains("cors");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setsJsessionIdCookie() {
|
public boolean setsJsessionId() {
|
||||||
return this.headerHints.contains("jsessionid");
|
return this.headerHints.contains("jsessionid");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.websocket.WebSocketHandler;
|
import org.springframework.websocket.WebSocketHandler;
|
||||||
import org.springframework.websocket.server.DefaultHandshakeHandler;
|
import org.springframework.websocket.server.DefaultHandshakeHandler;
|
||||||
import org.springframework.websocket.server.HandshakeHandler;
|
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<String, AbstractSockJsSession> sessions = new ConcurrentHashMap<String, AbstractSockJsSession>();
|
private final Map<String, AbstractSockJsSession> sessions = new ConcurrentHashMap<String, AbstractSockJsSession>();
|
||||||
|
|
||||||
|
private final ServerWebSocketSessionInitializer sessionInitializer = new ServerWebSocketSessionInitializer();
|
||||||
|
|
||||||
private ScheduledFuture sessionCleanupTask;
|
private ScheduledFuture sessionCleanupTask;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -187,14 +190,15 @@ public class DefaultSockJsService extends AbstractSockJsService {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractSockJsSession session = getSockJsSession(sessionId, webSocketHandler, transportHandler);
|
AbstractSockJsSession session = getSockJsSession(sessionId, webSocketHandler,
|
||||||
|
transportHandler, request, response);
|
||||||
|
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
if (transportType.setsNoCacheHeader()) {
|
if (transportType.setsNoCache()) {
|
||||||
addNoCacheHeaders(response);
|
addNoCacheHeaders(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transportType.setsJsessionIdCookie() && isJsessionIdCookieRequired()) {
|
if (transportType.setsJsessionId() && isJsessionIdCookieRequired()) {
|
||||||
Cookie cookie = request.getCookies().getCookie("JSESSIONID");
|
Cookie cookie = request.getCookies().getCookie("JSESSIONID");
|
||||||
String jsid = (cookie != null) ? cookie.getValue() : "dummy";
|
String jsid = (cookie != null) ? cookie.getValue() : "dummy";
|
||||||
// TODO: bypass use of Cookie object (causes Jetty to set Expires header)
|
// 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);
|
transportHandler.handleRequest(request, response, webSocketHandler, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbstractSockJsSession getSockJsSession(String sessionId,
|
protected AbstractSockJsSession getSockJsSession(String sessionId, WebSocketHandler handler,
|
||||||
WebSocketHandler webSocketHandler, TransportHandler transportHandler) {
|
TransportHandler transportHandler, ServerHttpRequest request, ServerHttpResponse response) {
|
||||||
|
|
||||||
AbstractSockJsSession session = this.sessions.get(sessionId);
|
AbstractSockJsSession session = this.sessions.get(sessionId);
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
|
|
@ -218,7 +222,7 @@ public class DefaultSockJsService extends AbstractSockJsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transportHandler instanceof SockJsSessionFactory) {
|
if (transportHandler instanceof SockJsSessionFactory) {
|
||||||
SockJsSessionFactory<?> sessionFactory = (SockJsSessionFactory<?>) transportHandler;
|
SockJsSessionFactory sessionFactory = (SockJsSessionFactory) transportHandler;
|
||||||
|
|
||||||
synchronized (this.sessions) {
|
synchronized (this.sessions) {
|
||||||
session = this.sessions.get(sessionId);
|
session = this.sessions.get(sessionId);
|
||||||
|
|
@ -229,7 +233,8 @@ public class DefaultSockJsService extends AbstractSockJsService {
|
||||||
scheduleSessionTask();
|
scheduleSessionTask();
|
||||||
}
|
}
|
||||||
logger.debug("Creating new session with session id \"" + sessionId + "\"");
|
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);
|
this.sessions.put(sessionId, session);
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ import org.springframework.websocket.WebSocketHandler;
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractHttpSendingTransportHandler
|
public abstract class AbstractHttpSendingTransportHandler
|
||||||
implements ConfigurableTransportHandler, SockJsSessionFactory<AbstractSockJsSession> {
|
implements ConfigurableTransportHandler, SockJsSessionFactory {
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,22 +16,16 @@
|
||||||
|
|
||||||
package org.springframework.sockjs.server.transport;
|
package org.springframework.sockjs.server.transport;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import org.springframework.sockjs.server.AbstractServerSockJsSession;
|
|
||||||
import org.springframework.sockjs.server.SockJsConfiguration;
|
import org.springframework.sockjs.server.SockJsConfiguration;
|
||||||
import org.springframework.sockjs.server.SockJsFrame;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.websocket.CloseStatus;
|
import org.springframework.websocket.CloseStatus;
|
||||||
import org.springframework.websocket.TextMessage;
|
import org.springframework.websocket.TextMessage;
|
||||||
import org.springframework.websocket.WebSocketHandler;
|
import org.springframework.websocket.WebSocketHandler;
|
||||||
import org.springframework.websocket.WebSocketSession;
|
import org.springframework.websocket.WebSocketSession;
|
||||||
import org.springframework.websocket.adapter.TextWebSocketHandlerAdapter;
|
import org.springframework.websocket.adapter.TextWebSocketHandlerAdapter;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper around a {@link WebSocketHandler} instance that parses and adds SockJS
|
* 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 SockJsConfiguration sockJsConfig;
|
||||||
|
|
||||||
private final WebSocketHandler webSocketHandler;
|
private WebSocketServerSockJsSession session;
|
||||||
|
|
||||||
private WebSocketServerSockJsSession sockJsSession;
|
|
||||||
|
|
||||||
private final AtomicInteger sessionCount = new AtomicInteger(0);
|
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(config, "sockJsConfig is required");
|
||||||
Assert.notNull(webSocketHandler, "webSocketHandler is required");
|
Assert.notNull(webSocketHandler, "webSocketHandler is required");
|
||||||
|
Assert.notNull(session, "session is required");
|
||||||
|
|
||||||
this.sockJsConfig = config;
|
this.sockJsConfig = config;
|
||||||
this.webSocketHandler = webSocketHandler;
|
this.session = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SockJsConfiguration getSockJsConfig() {
|
protected SockJsConfiguration getSockJsConfig() {
|
||||||
|
|
@ -76,100 +69,22 @@ public class SockJsWebSocketHandler extends TextWebSocketHandlerAdapter {
|
||||||
@Override
|
@Override
|
||||||
public void afterConnectionEstablished(WebSocketSession wsSession) throws Exception {
|
public void afterConnectionEstablished(WebSocketSession wsSession) throws Exception {
|
||||||
Assert.isTrue(this.sessionCount.compareAndSet(0, 1), "Unexpected connection");
|
Assert.isTrue(this.sessionCount.compareAndSet(0, 1), "Unexpected connection");
|
||||||
this.sockJsSession = new WebSocketServerSockJsSession(getSockJsSessionId(wsSession), getSockJsConfig());
|
this.session.initWebSocketSession(wsSession);
|
||||||
this.sockJsSession.initWebSocketSession(wsSession);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleTextMessage(WebSocketSession wsSession, TextMessage message) throws Exception {
|
public void handleTextMessage(WebSocketSession wsSession, TextMessage message) throws Exception {
|
||||||
this.sockJsSession.handleMessage(message, wsSession);
|
this.session.handleMessage(message, wsSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterConnectionClosed(WebSocketSession wsSession, CloseStatus status) throws Exception {
|
public void afterConnectionClosed(WebSocketSession wsSession, CloseStatus status) throws Exception {
|
||||||
this.sockJsSession.delegateConnectionClosed(status);
|
this.session.delegateConnectionClosed(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleTransportError(WebSocketSession webSocketSession, Throwable exception) throws Exception {
|
public void handleTransportError(WebSocketSession webSocketSession, Throwable exception) throws Exception {
|
||||||
this.sockJsSession.delegateError(exception);
|
this.session.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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
||||||
import org.springframework.http.server.ServerHttpRequest;
|
import org.springframework.http.server.ServerHttpRequest;
|
||||||
import org.springframework.http.server.ServerHttpResponse;
|
import org.springframework.http.server.ServerHttpResponse;
|
||||||
import org.springframework.sockjs.AbstractSockJsSession;
|
import org.springframework.sockjs.AbstractSockJsSession;
|
||||||
|
import org.springframework.sockjs.SockJsSessionFactory;
|
||||||
import org.springframework.sockjs.server.ConfigurableTransportHandler;
|
import org.springframework.sockjs.server.ConfigurableTransportHandler;
|
||||||
import org.springframework.sockjs.server.SockJsConfiguration;
|
import org.springframework.sockjs.server.SockJsConfiguration;
|
||||||
import org.springframework.sockjs.server.TransportErrorException;
|
import org.springframework.sockjs.server.TransportErrorException;
|
||||||
|
|
@ -39,7 +40,8 @@ import org.springframework.websocket.server.HandshakeHandler;
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
public class WebSocketTransportHandler implements ConfigurableTransportHandler, HandshakeHandler {
|
public class WebSocketTransportHandler implements ConfigurableTransportHandler,
|
||||||
|
HandshakeHandler, SockJsSessionFactory {
|
||||||
|
|
||||||
private final HandshakeHandler handshakeHandler;
|
private final HandshakeHandler handshakeHandler;
|
||||||
|
|
||||||
|
|
@ -61,12 +63,18 @@ public class WebSocketTransportHandler implements ConfigurableTransportHandler,
|
||||||
this.sockJsConfig = sockJsConfig;
|
this.sockJsConfig = sockJsConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractSockJsSession createSession(String sessionId, WebSocketHandler webSocketHandler) {
|
||||||
|
return new WebSocketServerSockJsSession(sessionId, this.sockJsConfig, webSocketHandler);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleRequest(ServerHttpRequest request, ServerHttpResponse response,
|
public void handleRequest(ServerHttpRequest request, ServerHttpResponse response,
|
||||||
WebSocketHandler webSocketHandler, AbstractSockJsSession session) throws TransportErrorException {
|
WebSocketHandler webSocketHandler, AbstractSockJsSession session) throws TransportErrorException {
|
||||||
|
|
||||||
try {
|
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);
|
this.handshakeHandler.doHandshake(request, response, sockJsWrapper);
|
||||||
}
|
}
|
||||||
catch (Throwable t) {
|
catch (Throwable t) {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@
|
||||||
package org.springframework.websocket;
|
package org.springframework.websocket;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows sending messages over a WebSocket connection as well as closing it.
|
* Allows sending messages over a WebSocket connection as well as closing it.
|
||||||
|
|
@ -33,9 +35,9 @@ public interface WebSocketSession {
|
||||||
String getId();
|
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.
|
* Return whether the underlying socket is using a secure transport.
|
||||||
|
|
@ -43,9 +45,26 @@ public interface WebSocketSession {
|
||||||
boolean isSecure();
|
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
|
||||||
|
* <code>null</code>.
|
||||||
*/
|
*/
|
||||||
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
|
* Send a WebSocket message either {@link TextMessage} or
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* @author Rossen Stoyanchev
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractWebSocketSesssionAdapter implements WebSocketSession {
|
public abstract class AbstractWebSocketSesssionAdapter<T> implements ConfigurableWebSocketSession {
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
|
|
||||||
|
public abstract void initSession(T session);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void sendMessage(WebSocketMessage message) throws IOException {
|
public final void sendMessage(WebSocketMessage message) throws IOException {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,6 @@ import org.springframework.websocket.BinaryMessage;
|
||||||
import org.springframework.websocket.CloseStatus;
|
import org.springframework.websocket.CloseStatus;
|
||||||
import org.springframework.websocket.TextMessage;
|
import org.springframework.websocket.TextMessage;
|
||||||
import org.springframework.websocket.WebSocketHandler;
|
import org.springframework.websocket.WebSocketHandler;
|
||||||
import org.springframework.websocket.WebSocketSession;
|
|
||||||
import org.springframework.websocket.support.ExceptionWebSocketHandlerDecorator;
|
import org.springframework.websocket.support.ExceptionWebSocketHandlerDecorator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -40,18 +39,20 @@ public class JettyWebSocketListenerAdapter implements WebSocketListener {
|
||||||
|
|
||||||
private final WebSocketHandler webSocketHandler;
|
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(webSocketHandler, "webSocketHandler is required");
|
||||||
|
Assert.notNull(wsSession, "wsSession is required");
|
||||||
this.webSocketHandler = webSocketHandler;
|
this.webSocketHandler = webSocketHandler;
|
||||||
|
this.wsSession = wsSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onWebSocketConnect(Session session) {
|
public void onWebSocketConnect(Session session) {
|
||||||
this.wsSession = new JettyWebSocketSessionAdapter(session);
|
this.wsSession.initSession(session);
|
||||||
try {
|
try {
|
||||||
this.webSocketHandler.afterConnectionEstablished(this.wsSession);
|
this.webSocketHandler.afterConnectionEstablished(this.wsSession);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,12 @@
|
||||||
package org.springframework.websocket.adapter;
|
package org.springframework.websocket.adapter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
import org.eclipse.jetty.websocket.api.Session;
|
import org.eclipse.jetty.websocket.api.Session;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.websocket.BinaryMessage;
|
import org.springframework.websocket.BinaryMessage;
|
||||||
import org.springframework.websocket.CloseStatus;
|
import org.springframework.websocket.CloseStatus;
|
||||||
|
|
@ -31,38 +34,78 @@ import org.springframework.websocket.WebSocketSession;
|
||||||
* Adapts Jetty's {@link Session} to Spring's {@link WebSocketSession}.
|
* Adapts Jetty's {@link Session} to Spring's {@link WebSocketSession}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
public class JettyWebSocketSessionAdapter extends AbstractWebSocketSesssionAdapter {
|
public class JettyWebSocketSessionAdapter
|
||||||
|
extends AbstractWebSocketSesssionAdapter<org.eclipse.jetty.websocket.api.Session> {
|
||||||
|
|
||||||
private Session session;
|
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;
|
this.session = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return ObjectUtils.getIdentityHexString(this.session);
|
return ObjectUtils.getIdentityHexString(this.session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isOpen() {
|
|
||||||
return this.session.isOpen();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSecure() {
|
public boolean isSecure() {
|
||||||
return this.session.isSecure();
|
return this.session.isSecure();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URI getURI() {
|
public URI getUri() {
|
||||||
return this.session.getUpgradeRequest().getRequestURI();
|
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
|
@Override
|
||||||
protected void sendTextMessage(TextMessage message) throws IOException {
|
protected void sendTextMessage(TextMessage message) throws IOException {
|
||||||
this.session.getRemote().sendString(message.getPayload());
|
this.session.getRemote().sendString(message.getPayload());
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,11 @@ import org.springframework.websocket.BinaryMessage;
|
||||||
import org.springframework.websocket.CloseStatus;
|
import org.springframework.websocket.CloseStatus;
|
||||||
import org.springframework.websocket.TextMessage;
|
import org.springframework.websocket.TextMessage;
|
||||||
import org.springframework.websocket.WebSocketHandler;
|
import org.springframework.websocket.WebSocketHandler;
|
||||||
import org.springframework.websocket.WebSocketSession;
|
|
||||||
import org.springframework.websocket.support.ExceptionWebSocketHandlerDecorator;
|
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
|
* @author Rossen Stoyanchev
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
|
|
@ -46,19 +45,22 @@ public class StandardEndpointAdapter extends Endpoint {
|
||||||
|
|
||||||
private final WebSocketHandler handler;
|
private final WebSocketHandler handler;
|
||||||
|
|
||||||
private WebSocketSession wsSession;
|
private final StandardWebSocketSessionAdapter wsSession;
|
||||||
|
|
||||||
|
|
||||||
public StandardEndpointAdapter(WebSocketHandler webSocketHandler) {
|
public StandardEndpointAdapter(WebSocketHandler handler, StandardWebSocketSessionAdapter wsSession) {
|
||||||
Assert.notNull(webSocketHandler, "webSocketHandler is required");
|
Assert.notNull(handler, "handler is required");
|
||||||
this.handler = webSocketHandler;
|
Assert.notNull(wsSession, "wsSession is required");
|
||||||
|
this.handler = handler;
|
||||||
|
this.wsSession = wsSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpen(final javax.websocket.Session session, EndpointConfig config) {
|
public void onOpen(final javax.websocket.Session session, EndpointConfig config) {
|
||||||
|
|
||||||
this.wsSession = new StandardWebSocketSessionAdapter(session);
|
this.wsSession.initSession(session);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.handler.afterConnectionEstablished(this.wsSession);
|
this.handler.afterConnectionEstablished(this.wsSession);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package org.springframework.websocket.adapter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
import javax.websocket.CloseReason;
|
import javax.websocket.CloseReason;
|
||||||
import javax.websocket.CloseReason.CloseCodes;
|
import javax.websocket.CloseReason.CloseCodes;
|
||||||
|
|
@ -35,35 +36,76 @@ import org.springframework.websocket.WebSocketSession;
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
public class StandardWebSocketSessionAdapter extends AbstractWebSocketSesssionAdapter {
|
public class StandardWebSocketSessionAdapter extends AbstractWebSocketSesssionAdapter<javax.websocket.Session> {
|
||||||
|
|
||||||
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");
|
Assert.notNull(session, "session is required");
|
||||||
this.session = session;
|
this.session = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return this.session.getId();
|
return this.session.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOpen() {
|
public URI getUri() {
|
||||||
return this.session.isOpen();
|
return this.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUri(URI uri) {
|
||||||
|
this.uri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSecure() {
|
public boolean isSecure() {
|
||||||
return this.session.isSecure();
|
return this.session.isSecure();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URI getURI() {
|
public Principal getPrincipal() {
|
||||||
return this.session.getRequestURI();
|
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
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -28,12 +28,12 @@ import javax.websocket.ClientEndpointConfig.Configurator;
|
||||||
import javax.websocket.ContainerProvider;
|
import javax.websocket.ContainerProvider;
|
||||||
import javax.websocket.Endpoint;
|
import javax.websocket.Endpoint;
|
||||||
import javax.websocket.HandshakeResponse;
|
import javax.websocket.HandshakeResponse;
|
||||||
import javax.websocket.Session;
|
|
||||||
import javax.websocket.WebSocketContainer;
|
import javax.websocket.WebSocketContainer;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.web.util.UriComponents;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
import org.springframework.websocket.WebSocketHandler;
|
import org.springframework.websocket.WebSocketHandler;
|
||||||
import org.springframework.websocket.WebSocketSession;
|
import org.springframework.websocket.WebSocketSession;
|
||||||
|
|
@ -67,15 +67,26 @@ public class StandardWebSocketClient implements WebSocketClient {
|
||||||
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, String uriTemplate, Object... uriVariables)
|
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, String uriTemplate, Object... uriVariables)
|
||||||
throws WebSocketConnectFailureException {
|
throws WebSocketConnectFailureException {
|
||||||
|
|
||||||
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode().toUri();
|
UriComponents uriComponents = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode();
|
||||||
return doHandshake(webSocketHandler, null, uri);
|
return doHandshake(webSocketHandler, null, uriComponents);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler,
|
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler,
|
||||||
final HttpHeaders httpHeaders, URI uri) throws WebSocketConnectFailureException {
|
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();
|
ClientEndpointConfig.Builder configBuidler = ClientEndpointConfig.Builder.create();
|
||||||
if (httpHeaders != null) {
|
if (httpHeaders != null) {
|
||||||
|
|
@ -109,8 +120,9 @@ public class StandardWebSocketClient implements WebSocketClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Session session = this.webSocketContainer.connectToServer(endpoint, configBuidler.build(), uri);
|
// TODO: do not block
|
||||||
return new StandardWebSocketSessionAdapter(session);
|
this.webSocketContainer.connectToServer(endpoint, configBuidler.build(), uri);
|
||||||
|
return session;
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
throw new WebSocketConnectFailureException("Failed to connect to " + uri, e);
|
throw new WebSocketConnectFailureException("Failed to connect to " + uri, e);
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,12 @@
|
||||||
package org.springframework.websocket.client.jetty;
|
package org.springframework.websocket.client.jetty;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.eclipse.jetty.websocket.api.Session;
|
|
||||||
import org.springframework.context.SmartLifecycle;
|
import org.springframework.context.SmartLifecycle;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.web.util.UriComponents;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
import org.springframework.websocket.WebSocketHandler;
|
import org.springframework.websocket.WebSocketHandler;
|
||||||
import org.springframework.websocket.WebSocketSession;
|
import org.springframework.websocket.WebSocketSession;
|
||||||
|
|
@ -126,23 +125,34 @@ public class JettyWebSocketClient implements WebSocketClient, SmartLifecycle {
|
||||||
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, String uriTemplate, Object... uriVariables)
|
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, String uriTemplate, Object... uriVariables)
|
||||||
throws WebSocketConnectFailureException {
|
throws WebSocketConnectFailureException {
|
||||||
|
|
||||||
URI uri = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode().toUri();
|
UriComponents uriComponents = UriComponentsBuilder.fromUriString(uriTemplate).buildAndExpand(uriVariables).encode();
|
||||||
return doHandshake(webSocketHandler, null, uri);
|
return doHandshake(webSocketHandler, null, uriComponents);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, HttpHeaders headers, URI uri)
|
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, HttpHeaders headers, URI uri)
|
||||||
throws WebSocketConnectFailureException {
|
throws WebSocketConnectFailureException {
|
||||||
|
|
||||||
|
return doHandshake(webSocketHandler, headers, UriComponentsBuilder.fromUri(uri).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public WebSocketSession doHandshake(WebSocketHandler webSocketHandler, HttpHeaders headers, UriComponents uriComponents)
|
||||||
|
throws WebSocketConnectFailureException {
|
||||||
|
|
||||||
// TODO: populate headers
|
// 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 {
|
try {
|
||||||
// block for now
|
// TODO: do not block
|
||||||
Future<org.eclipse.jetty.websocket.api.Session> future = this.client.connect(listener, uri);
|
this.client.connect(listener, uri).get();
|
||||||
Session session = future.get();
|
return session;
|
||||||
return new JettyWebSocketSessionAdapter(session);
|
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
throw new WebSocketConnectFailureException("Failed to connect to " + uri, e);
|
throw new WebSocketConnectFailureException("Failed to connect to " + uri, e);
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ import org.springframework.http.server.ServerHttpRequest;
|
||||||
import org.springframework.http.server.ServerHttpResponse;
|
import org.springframework.http.server.ServerHttpResponse;
|
||||||
import org.springframework.websocket.WebSocketHandler;
|
import org.springframework.websocket.WebSocketHandler;
|
||||||
import org.springframework.websocket.adapter.StandardEndpointAdapter;
|
import org.springframework.websocket.adapter.StandardEndpointAdapter;
|
||||||
|
import org.springframework.websocket.adapter.StandardWebSocketSessionAdapter;
|
||||||
|
import org.springframework.websocket.server.HandshakeFailureException;
|
||||||
import org.springframework.websocket.server.RequestUpgradeStrategy;
|
import org.springframework.websocket.server.RequestUpgradeStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -39,15 +41,20 @@ public abstract class AbstractEndpointUpgradeStrategy implements RequestUpgradeS
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
|
private final ServerWebSocketSessionInitializer wsSessionInitializer = new ServerWebSocketSessionInitializer();
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void upgrade(ServerHttpRequest request, ServerHttpResponse response,
|
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,
|
protected abstract void upgradeInternal(ServerHttpRequest request, ServerHttpResponse response,
|
||||||
String selectedProtocol, Endpoint endpoint) throws IOException;
|
String selectedProtocol, Endpoint endpoint) throws IOException, HandshakeFailureException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ import org.springframework.http.server.ServletServerHttpResponse;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.websocket.WebSocketHandler;
|
import org.springframework.websocket.WebSocketHandler;
|
||||||
import org.springframework.websocket.adapter.JettyWebSocketListenerAdapter;
|
import org.springframework.websocket.adapter.JettyWebSocketListenerAdapter;
|
||||||
|
import org.springframework.websocket.adapter.JettyWebSocketSessionAdapter;
|
||||||
import org.springframework.websocket.server.HandshakeFailureException;
|
import org.springframework.websocket.server.HandshakeFailureException;
|
||||||
import org.springframework.websocket.server.RequestUpgradeStrategy;
|
import org.springframework.websocket.server.RequestUpgradeStrategy;
|
||||||
|
|
||||||
|
|
@ -53,11 +54,13 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy {
|
||||||
|
|
||||||
// FIXME when to call factory.cleanup();
|
// 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";
|
+ ".HANDLER_PROVIDER";
|
||||||
|
|
||||||
private WebSocketServerFactory factory;
|
private WebSocketServerFactory factory;
|
||||||
|
|
||||||
|
private final ServerWebSocketSessionInitializer wsSessionInitializer = new ServerWebSocketSessionInitializer();
|
||||||
|
|
||||||
|
|
||||||
public JettyRequestUpgradeStrategy() {
|
public JettyRequestUpgradeStrategy() {
|
||||||
this.factory = new WebSocketServerFactory();
|
this.factory = new WebSocketServerFactory();
|
||||||
|
|
@ -65,17 +68,14 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy {
|
||||||
@Override
|
@Override
|
||||||
public Object createWebSocket(UpgradeRequest request, UpgradeResponse response) {
|
public Object createWebSocket(UpgradeRequest request, UpgradeResponse response) {
|
||||||
Assert.isInstanceOf(ServletWebSocketRequest.class, request);
|
Assert.isInstanceOf(ServletWebSocketRequest.class, request);
|
||||||
ServletWebSocketRequest servletRequest = (ServletWebSocketRequest) request;
|
return ((ServletWebSocketRequest) request).getServletAttributes().get(WEBSOCKET_LISTENER_ATTR_NAME);
|
||||||
WebSocketHandler webSocketHandler =
|
|
||||||
(WebSocketHandler) servletRequest.getServletAttributes().get(HANDLER_PROVIDER_ATTR_NAME);
|
|
||||||
return new JettyWebSocketListenerAdapter(webSocketHandler);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
this.factory.init();
|
this.factory.init();
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
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);
|
Assert.isInstanceOf(ServletServerHttpResponse.class, response);
|
||||||
HttpServletResponse servletResponse = ((ServletServerHttpResponse) response).getServletResponse();
|
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,
|
JettyWebSocketSessionAdapter session = new JettyWebSocketSessionAdapter();
|
||||||
String selectedProtocol, final WebSocketHandler webSocketHandler) throws IOException {
|
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(servletRequest, servletResponse)) {
|
||||||
|
|
||||||
if (!this.factory.acceptWebSocket(request, response)) {
|
|
||||||
// should never happen
|
// should never happen
|
||||||
throw new HandshakeFailureException("WebSocket request not accepted by Jetty");
|
throw new HandshakeFailureException("WebSocket request not accepted by Jetty");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -41,7 +41,7 @@ public class LoggingWebSocketHandlerDecorator extends WebSocketHandlerDecorator
|
||||||
@Override
|
@Override
|
||||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Connection established, " + session + ", uri=" + session.getURI());
|
logger.debug("Connection established, " + session + ", uri=" + session.getUri());
|
||||||
}
|
}
|
||||||
super.afterConnectionEstablished(session);
|
super.afterConnectionEstablished(session);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue