-
Notifications
You must be signed in to change notification settings - Fork 2k
Labels
BugFor general bugs on Jetty sideFor general bugs on Jetty sideSpecificationFor all industry Specifications (IETF / Servlet / etc)For all industry Specifications (IETF / Servlet / etc)
Description
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:

Metadata
Metadata
Assignees
Labels
BugFor general bugs on Jetty sideFor general bugs on Jetty sideSpecificationFor all industry Specifications (IETF / Servlet / etc)For all industry Specifications (IETF / Servlet / etc)