[undertow-dev] How to access the http headers in Endpoint.onOpen ?
Angelo Salvade
angelo.salvade at gmail.com
Fri Feb 10 02:10:01 EST 2017
Hi Stuart
Thanks for the answer.
Just to be sure:
Does it mean you agree with my assumption, that according to the spec,
it won't be possible to pass headers safely (due to multi-threading)
to Endpoint.onOpen?
FYI:
I also posted this issue to the mailing list jetty-users.
They are telling Tomcat also seems to implement the Jetty behavior.
This is against the spec but would be a more useful implementation and
it would solve the problem.
Please see http://dev.eclipse.org/mhonarc/lists/jetty-users/msg07615.html
Regards,
Angelo
On Thu, Feb 9, 2017 at 10:55 PM, Stuart Douglas <sdouglas at redhat.com> wrote:
> I think you will need to take this up with the Websocket EG, I think
> Undertow follows the spec as it is currently implemented, so I don't
> really want to change it.
>
> Stuart
>
> On Fri, Feb 10, 2017 at 4:09 AM, Angelo Salvade
> <angelo.salvade at gmail.com> 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
>>
>> _______________________________________________
>> undertow-dev mailing list
>> undertow-dev at lists.jboss.org
>> https://lists.jboss.org/mailman/listinfo/undertow-dev
More information about the undertow-dev
mailing list