I need to be able to abort a websocket connection during the handshake in case the HTTP request does not meet certain criteria. From what I understand, the proper place to d
you're right , use ´modifyHandShake()´ to update the response headers , you need exactly to remove or set the value of the header Sec-WebSocket-Accept
, check this from the spec
The |Sec-WebSocket-Accept| header field indicates whether the server is willing to accept the connection. If present, this header field must include a hash of the client's nonce sent in |Sec-WebSocket-Key| along with a predefined GUID. Any other value must not be interpreted as an acceptance of the connection by the server.
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
These fields are checked by the WebSocket client for scripted pages. If the |Sec-WebSocket-Accept| value does not match the expected value, if the header field is missing, or if the HTTP status code is not 101, the connection will not be established, and WebSocket frames will not be sent.
your code would look like this :
@Override
public void modifyHandshake(ServerEndpointConfig sec,
HandshakeRequest request, HandshakeResponse response) {
super.modifyHandshake(sec, request, response);
response.getHeaders().put(HandshakeResponse.SEC_WEBSOCKET_ACCEPT, new ArrayList<String>());
}
The browser will interpret this like server did not accepted the connection. for example in chrome I get the message
Error during Websocket handshake
I know - old thread but I don't see any improvements about this. So maybe someone can discuss my solution for this problem.
I tried leos version, running Wildfly 8.0 , Undertow 1.0
final ArrayList<String> finalEmpty = new ArrayList<String>();
response.getHeaders().put(HandshakeResponse.SEC_WEBSOCKET_ACCEPT,finalEmpty);
This will cause some funny behavior:
Even though your browser should close the connection, they will all go through the onOpen()
procedure.
onOpen()
, then triggers onError()
. In my
case, I do some logging about disconnected clients so I anways call
onClose()
when there is an error.Don't mess up your headers and don't let the client do the dity work.
Instead, you should add authentification data to Configuration.
/** some verification foo code...**/
config.getUserProperties().put("isValid",true);
in onOpen()
you then check for the value of isValid. If it isnt, you call onClose(session,null);
. and the session will be closed.
It's not the best solution but thats because websocket authentification sucks and every browser is acting different sometimes. Please see: Websocket: Closing browser triggers onError() in chrome but onClose() event in Firefox
The easiest way is to setup simple web-filter in your web.xml which will be executed before handshake.
Smth like:
public class MyHandshakeFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
// do nothing
}
/**
* Passes request to chain when request port is equal to specified in the allowedPort property
* and returns HttpServletResponse.SC_NOT_FOUND in other case.
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
if (<your validation here based on http request>) {
// request conditions are met. continue handshake...
chain.doFilter(request, response);
} else {
// request conditions are NOT met. reject handshake...
((HttpServletResponse) response).setStatus(HttpServletResponse.SC_FORBIDDEN);
}
}
}
and in web.xml:
<filter>
<filter-name>yourHandshakeFilter</filter-name>
<filter-class>com....MyHandshakeFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>yourHandshakeFilter</filter-name>
<url-pattern>/yourEndpointUrl</url-pattern>
</filter-mapping>
and your ServerEndpoint should be smth like:
@ServerEndpoint("/yourEndpointUrl")
public class MyServerEndpoint {
...
}
Another technique:
When you throw a RuntimeException from ServerEndpointConfig.Configurator#modifyHandshake
then the connection is not established.
This works in Tomcat 8. Got the idea from a Jetty example so I guess it also works in Jetty.