Skip to content

WebSocketClient attempts to use HTTP/2 on servers without SETTINGS_ENABLE_CONNECT_PROTOCOL #13375

@jacob-pro

Description

@jacob-pro

Jetty version(s)
12.0.23

Description

When a Jetty WebSocketClient has HTTP/2 enabled using HttpClientTransportDynamic it attempts to establish HTTP/2 WebSockets on servers that do not support it.

How to reproduce?

For example try connecting to wss://echo.websocket.org - this server currently supports HTTP/2 for HTML but not for WebSockets:

public class WebSocketHttp2 {

    public static class Listener implements Session.Listener {
        private volatile Session session;

        @Override
        public void onWebSocketOpen(Session session) {
            this.session = session;
            session.demand();
        }
    }

    public static void main(String[] args) throws Exception {
        ClientConnector clientConnector = new ClientConnector();
        ClientConnectionFactory.Info http1 = HttpClientConnectionFactory.HTTP11;
        ClientConnectionFactory.Info http2 = new ClientConnectionFactoryOverHTTP2.HTTP2(new HTTP2Client(clientConnector));
        HttpClient httpClient = new HttpClient(new HttpClientTransportDynamic(clientConnector, http1, http2));
        WebSocketClient client = new WebSocketClient(httpClient);
        client.start();
        client.connect(new Listener(), URI.create("wss://echo.websocket.org")).get();
    }
}

Output:

Exception in thread "main" java.util.concurrent.ExecutionException: java.io.IOException: protocol_error
	at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:396)
	at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2073)
	at org.example.WebSocketHttp2.main(WebSocketHttp2.java:35)
Caused by: java.io.IOException: protocol_error
	at org.eclipse.jetty.http2.client.transport.internal.HttpReceiverOverHTTP2.lambda$onReset$4(HttpReceiverOverHTTP2.java:242)
	at org.eclipse.jetty.util.thread.Invocable$ReadyTask.run(Invocable.java:177)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:480)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:428)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293)
	at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.produce(AdaptiveExecutionStrategy.java:195)
	at org.eclipse.jetty.http2.HTTP2Connection.produce(HTTP2Connection.java:210)
	at org.eclipse.jetty.http2.HTTP2Connection.onFillable(HTTP2Connection.java:157)

You can see with nghttp2 that this server does not advertise support:

nghttp -v https://echo.websocket.org/
[  0.087] recv SETTINGS frame <length=24, flags=0x00, stream_id=0>
          (niv=4)
          [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
          [SETTINGS_INITIAL_WINDOW_SIZE(0x04):1048576]
          [SETTINGS_MAX_FRAME_SIZE(0x05):16384]
          [SETTINGS_MAX_HEADER_LIST_SIZE(0x06):262144]

Compare to a Jetty server which does:

nghttp -v https://localhost:8443
[  0.406] recv SETTINGS frame <length=24, flags=0x00, stream_id=0>
          (niv=4)
          [SETTINGS_MAX_CONCURRENT_STREAMS(0x03):128]
          [SETTINGS_INITIAL_WINDOW_SIZE(0x04):524288]
          [SETTINGS_MAX_HEADER_LIST_SIZE(0x06):131072]
          [SETTINGS_ENABLE_CONNECT_PROTOCOL(0x08):1]

Expected Behavior

https://datatracker.ietf.org/doc/html/rfc8441#section-3

If the server does not advertise SETTINGS_ENABLE_CONNECT_PROTOCOL then the WebSocketClient should dynamically use HTTP/1.1 instead.

If a client were to use the provisions of the extended CONNECT method defined in
this document without first receiving a SETTINGS_ENABLE_CONNECT_PROTOCOL parameter, a non-supporting peer
would detect a malformed request and generate a stream error

Presumably Firefox is checking for this:

Image Image

Metadata

Metadata

Assignees

Labels

BugFor general bugs on Jetty sideSpecificationFor all industry Specifications (IETF / Servlet / etc)

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions