Skip to content

Commit

Permalink
Upgrade WebSocket from Java HttpClient (#3991)
Browse files Browse the repository at this point in the history
* Upgrade request with content-length 0 now work

Signed-off-by: Tomas Langer <tomas.langer@oracle.com>
  • Loading branch information
tomas-langer committed Mar 23, 2022
1 parent dc4668e commit 85bb1cb
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
18 changes: 18 additions & 0 deletions webserver/tyrus/pom.xml
Expand Up @@ -85,6 +85,24 @@
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-testCompile</id>
<configuration>
<!--
We use HTTP client from tests, and we do not want it as a module dependency
-->
<compilerArgs>
<compilerArg>--add-modules</compilerArg>
<compilerArg>java.net.http</compilerArg>
</compilerArgs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
Expand Down
@@ -0,0 +1,85 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.helidon.webserver.tyrus;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.websocket.server.ServerEndpointConfig;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

class HttpClientTest extends TyrusSupportBaseTest {
@BeforeAll
static void startServer() throws ExecutionException, InterruptedException, TimeoutException {
ServerEndpointConfig.Builder builder = ServerEndpointConfig.Builder.create(
EchoEndpoint.class, "/");
webServer(true, builder.build());
}

@Test
void testJdkClient() throws ExecutionException, InterruptedException, TimeoutException {
URI uri = URI.create("ws://localhost:" + webServer().port() + "/tyrus/echo");
ClientListener listener = new ClientListener();

WebSocket webSocket = HttpClient.newHttpClient()
.newWebSocketBuilder()
.buildAsync(uri, listener)
.get();

webSocket.sendText("message", true);
webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "finished");

String response = listener.await();
assertThat(response, is("message"));
}

private static class ClientListener implements WebSocket.Listener {
private final CompletableFuture<String> future = new CompletableFuture<>();

@Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
future.complete(data.toString());
return CompletableFuture.completedFuture(data);
}

@Override
public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) {
future.complete(reason);
return CompletableFuture.completedFuture(reason);
}

@Override
public void onError(WebSocket webSocket, Throwable error) {
future.completeExceptionally(error);
}

public String await() throws ExecutionException, InterruptedException, TimeoutException {
return future.get(10, TimeUnit.SECONDS);
}
}
}
Expand Up @@ -367,7 +367,9 @@ private boolean channelReadHttpRequest(ChannelHandlerContext ctx, Context reques

String contentLength = request.headers().get(HttpHeaderNames.CONTENT_LENGTH);

// HTTP WebSocket client sends a content length of 0 together with Connection: Upgrade
if ("0".equals(contentLength)
&& !"upgrade".equalsIgnoreCase(request.headers().get(HttpHeaderNames.CONNECTION))
|| (contentLength == null
&& !"upgrade".equalsIgnoreCase(request.headers().get(HttpHeaderNames.CONNECTION))
&& !"chunked".equalsIgnoreCase(request.headers().get(HttpHeaderNames.TRANSFER_ENCODING))
Expand Down

0 comments on commit 85bb1cb

Please sign in to comment.