Skip to content

Commit 13ce20b

Browse files
committed
Remove IOException from HandshakeHandler
1 parent 2397b21 commit 13ce20b

11 files changed

+109
-83
lines changed

spring-websocket/src/main/java/org/springframework/web/socket/server/DefaultHandshakeHandler.java

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -132,50 +132,55 @@ public String[] getSupportedProtocols() {
132132

133133
@Override
134134
public final boolean doHandshake(ServerHttpRequest request, ServerHttpResponse response,
135-
WebSocketHandler webSocketHandler, Map<String, Object> attributes) throws IOException, HandshakeFailureException {
135+
WebSocketHandler wsHandler, Map<String, Object> attributes) throws HandshakeFailureException {
136136

137137
if (logger.isDebugEnabled()) {
138138
logger.debug("Initiating handshake for " + request.getURI() + ", headers=" + request.getHeaders());
139139
}
140140

141-
if (!HttpMethod.GET.equals(request.getMethod())) {
142-
response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED);
143-
response.getHeaders().setAllow(Collections.singleton(HttpMethod.GET));
144-
logger.debug("Only HTTP GET is allowed, current method is " + request.getMethod());
145-
return false;
146-
}
147-
if (!"WebSocket".equalsIgnoreCase(request.getHeaders().getUpgrade())) {
148-
handleInvalidUpgradeHeader(request, response);
149-
return false;
150-
}
151-
if (!request.getHeaders().getConnection().contains("Upgrade") &&
152-
!request.getHeaders().getConnection().contains("upgrade")) {
153-
handleInvalidConnectHeader(request, response);
154-
return false;
155-
}
156-
if (!isWebSocketVersionSupported(request)) {
157-
handleWebSocketVersionNotSupported(request, response);
158-
return false;
159-
}
160-
if (!isValidOrigin(request)) {
161-
response.setStatusCode(HttpStatus.FORBIDDEN);
162-
return false;
141+
try {
142+
if (!HttpMethod.GET.equals(request.getMethod())) {
143+
response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED);
144+
response.getHeaders().setAllow(Collections.singleton(HttpMethod.GET));
145+
logger.debug("Only HTTP GET is allowed, current method is " + request.getMethod());
146+
return false;
147+
}
148+
if (!"WebSocket".equalsIgnoreCase(request.getHeaders().getUpgrade())) {
149+
handleInvalidUpgradeHeader(request, response);
150+
return false;
151+
}
152+
if (!request.getHeaders().getConnection().contains("Upgrade") &&
153+
!request.getHeaders().getConnection().contains("upgrade")) {
154+
handleInvalidConnectHeader(request, response);
155+
return false;
156+
}
157+
if (!isWebSocketVersionSupported(request)) {
158+
handleWebSocketVersionNotSupported(request, response);
159+
return false;
160+
}
161+
if (!isValidOrigin(request)) {
162+
response.setStatusCode(HttpStatus.FORBIDDEN);
163+
return false;
164+
}
165+
String wsKey = request.getHeaders().getSecWebSocketKey();
166+
if (wsKey == null) {
167+
logger.debug("Missing \"Sec-WebSocket-Key\" header");
168+
response.setStatusCode(HttpStatus.BAD_REQUEST);
169+
return false;
170+
}
163171
}
164-
String wsKey = request.getHeaders().getSecWebSocketKey();
165-
if (wsKey == null) {
166-
logger.debug("Missing \"Sec-WebSocket-Key\" header");
167-
response.setStatusCode(HttpStatus.BAD_REQUEST);
168-
return false;
172+
catch (IOException ex) {
173+
throw new HandshakeFailureException(
174+
"Response update failed during upgrade to WebSocket, uri=" + request.getURI(), ex);
169175
}
170176

171-
String selectedProtocol = selectProtocol(request.getHeaders().getSecWebSocketProtocol());
172-
// TODO: select extensions
177+
String subProtocol = selectProtocol(request.getHeaders().getSecWebSocketProtocol());
173178

174179
if (logger.isDebugEnabled()) {
175-
logger.debug("Upgrading request");
180+
logger.debug("Upgrading request, sub-protocol=" + subProtocol);
176181
}
177182

178-
this.requestUpgradeStrategy.upgrade(request, response, selectedProtocol, webSocketHandler, attributes);
183+
this.requestUpgradeStrategy.upgrade(request, response, subProtocol, wsHandler, attributes);
179184

180185
return true;
181186
}

spring-websocket/src/main/java/org/springframework/web/socket/server/HandshakeFailureException.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,19 @@
3434
@SuppressWarnings("serial")
3535
public class HandshakeFailureException extends NestedRuntimeException {
3636

37-
public HandshakeFailureException(String msg, Throwable cause) {
38-
super(msg, cause);
37+
38+
/**
39+
* Constructor with message and root cause.
40+
*/
41+
public HandshakeFailureException(String message, Throwable cause) {
42+
super(message, cause);
3943
}
4044

41-
public HandshakeFailureException(String msg) {
42-
super(msg);
45+
/**
46+
* Constructor without a message.
47+
*/
48+
public HandshakeFailureException(String message) {
49+
super(message);
4350
}
4451

4552
}

spring-websocket/src/main/java/org/springframework/web/socket/server/HandshakeHandler.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.web.socket.server;
1818

19-
import java.io.IOException;
2019
import java.util.Map;
2120

2221
import org.springframework.http.server.ServerHttpRequest;
@@ -36,6 +35,7 @@
3635
*/
3736
public interface HandshakeHandler {
3837

38+
3939
/**
4040
* Initiate the handshake.
4141
*
@@ -51,14 +51,11 @@ public interface HandshakeHandler {
5151
* response status, headers, and body will have been updated to reflect the
5252
* result of the negotiation
5353
*
54-
* @throws IOException thrown when accessing or setting the response
55-
*
5654
* @throws HandshakeFailureException thrown when handshake processing failed to
5755
* complete due to an internal, unrecoverable error, i.e. a server error as
58-
* opposed to a failure to successfully negotiate the requirements of the
59-
* handshake request.
56+
* opposed to a failure to successfully negotiate the handshake.
6057
*/
6158
boolean doHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
62-
Map<String, Object> attributes) throws IOException, HandshakeFailureException;
59+
Map<String, Object> attributes) throws HandshakeFailureException;
6360

6461
}

spring-websocket/src/main/java/org/springframework/web/socket/server/RequestUpgradeStrategy.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.web.socket.server;
1818

19-
import java.io.IOException;
2019
import java.util.Map;
2120

2221
import org.springframework.http.server.ServerHttpRequest;
@@ -53,6 +52,6 @@ public interface RequestUpgradeStrategy {
5352
* handshake request.
5453
*/
5554
void upgrade(ServerHttpRequest request, ServerHttpResponse response, String acceptedProtocol,
56-
WebSocketHandler wsHandler, Map<String, Object> attributes) throws IOException, HandshakeFailureException;
55+
WebSocketHandler wsHandler, Map<String, Object> attributes) throws HandshakeFailureException;
5756

5857
}

spring-websocket/src/main/java/org/springframework/web/socket/server/support/AbstractStandardUpgradeStrategy.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.web.socket.server.support;
1818

19-
import java.io.IOException;
2019
import java.net.InetSocketAddress;
2120
import java.util.Map;
2221

@@ -34,7 +33,8 @@
3433
import org.springframework.web.socket.server.RequestUpgradeStrategy;
3534

3635
/**
37-
* A {@link RequestUpgradeStrategy} for containers that support standard Java WebSocket.
36+
* A base class for {@link RequestUpgradeStrategy} implementations that build on the
37+
* standard WebSocket API for Java.
3838
*
3939
* @author Rossen Stoyanchev
4040
* @since 4.0
@@ -46,20 +46,20 @@ public abstract class AbstractStandardUpgradeStrategy implements RequestUpgradeS
4646

4747
@Override
4848
public void upgrade(ServerHttpRequest request, ServerHttpResponse response, String acceptedProtocol,
49-
WebSocketHandler wsHandler, Map<String, Object> attributes)
50-
throws IOException, HandshakeFailureException {
49+
WebSocketHandler wsHandler, Map<String, Object> attributes) throws HandshakeFailureException {
5150

5251
HttpHeaders headers = request.getHeaders();
52+
5353
InetSocketAddress localAddr = request.getLocalAddress();
5454
InetSocketAddress remoteAddr = request.getRemoteAddress();
5555

56-
StandardWebSocketSession wsSession = new StandardWebSocketSession(headers, attributes, localAddr, remoteAddr);
57-
StandardWebSocketHandlerAdapter endpoint = new StandardWebSocketHandlerAdapter(wsHandler, wsSession);
56+
StandardWebSocketSession session = new StandardWebSocketSession(headers, attributes, localAddr, remoteAddr);
57+
StandardWebSocketHandlerAdapter endpoint = new StandardWebSocketHandlerAdapter(wsHandler, session);
5858

5959
upgradeInternal(request, response, acceptedProtocol, endpoint);
6060
}
6161

6262
protected abstract void upgradeInternal(ServerHttpRequest request, ServerHttpResponse response,
63-
String selectedProtocol, Endpoint endpoint) throws IOException, HandshakeFailureException;
63+
String selectedProtocol, Endpoint endpoint) throws HandshakeFailureException;
6464

6565
}

spring-websocket/src/main/java/org/springframework/web/socket/server/support/GlassFishRequestUpgradeStrategy.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public String[] getSupportedVersions() {
7070

7171
@Override
7272
public void upgradeInternal(ServerHttpRequest request, ServerHttpResponse response,
73-
String selectedProtocol, Endpoint endpoint) throws IOException, HandshakeFailureException {
73+
String selectedProtocol, Endpoint endpoint) throws HandshakeFailureException {
7474

7575
Assert.isTrue(request instanceof ServletServerHttpRequest);
7676
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
@@ -85,12 +85,16 @@ public void upgradeInternal(ServerHttpRequest request, ServerHttpResponse respon
8585
webSocketEngine.register(webSocketApplication);
8686
}
8787
catch (DeploymentException ex) {
88-
throw new HandshakeFailureException("Failed to deploy endpoint in GlassFish", ex);
88+
throw new HandshakeFailureException("Failed to configure endpoint in GlassFish", ex);
8989
}
9090

9191
try {
9292
performUpgrade(servletRequest, servletResponse, request.getHeaders(), webSocketApplication);
9393
}
94+
catch (IOException ex) {
95+
throw new HandshakeFailureException(
96+
"Response update failed during upgrade to WebSocket, uri=" + request.getURI(), ex);
97+
}
9498
finally {
9599
webSocketEngine.unregister(webSocketApplication);
96100
}

spring-websocket/src/main/java/org/springframework/web/socket/server/support/JettyRequestUpgradeStrategy.java

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,30 +44,26 @@
4444
* {@code org.eclipse.jetty.websocket.server.WebSocketHandler} class.
4545
*
4646
* @author Phillip Webb
47+
* @author Rossen Stoyanchev
4748
* @since 4.0
4849
*/
4950
public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy {
5051

51-
// FIXME jetty has options, timeouts etc. Do we need a common abstraction
52-
53-
// FIXME need a way for someone to plug their own RequestUpgradeStrategy or override
54-
// Jetty settings
55-
56-
// FIXME when to call factory.cleanup();
57-
58-
private static final String WEBSOCKET_LISTENER_ATTR_NAME = JettyRequestUpgradeStrategy.class.getName()
59-
+ ".HANDLER_PROVIDER";
52+
private static final String WS_HANDLER_ATTR_NAME = JettyRequestUpgradeStrategy.class.getName() + ".WS_LISTENER";
6053

6154
private WebSocketServerFactory factory;
6255

6356

57+
/**
58+
* Default constructor.
59+
*/
6460
public JettyRequestUpgradeStrategy() {
6561
this.factory = new WebSocketServerFactory();
6662
this.factory.setCreator(new WebSocketCreator() {
6763
@Override
6864
public Object createWebSocket(UpgradeRequest request, UpgradeResponse response) {
6965
Assert.isInstanceOf(ServletUpgradeRequest.class, request);
70-
return ((ServletUpgradeRequest) request).getServletAttributes().get(WEBSOCKET_LISTENER_ATTR_NAME);
66+
return ((ServletUpgradeRequest) request).getServletAttributes().get(WS_HANDLER_ATTR_NAME);
7167
}
7268
});
7369
try {
@@ -86,27 +82,29 @@ public String[] getSupportedVersions() {
8682

8783
@Override
8884
public void upgrade(ServerHttpRequest request, ServerHttpResponse response,
89-
String protocol, WebSocketHandler wsHandler, Map<String, Object> attrs) throws IOException {
85+
String protocol, WebSocketHandler wsHandler, Map<String, Object> attrs) throws HandshakeFailureException {
9086

9187
Assert.isInstanceOf(ServletServerHttpRequest.class, request);
9288
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
9389

9490
Assert.isInstanceOf(ServletServerHttpResponse.class, response);
9591
HttpServletResponse servletResponse = ((ServletServerHttpResponse) response).getServletResponse();
9692

97-
if (!this.factory.isUpgradeRequest(servletRequest, servletResponse)) {
98-
// should never happen
99-
throw new HandshakeFailureException("Not a WebSocket request");
100-
}
101-
102-
JettyWebSocketSession wsSession = new JettyWebSocketSession(request.getPrincipal(), attrs);
103-
JettyWebSocketHandlerAdapter wsListener = new JettyWebSocketHandlerAdapter(wsHandler, wsSession);
93+
Assert.isTrue(this.factory.isUpgradeRequest(servletRequest, servletResponse), "Not a WebSocket handshake");
10494

105-
servletRequest.setAttribute(WEBSOCKET_LISTENER_ATTR_NAME, wsListener);
95+
JettyWebSocketSession session = new JettyWebSocketSession(request.getPrincipal(), attrs);
96+
JettyWebSocketHandlerAdapter handlerAdapter = new JettyWebSocketHandlerAdapter(wsHandler, session);
10697

107-
if (!this.factory.acceptWebSocket(servletRequest, servletResponse)) {
108-
// should not happen
109-
throw new HandshakeFailureException("WebSocket request not accepted by Jetty");
98+
try {
99+
servletRequest.setAttribute(WS_HANDLER_ATTR_NAME, handlerAdapter);
100+
this.factory.acceptWebSocket(servletRequest, servletResponse);
101+
}
102+
catch (IOException ex) {
103+
throw new HandshakeFailureException(
104+
"Response update failed during upgrade to WebSocket, uri=" + request.getURI(), ex);
105+
}
106+
finally {
107+
servletRequest.removeAttribute(WS_HANDLER_ATTR_NAME);
110108
}
111109
}
112110

spring-websocket/src/main/java/org/springframework/web/socket/server/support/TomcatRequestUpgradeStrategy.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
package org.springframework.web.socket.server.support;
1818

19+
import java.io.IOException;
1920
import java.util.Arrays;
2021
import java.util.Collections;
2122
import java.util.Map;
2223

2324
import javax.servlet.ServletContext;
25+
import javax.servlet.ServletException;
2426
import javax.servlet.http.HttpServletRequest;
2527
import javax.servlet.http.HttpServletResponse;
2628
import javax.websocket.Endpoint;
@@ -67,8 +69,13 @@ public void upgradeInternal(ServerHttpRequest request, ServerHttpResponse respon
6769
try {
6870
getContainer(servletRequest).doUpgrade(servletRequest, servletResponse, endpointConfig, pathParams);
6971
}
70-
catch (Exception ex) {
71-
throw new HandshakeFailureException("Failed to upgrade HttpServletRequest", ex);
72+
catch (ServletException ex) {
73+
throw new HandshakeFailureException(
74+
"Servlet request failed to upgrade to WebSocket, uri=" + request.getURI(), ex);
75+
}
76+
catch (IOException ex) {
77+
throw new HandshakeFailureException(
78+
"Response update failed during upgrade to WebSocket, uri=" + request.getURI(), ex);
7279
}
7380
}
7481

spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsException.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ public class SockJsException extends NestedRuntimeException {
3030
private final String sessionId;
3131

3232

33+
public SockJsException(String message, Throwable cause) {
34+
this(message, null, cause);
35+
}
36+
3337
public SockJsException(String message, String sessionId, Throwable cause) {
3438
super(message, cause);
3539
this.sessionId = sessionId;

spring-websocket/src/main/java/org/springframework/web/socket/sockjs/SockJsHttpRequestHandler.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,15 @@ protected WebSocketHandler decorateWebSocketHandler(WebSocketHandler handler) {
7474
public void handleRequest(HttpServletRequest servletRequest, HttpServletResponse servletResponse)
7575
throws ServletException, IOException {
7676

77-
ServerHttpRequest serverRequest = new ServletServerHttpRequest(servletRequest);
78-
ServerHttpResponse serverResponse = new ServletServerHttpResponse(servletResponse);
77+
ServerHttpRequest request = new ServletServerHttpRequest(servletRequest);
78+
ServerHttpResponse response = new ServletServerHttpResponse(servletResponse);
7979

80-
this.sockJsService.handleRequest(serverRequest, serverResponse, this.webSocketHandler);
80+
try {
81+
this.sockJsService.handleRequest(request, response, this.webSocketHandler);
82+
}
83+
catch (Throwable t) {
84+
throw new SockJsException("Uncaught failure in SockJS request, uri=" + request.getURI(), t);
85+
}
8186
}
8287

8388
}

0 commit comments

Comments
 (0)