Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-users] How to access the http headers in Endpoint.onOpen ?

As you have discovered, this isn't spelled out in the JSR356 spec.
The JSR356 spec is very simple/naive, it doesn't cover a lot of moderate to advanced concepts.

We follow the modifyHandshake and user properties as outlined in this stackoverflow answer ...


Of note, it appears that Apache Tomcat also follows this behavior.


Joakim Erdfelt / joakim@xxxxxxxxxxx

On Thu, Feb 9, 2017 at 10:07 AM, Angelo Salvade <angelo.salvade@xxxxxxxxx> wrote:
Hi

If I understand the Java API for WebSocket Spec (JSR 356) correctly,
the only way to access the http headers and the http session is by
the parameter 'HandshakeRequest request' of
ServerEndpointConfig.Configurator.modifyHandshake
with the methods HandshakeRequest.getHeaders and
HandshakeRequest.getHttpSession.

>From there, the only way to pass this data to Endpoint.onOpen seems to
be by EndpointConfig.getUserProperties
because 'EndpointConfig config' is a parameter of Endpoint.onOpen.

The problem is, that according to the documentation, EndpointConfig is
shared with all sessions and therefore this won't work.
See also https://java.net/jira/browse/WEBSOCKET_SPEC-218 and
https://java.net/jira/browse/WEBSOCKET_SPEC-235.
However, I did some testing with Undertow and Jetty.

Please have a look at the following test code:

static ServerEndpointConfig.Configurator SERVER_CONFIGURATOR = new
ServerEndpointConfig.Configurator() {
    @Override public <T> T getEndpointInstance(Class<T> endpointClass) {
        return endpointClass.cast(new Endpoint() {
            @Override public void onOpen(Session session,
EndpointConfig config) {
                System.out.printf(
                    "onOpen - config: %s, session: %s%n",

config.getUserProperties().keySet().stream().filter(k ->
k.startsWith("Header")).collect(Collectors.toSet()),

session.getUserProperties().keySet().stream().filter(k ->
k.startsWith("Header")).collect(Collectors.toSet())
                );
            }
            @Override public void onClose(Session session, CloseReason
closeReason) {
            }
            @Override public void onError(Session session, Throwable
throwable) {
            }
        });
    }
    @Override public void modifyHandshake(ServerEndpointConfig sec,
HandshakeRequest request, HandshakeResponse response) {
        sec.getUserProperties().putAll(request.getHeaders());
    }
    @Override public String getNegotiatedSubprotocol(List<String>
supported, List<String> requested) {
        return "";
    }
    @Override public List<Extension>
getNegotiatedExtensions(List<Extension> installed, List<Extension>
requested) {
        return new ArrayList<>();
    }
    @Override public boolean checkOrigin(String originHeaderValue) {
        return true;
    }
};

static void clientConnect(WebSocketContainer container) throws Exception {
    for (String header : Arrays.asList("Header1", "Header2")) {
        container.connectToServer(
            new Endpoint() {
                @Override public void onOpen(Session session,
EndpointConfig config) {
                }
            },
            ClientEndpointConfig.Builder.create().configurator(new
ClientEndpointConfig.Configurator() {
                @Override public void beforeRequest(Map<String,
List<String>> headers) {
                    headers.put(header, Collections.singletonList("foo"));
                }
            }).build(),
            URI.create("ws://localhost:" + PORT + PATH)
        );
        TimeUnit.SECONDS.sleep(1L);
    }
}

You'll find the source code in the attachments and under:
https://github.com/softappeal/yass/blob/master/java/test/ch/softappeal/yass/transport/ws/test/up/UserPropertiesTest.java
https://github.com/softappeal/yass/blob/master/java/test/ch/softappeal/yass/transport/ws/test/up/UndertowUserPropertiesTest.java
https://github.com/softappeal/yass/blob/master/java/test/ch/softappeal/yass/transport/ws/test/up/JettyUserPropertiesTest.java

These are the outputs of the tests:

UndertowUserPropertiesTest (io.undertow:undertow-websockets-jsr:1.4.8.Final)
onOpen - config: [Header1], session: [Header1]
onOpen - config: [Header1, Header2], session: [Header1, Header2]

JettyUserPropertiesTest
(org.eclipse.jetty.websocket:javax-websocket-server-impl:9.4.1.v20170120)
onOpen - config: [Header1], session: [Header1]
onOpen - config: [Header2], session: [Header2]

So the questions are:

Jetty and Undertow seem to copy EndpointConfig.getUserProperties to
Session.getUserProperties.
Is this behaviour guaranteed? Where does it say so in the spec?

Jetty seems to make a new EndpointConfig.getUserProperties for each session.
This seems NOT to be according to the spec.
This behaviour would be THE SOLUTION to my problem.

Undertow seems to share EndpointConfig.getUserProperties over all sessions.
This seems to be according to the spec.
But so it's not possible to pass the headers to Endpoint.onOpen.

So can we say the WebSocket API should behave like Jetty?

Regards,
Angelo

_______________________________________________
jetty-users mailing list
jetty-users@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/jetty-users


Back to the top