Why does Jetty JSR356 behave differently with regards to checkOrigin and modifyHandshake

Azeq

I was playing around with Jetty (9.2.3v20140905) by connecting a web socket endpoint where I tried to use my own ServerEndpointConfig when I came across Jetty's code to see how it was used. I notice that it is used in JsrCreator when a web socket object is created:

Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp){
 ...
 // modify handshake
 configurator.modifyHandshake(config,hsreq,hsresp);
 ...
}

I read the javadoc of modifyHandshake of ServerEndpointConfig (javax.websocket-api 1.0) that states:

Called by the container after it has formulated a handshake response resulting from a well-formed handshake request. The container has already checked that this configuration has a matching URI, determined the validity of the origin using the checkOrigin method, and filled out the negotiated subprotocols and extensions based on this configuration. Custom configurations may override this method in order to inspect the request parameters and modify the handshake response that the server has formulated. and the URI checking also. If the developer does not override this method, no further modification of the request and response are made by the implementation.

Here's what Jetty does:

Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp){
 ...
 // modify handshake
 configurator.modifyHandshake(config,hsreq,hsresp);

 // check origin
 if (!configurator.checkOrigin(req.getOrigin())){...}
 ...
 resp.setAcceptedSubProtocol(subprotocol);
 ...
 resp.setExtensions(configs);
}

As you can see, the origin is checked after the configurator as been called. The response is modified after the configurator as been called. The method acceptWebSocket of WebSocketServerFactory makes a call to the WebSocketCreator:

Object websocketPojo = creator.createWebSocket(sockreq, sockresp);

And after that calls:

private boolean upgrade(HttpConnection http, ServletUpgradeRequest request, ServletUpgradeResponse response, EventDriver driver)

which also modifies the response via HandshakeRFC6455:

 // build response
 response.setHeader("Upgrade","WebSocket");
 response.addHeader("Connection","Upgrade");
 response.addHeader("Sec-WebSocket-Accept",AcceptHash.hashKey(key));

So I have no way modifying the response only with my configurator because Jetty will change it anyway.

It seems to me Jetty does not comply with JSR 356, the Java API for WebSocket, does it?

Joakim Erdfelt

Ah, one of the many ambiguous and ill defined parts of the JSR-356 spec.

You might want to read the open bugs against the spec.

There are many real world examples of scenarios that are rendered impossible if the original 1.x spec is follow exactly.

Now, to tackle the specific details of your question:

Why is checkOrigin called after modifyHandshake in the Jetty implementation?

This is because there are valid scenarios (esp with CDI and Spring) where the information needed by a checkOrigin implementation by the end user is not valid, or exists, until the modifyHandshake call is called.

Basically, the endpoint Configurator is created, the modifyHandshake is called, and at that point, all of the library integration (CDI, Spring, etc.) starts, that's when the endpoint enters the WebSocket (RFC6455) CONNECTING state. (once the endpoint's onOpen is called, then the WebSocket RFC6455 state goes to the OPEN state)

As you have probably noticed, there's no definitions in the spec of the scopes and lifetimes of objects when CDI (or Spring) is involved.

The 1.x JSR356 spec actually distances itself from servlet container specific behavior, it was done to make the spec as generic as possible, with the ability to have non-servlet websocket server containers too. Unfortunately, that also means that there are many use cases in a servlet container that doesn't mesh with the 1.x JSR356 spec.

Once the JSR356 spec is updated to properly define the CDI scopes on WebSocket, then this quirk of checkOrigin after modifyHandshake can be fixed.

Why is the implementation modifying the response after modifyHandshake?

The implementation has to modify the response, otherwise the response is invalid for HTTP/1.1 upgrade, the need of the implementation to cooperate with the endpoint and its configuration, for sub protocols, and extensions makes this a reality. (Notice that the the JSR356 spec punts on Extensions?)

This is also an area that is promised to be corrected in the next JSR356 revision.

The current work on the WebSocket over HTTP/2 spec makes this even more interesting, as it isn't (currently) using the HTTP/1.1 upgrade semantic. It just comes into existence with a handshake only (no Upgrade, no Origin, etc).

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Why does F# Interactive behave differently than compiler with regards to immutable value definition?

From Dev

Why does F# Interactive behave differently than compiler with regards to immutable value definition?

From Dev

Enable JSR356 with jetty-runner

From Dev

Why does strptime() behave differently on OSX and on Linux?

From Dev

Why does this array initialize behave differently?

From Dev

Why does this constraint behave differently on different simulators?

From Dev

Why does this contextmanager behave differently with dict comprehensions?

From Dev

Why does FINDSTR behave differently in powershell and cmd?

From Dev

Why does EOF behave differently in fgets and read

From Dev

Why does the complement behave differently through printf?

From Dev

Why does "last" behave differently in Perl in these examples?

From Dev

Why does this code behave differently in NodeJS?

From Dev

Why does "grep" behave differently in this example?

From Dev

Why does this array initialize behave differently?

From Dev

Why does this contextmanager behave differently with dict comprehensions?

From Dev

Why does `==` behave differently inside `[ ... ]` in zsh and bash?

From Dev

Why does strptime() behave differently on OSX and on Linux?

From Dev

Why does /* */ comment behave differently ? Javascript bug?

From Dev

Why does "last" behave differently in Perl in these examples?

From Dev

Why does jQuery behave differently than javascript?

From Dev

Why does to_sym behave differently?

From Dev

Why does ghci behave differently to runHaskell?

From Dev

Why does SetSystemTime() behave differently in the Afternoons?

From Dev

Why does "include" behave differently in the global context than it does in a class?

From Dev

Why does "include" behave differently in the global context than it does in a class?

From Java

Why does R behave differently when parsing parameters of plotting?

From Dev

Why does the last list item behave differently in customized list?

From Dev

Why does the null-conditional operator behave differently for == and .Equals()?

From Dev

Why does sum(DF) behave differently from DF.sum()?

Related Related

  1. 1

    Why does F# Interactive behave differently than compiler with regards to immutable value definition?

  2. 2

    Why does F# Interactive behave differently than compiler with regards to immutable value definition?

  3. 3

    Enable JSR356 with jetty-runner

  4. 4

    Why does strptime() behave differently on OSX and on Linux?

  5. 5

    Why does this array initialize behave differently?

  6. 6

    Why does this constraint behave differently on different simulators?

  7. 7

    Why does this contextmanager behave differently with dict comprehensions?

  8. 8

    Why does FINDSTR behave differently in powershell and cmd?

  9. 9

    Why does EOF behave differently in fgets and read

  10. 10

    Why does the complement behave differently through printf?

  11. 11

    Why does "last" behave differently in Perl in these examples?

  12. 12

    Why does this code behave differently in NodeJS?

  13. 13

    Why does "grep" behave differently in this example?

  14. 14

    Why does this array initialize behave differently?

  15. 15

    Why does this contextmanager behave differently with dict comprehensions?

  16. 16

    Why does `==` behave differently inside `[ ... ]` in zsh and bash?

  17. 17

    Why does strptime() behave differently on OSX and on Linux?

  18. 18

    Why does /* */ comment behave differently ? Javascript bug?

  19. 19

    Why does "last" behave differently in Perl in these examples?

  20. 20

    Why does jQuery behave differently than javascript?

  21. 21

    Why does to_sym behave differently?

  22. 22

    Why does ghci behave differently to runHaskell?

  23. 23

    Why does SetSystemTime() behave differently in the Afternoons?

  24. 24

    Why does "include" behave differently in the global context than it does in a class?

  25. 25

    Why does "include" behave differently in the global context than it does in a class?

  26. 26

    Why does R behave differently when parsing parameters of plotting?

  27. 27

    Why does the last list item behave differently in customized list?

  28. 28

    Why does the null-conditional operator behave differently for == and .Equals()?

  29. 29

    Why does sum(DF) behave differently from DF.sum()?

HotTag

Archive