2

Im trying to connect to a commetd server via websocket client. I used exactly the code from an official cometd demo on github without modifications and try to connect to http://localhost:8080/cometd/test

.. but as soon as my client tries to do the websocket upgrade http request I get a response with "HTTP/1.1 400 Unknown Bayeux Transport" Any ideas?

I tried it with SSL and without it, the latter obviosly to reduce potential error sources. In both cases I get the same error.

Here is my pom, in case I forgot some important websocket related dependencies

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>de.verlinkied</groupId>
    <artifactId>bayeux-server</artifactId>
    <version>1.0</version>


    <properties>
        <jetty.version>9.2.22.v20170606</jetty.version>
        <cometd.version>3.1.3</cometd.version>
        <slf4j.version>1.7.25</slf4j.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>websocket-api</artifactId>
            <version>${jetty.version}</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>${jetty.version}</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>${jetty.version}</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-jmx</artifactId>
            <version>${jetty.version}</version>
        </dependency>


        <dependency>
            <groupId>org.eclipse.jetty.websocket</groupId>
            <artifactId>javax-websocket-server-impl</artifactId>
            <version>${jetty.version}</version>
        </dependency>

        <dependency>
            <groupId>org.cometd.java</groupId>
            <artifactId>cometd-java-server</artifactId>
            <version>${cometd.version}</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <configuration>
                    <mainClass>de.verlinked.BayeuxServerTest</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

mvn dependency:tree yields the following

[INFO] ------------------------------------------------------------------------
[INFO] Building bayeux-server 1.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ bayeux-server ---
[INFO] de.verlinkied:bayeux-server:jar:1.0
[INFO] +- org.eclipse.jetty.websocket:websocket-api:jar:9.2.22.v20170606:compile
[INFO] +- org.eclipse.jetty:jetty-server:jar:9.2.22.v20170606:compile
[INFO] |  +- javax.servlet:javax.servlet-api:jar:3.1.0:compile
[INFO] |  +- org.eclipse.jetty:jetty-http:jar:9.2.22.v20170606:compile
[INFO] |  \- org.eclipse.jetty:jetty-io:jar:9.2.22.v20170606:compile
[INFO] +- org.eclipse.jetty:jetty-servlet:jar:9.2.22.v20170606:compile
[INFO] |  \- org.eclipse.jetty:jetty-security:jar:9.2.22.v20170606:compile
[INFO] +- org.eclipse.jetty:jetty-jmx:jar:9.2.22.v20170606:compile
[INFO] |  \- org.eclipse.jetty:jetty-util:jar:9.2.22.v20170606:compile
[INFO] +- org.eclipse.jetty.websocket:javax-websocket-server-impl:jar:9.2.22.v20170606:compile
[INFO] |  +- org.eclipse.jetty:jetty-annotations:jar:9.2.22.v20170606:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-plus:jar:9.2.22.v20170606:compile
[INFO] |  |  |  \- org.eclipse.jetty:jetty-jndi:jar:9.2.22.v20170606:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-webapp:jar:9.2.22.v20170606:compile
[INFO] |  |  |  \- org.eclipse.jetty:jetty-xml:jar:9.2.22.v20170606:compile
[INFO] |  |  +- javax.annotation:javax.annotation-api:jar:1.2:compile
[INFO] |  |  +- org.ow2.asm:asm:jar:5.0.1:compile
[INFO] |  |  \- org.ow2.asm:asm-commons:jar:5.0.1:compile
[INFO] |  |     \- org.ow2.asm:asm-tree:jar:5.0.1:compile
[INFO] |  +- org.eclipse.jetty.websocket:javax-websocket-client-impl:jar:9.2.22.v20170606:compile
[INFO] |  |  \- org.eclipse.jetty.websocket:websocket-client:jar:9.2.22.v20170606:compile
[INFO] |  +- org.eclipse.jetty.websocket:websocket-server:jar:9.2.22.v20170606:compile
[INFO] |  |  +- org.eclipse.jetty.websocket:websocket-common:jar:9.2.22.v20170606:compile
[INFO] |  |  \- org.eclipse.jetty.websocket:websocket-servlet:jar:9.2.22.v20170606:compile
[INFO] |  \- javax.websocket:javax.websocket-api:jar:1.0:compile
[INFO] +- org.cometd.java:cometd-java-server:jar:3.1.3:compile
[INFO] |  +- org.cometd.java:bayeux-api:jar:3.1.3:compile
[INFO] |  \- org.cometd.java:cometd-java-common:jar:3.1.3:compile
[INFO] |     \- org.eclipse.jetty:jetty-util-ajax:jar:9.2.22.v20170606:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.7.25:compile
[INFO] \- org.slf4j:slf4j-log4j12:jar:1.7.25:compile
[INFO]    \- log4j:log4j:jar:1.2.17:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

The jetty log shows the following

3411 [qtp1080615555-20] DEBUG org.eclipse.jetty.server.HttpChannel  - HttpChannelOverHttp@31f5a8ff{r=1,c=false,a=IDLE,uri=/cometd/test} messageComplete
3411 [qtp1080615555-20] DEBUG org.eclipse.jetty.server.HttpInput  - HttpInputOverHTTP@6f0992d0 EOF
3411 [qtp1080615555-20] DEBUG org.eclipse.jetty.server.HttpChannel  - HttpChannelOverHttp@31f5a8ff{r=1,c=false,a=IDLE,uri=/cometd/test} handle enter
3412 [qtp1080615555-20 - /cometd/test] DEBUG org.eclipse.jetty.server.HttpChannelState  - HttpChannelState@738a2171{s=IDLE i=true a=null} handling IDLE
3412 [qtp1080615555-20 - /cometd/test] DEBUG org.eclipse.jetty.server.HttpChannel  - HttpChannelOverHttp@31f5a8ff{r=1,c=false,a=DISPATCHED,uri=/cometd/test} action REQUEST_DISPATCH
3412 [qtp1080615555-20 - /cometd/test] DEBUG org.eclipse.jetty.server.Server  - REQUEST GET /cometd/test on HttpChannelOverHttp@31f5a8ff{r=1,c=false,a=DISPATCHED,uri=/cometd/test}
3412 [qtp1080615555-20 - /cometd/test] DEBUG org.eclipse.jetty.server.handler.ContextHandler  - scope null||/cometd/test @ o.e.j.s.ServletContextHandler@35fdf572{/,null,AVAILABLE}
3413 [qtp1080615555-20 - /cometd/test] DEBUG org.eclipse.jetty.server.handler.ContextHandler  - context=||/cometd/test @ o.e.j.s.ServletContextHandler@35fdf572{/,null,AVAILABLE}
3413 [qtp1080615555-20 - /cometd/test] DEBUG org.eclipse.jetty.servlet.ServletHandler  - servlet |/cometd|/test -> org.cometd.server.CometDServlet-629a2d4a@4553b89a==org.cometd.server.CometDServlet,1,true
3413 [qtp1080615555-20 - /cometd/test] DEBUG org.eclipse.jetty.servlet.ServletHandler  - chain=Jetty_WebSocketUpgradeFilter->org.cometd.server.CometDServlet-629a2d4a@4553b89a==org.cometd.server.CometDServlet,1,true
3414 [qtp1080615555-20 - /cometd/test] DEBUG org.eclipse.jetty.servlet.ServletHandler  - call filter Jetty_WebSocketUpgradeFilter
3416 [qtp1080615555-20 - /cometd/test] DEBUG org.eclipse.jetty.servlet.ServletHandler  - call servlet org.cometd.server.CometDServlet-629a2d4a@4553b89a==org.cometd.server.CometDServlet,1,true
3418 [qtp1080615555-20 - /cometd/test] DEBUG org.eclipse.jetty.server.HttpConnection  - org.eclipse.jetty.server.HttpConnection$SendCallback@62e6f50[PROCESSING][i=ResponseInfo{HTTP/1.1 400 Unknown Bayeux Transport,304,false},cb=org.eclipse.jetty.server.HttpChannel$CommitCallback@6892f8b1] generate: NEED_HEADER (null,[p=0,l=304,c=2048,r=304],true)@START

Where you can see that some Jetty_WebSocketUpgradeFilter is called, which makes me think that the websocket dependency is present but still something goes wrong.

Magnus Lutz
  • 558
  • 3
  • 12
  • What server are you deploying your web app to ? I ask because you are using the Jetty specific WebSocket CometD bindings, which require Jetty as a server. Please specify also the exact server version. – sbordet Jan 03 '18 at 14:46
  • the example in the provided link uses embedded jetty, the version is 9.2.23.v20171218 as noted in the pom's properties – Magnus Lutz Jan 03 '18 at 15:02

2 Answers2

4

Jetty offers 2 different WebSocket flavors, the standard JSR 356 one and a Jetty specific one.

The first is indicated in Maven artifacts with javax in the artifact name, while the second is indicated with jetty in the artifact name.

From your POM above you are using cometd-java-websocket-jetty-server, which is the CometD binding to the jetty WebSocket flavor.

However, you are explicitly specifying as a dependency the javax-websocket-server-impl artifact, which is the JSR 356 javax flavor.

I am guessing that if you make the dependencies consistent, that is depend on the javax flavor only or the jetty flavor only will solve your issue.

Unless you need to use the Jetty specific features, I would recommend that you use the JSR 356 javax flavor for both the CometD binding (org.cometd.java:cometd-java-websocket-javax-server) and the Jetty dependency (org.eclipse.jetty.websocket:javax-websocket-server-impl).

sbordet
  • 16,856
  • 1
  • 50
  • 45
  • I tried using only javax-websocket-server-impl, also adjusted my question showing the mvn dependency:tree. Still no luck though – Magnus Lutz Jan 04 '18 at 09:32
  • You never showed your embedded code, so please make sure that your code resembles what present in [this section](https://docs.cometd.org/current/reference/#_installation_jetty_embedded) of the CometD documentation, in particular the call to `WebSocketServerContainerInitializer` to initialize WebSocket. – sbordet Jan 04 '18 at 14:32
  • Its the exact code from this [link](https://github.com/cometd/cometd/blob/master/cometd-demo/src/test/java/org/cometd/demo/Demo.java), as mentioned in the question which the section you provided even refers too – Magnus Lutz Jan 04 '18 at 14:37
  • So the code is taken from an actual test and therefore it runs properly. What is different from your configuration and the CometD demo ? – sbordet Jan 04 '18 at 14:59
  • thats exactly what im trying to find out! I hoped that the dependencies differ in some way and espacially that something websocket related is missing but it seems not, eh? – Magnus Lutz Jan 04 '18 at 15:09
  • If you get the "unknown transport" error, it means that the HTTP request that upgrades to WebSocket is not intercepted by the `WebSocketUpgradeFilter` that is installed by Jetty under the covers (if `WebSocketServerContainerInitializer` is called properly). So two things: 1) call server.dumpStdErr() after you started the server, it should show if the filter is there; 2) take a network dump to see if the WebSocket upgrade request is legit. – sbordet Jan 04 '18 at 18:31
  • thats what i thought in the first place, but the log says "call filter Jetty_WebSocketUpgradeFilter" – Magnus Lutz Jan 08 '18 at 09:26
  • The log also shows that after the `WebSocketUpgradeFilter` the `CometDServlet` is called, which means that for some reason the WebSocket upgrade was not good, and the filter just forwarded the request. You need to enable the DEBUG level for the `WebSocketUpgradeFilter` to see more about what the filter does, or just debug it. – sbordet Jan 08 '18 at 14:33
  • I alrady have only one log4j rootLogger which is set to debug and which seems to be used by jetty and cometd. Im not sure if I can get more logging out of it – Magnus Lutz Jan 08 '18 at 15:36
1

I had the exact same issue. I tried to track this down. It seems to me that this is caused by the way the bayeux server initializes the websocket transport mappings from the ws.cometdURLMapping property. Either that, or I'm using a wrong value of ws.cometdURLMapping.

Assuming the websockets dependencies are configured correctly, so using jsr 356, websocket upgrade requests go through Jetty WebSocketUpgradeFilter.doFilter(). This method verifies that the request is a legitimate websockets upgrade request and that the one of its mappings matches the websocket request path.

This is where things fail for me. There is never a successful match.

I have configured ws.cometdURLMapping to /cometd/*. I expected this to mean that any websocket request for /cometd/<whatever/here> would be accepted.

This is not happening because AbstractWebSocketTransport.normalizeURLMapping() transforms /cometd/* into /cometd which AFAICS is interpreted by the Jetty websocket code as a regular expression. Here's the bit of Comet code I'm referring to:

protected List<String> normalizeURLMapping(String urlMapping) {
    String[] mappings = urlMapping.split(",");
    List<String> result = new ArrayList<>(mappings.length);
    for (String mapping : mappings) {
        if (mapping.endsWith("/*")) {
            mapping = mapping.substring(0, mapping.length() - 2);
        }
        if (!mapping.startsWith("/")) {
            mapping = "/" + mapping;
        }
        result.add(mapping);
    }
    return result;
}

The regular expression ^/cometd$ certainly does not match my websocket request path which is /cometd/, or /cometd/something-here, so the websocket upgrade filter is bypassed.

I haven't tracked down what happens after this, but I assume that since no transport is marked as available, the comet server just bails out with a HTTP 400 Unknown Bayeux transport.

Cosimo
  • 2,846
  • 1
  • 24
  • 26