Skip to content

Commit

Permalink
Add helper method to determine if request can be upgraded to websocket.
Browse files Browse the repository at this point in the history
Vert.x Web And Vert.x HTTP Proxy have similar code.
This method covers all cases and can be reused.

Signed-off-by: Thomas Segismont <tsegismont@gmail.com>
  • Loading branch information
tsegismont committed Feb 6, 2024
1 parent 6ddadec commit 3e1096f
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 4 deletions.
20 changes: 20 additions & 0 deletions src/main/java/io/vertx/core/http/impl/HttpUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -1016,4 +1016,24 @@ public static boolean isValidHostAuthority(String host) {
int len = host.length();
return HostAndPortImpl.parseHost(host, 0, len) == len;
}

public static boolean canUpgradeToWebSocket(HttpServerRequest req) {
if (req.version() != io.vertx.core.http.HttpVersion.HTTP_1_1) {
return false;
}
if (req.method() != io.vertx.core.http.HttpMethod.GET) {
return false;
}
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)) {
for (String upgrade : headers.getAll(io.vertx.core.http.HttpHeaders.UPGRADE)) {
if (upgrade.toLowerCase().contains(io.vertx.core.http.HttpHeaders.WEBSOCKET)) {
return true;
}
}
}
}
return false;
}
}
62 changes: 58 additions & 4 deletions src/test/java/io/vertx/core/http/Http1xTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.LongConsumer;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
Expand Down Expand Up @@ -5310,4 +5307,61 @@ public void testMissingHostHeader() throws Exception {
}));
await();
}

@Test
public void testCanUpgradeToWebSocket() throws Exception {
UnaryOperator<RequestOptions> config = ro -> ro.setMethod(HttpMethod.GET)
.putHeader(HttpHeaders.CONNECTION, HttpHeaders.UPGRADE)
.putHeader(HttpHeaders.UPGRADE, HttpHeaders.WEBSOCKET);
doTestCanUpgradeToWebSocket(config, true);
}

@Test
public void testCanUpgradeToWebSocketFirefox() throws Exception {
UnaryOperator<RequestOptions> config = ro -> ro.setMethod(HttpMethod.GET)
.putHeader(HttpHeaders.CONNECTION, HttpHeaders.KEEP_ALIVE + ", " + HttpHeaders.UPGRADE)
.putHeader(HttpHeaders.UPGRADE, HttpHeaders.WEBSOCKET);
doTestCanUpgradeToWebSocket(config, true);
}

@Test
public void testCannotUpgradePostRequestToWebSocket() throws Exception {
UnaryOperator<RequestOptions> config = ro -> ro.setMethod(HttpMethod.POST)
.putHeader(HttpHeaders.CONNECTION, HttpHeaders.UPGRADE)
.putHeader(HttpHeaders.UPGRADE, HttpHeaders.WEBSOCKET);
doTestCanUpgradeToWebSocket(config, false);
}

@Test
public void testCannotUpgradeToWebSocketIfConnectionHeaderIsMissing() throws Exception {
UnaryOperator<RequestOptions> config = ro -> ro.setMethod(HttpMethod.GET)
.putHeader(HttpHeaders.UPGRADE, HttpHeaders.WEBSOCKET);
doTestCanUpgradeToWebSocket(config, false);
}

@Test
public void testCannotUpgradeToWebSocketIfUpgradeDoesNotContainWebsocket() throws Exception {
UnaryOperator<RequestOptions> config = ro -> ro.setMethod(HttpMethod.GET)
.putHeader(HttpHeaders.CONNECTION, HttpHeaders.UPGRADE)
.putHeader(HttpHeaders.UPGRADE, "foo");
doTestCanUpgradeToWebSocket(config, false);
}

private void doTestCanUpgradeToWebSocket(UnaryOperator<RequestOptions> config, boolean shouldSucceed) throws Exception {
server.requestHandler(req -> {
HttpServerResponse serverResponse = req.response();
int statusCode = HttpUtils.canUpgradeToWebSocket(req) ? 200 : 500;
serverResponse.setStatusCode(statusCode);
serverResponse.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();
}));
req.send();
}));
await();
}
}

0 comments on commit 3e1096f

Please sign in to comment.