diff --git a/src/main/java/io/vertx/core/http/impl/HttpUtils.java b/src/main/java/io/vertx/core/http/impl/HttpUtils.java index 259f961c6ec..f147e875476 100644 --- a/src/main/java/io/vertx/core/http/impl/HttpUtils.java +++ b/src/main/java/io/vertx/core/http/impl/HttpUtils.java @@ -1008,7 +1008,19 @@ static void resolveFile(VertxInternal vertx, String filename, long offset, long } static boolean isConnectOrUpgrade(io.vertx.core.http.HttpMethod method, MultiMap headers) { - return method == io.vertx.core.http.HttpMethod.CONNECT || (method == io.vertx.core.http.HttpMethod.GET && headers.contains(io.vertx.core.http.HttpHeaders.CONNECTION, io.vertx.core.http.HttpHeaders.UPGRADE, true)); + if (method == io.vertx.core.http.HttpMethod.CONNECT) { + return true; + } + if (method == io.vertx.core.http.HttpMethod.GET) { + for (String connection : headers.getAll(io.vertx.core.http.HttpHeaders.CONNECTION)) { + // Firefox doesn't send a normal 'Connection: Upgrade' header for WebSockets. + // Instead, it sends: 'Connection: keep-alive, Upgrade'. + if (AsciiString.containsIgnoreCase(connection, io.vertx.core.http.HttpHeaders.UPGRADE)) { + return true; + } + } + } + return false; } static boolean isKeepAlive(HttpRequest request) { @@ -1031,9 +1043,9 @@ public static boolean canUpgradeToWebSocket(HttpServerRequest req) { } MultiMap headers = req.headers(); for (String connection : headers.getAll(io.vertx.core.http.HttpHeaders.CONNECTION)) { - if (connection.toLowerCase().contains(io.vertx.core.http.HttpHeaders.UPGRADE)) { + if (AsciiString.containsIgnoreCase(connection, io.vertx.core.http.HttpHeaders.UPGRADE)) { for (String upgrade : headers.getAll(io.vertx.core.http.HttpHeaders.UPGRADE)) { - if (upgrade.toLowerCase().contains(io.vertx.core.http.HttpHeaders.WEBSOCKET)) { + if (AsciiString.containsIgnoreCase(upgrade, io.vertx.core.http.HttpHeaders.WEBSOCKET)) { return true; } } diff --git a/src/test/java/io/vertx/core/http/Http1xTest.java b/src/test/java/io/vertx/core/http/Http1xTest.java index 5fa5b261c03..212648ed0e8 100644 --- a/src/test/java/io/vertx/core/http/Http1xTest.java +++ b/src/test/java/io/vertx/core/http/Http1xTest.java @@ -25,7 +25,6 @@ import io.vertx.core.impl.ContextInternal; import io.vertx.core.impl.Utils; import io.vertx.core.impl.VertxInternal; -import io.vertx.core.impl.transports.JDKTransport; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; import io.vertx.core.net.*; @@ -5351,16 +5350,31 @@ public void testCannotUpgradeToWebSocketIfUpgradeDoesNotContainWebsocket() throw private void doTestCanUpgradeToWebSocket(UnaryOperator config, boolean shouldSucceed) throws Exception { server.requestHandler(req -> { - HttpServerResponse serverResponse = req.response(); - int statusCode = HttpUtils.canUpgradeToWebSocket(req) ? 200 : 500; - serverResponse.setStatusCode(statusCode); - serverResponse.end(); + HttpServerResponse resp = req.response(); + if (HttpUtils.canUpgradeToWebSocket(req)) { + resp.headers() + .set(HttpHeaders.CONNECTION, HttpHeaders.UPGRADE) + .set(HttpHeaders.UPGRADE, HttpHeaders.WEBSOCKET); + req.toNetSocket().onComplete(onSuccess(sock -> { + sock.write(Buffer.buffer("foo")); + })); + } else { + resp.setStatusCode(500).end(); + } }); startServer(testAddress); client.request(config.apply(new RequestOptions(requestOptions))).onComplete(onSuccess(req -> { req.response().onComplete(onSuccess(resp -> { - assertEquals(shouldSucceed ? 200 : 500, resp.statusCode()); - testComplete(); + if (shouldSucceed) { + assertEquals(101, resp.statusCode()); + resp.netSocket().handler(buffer -> { + assertEquals("foo", buffer.toString()); + testComplete(); + }); + } else { + assertEquals(500, resp.statusCode()); + testComplete(); + } })); req.send(); }));