Skip to content

Commit

Permalink
HTTP 1 parser, CONNECT host:port fix, HTTP2 support tests
Browse files Browse the repository at this point in the history
Signed-off-by: Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com>
  • Loading branch information
jbescos committed Aug 1, 2023
1 parent 39b644b commit 2749bc2
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 84 deletions.
4 changes: 4 additions & 0 deletions nima/tests/integration/webclient/webclient/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
<groupId>io.helidon.nima.webclient</groupId>
<artifactId>helidon-nima-webclient</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.nima.http2</groupId>
<artifactId>helidon-nima-http2-webclient</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.nima.webserver</groupId>
<artifactId>helidon-nima-webserver</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.net.Socket;
import java.util.Arrays;
import java.util.Base64;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -53,7 +54,8 @@ class HttpProxy {
this(port, null, null);
}

boolean start() {
void start() {
CountDownLatch ready = new CountDownLatch(1);
executor.submit(() -> {
try (ServerSocket server = new ServerSocket(port)) {
this.connectedPort = server.getLocalPort();
Expand All @@ -62,6 +64,7 @@ boolean start() {
Socket origin = server.accept();
LOGGER.log(Level.DEBUG, "Open: " + origin);
counter.incrementAndGet();
ready.countDown();
origin.setSoTimeout(TIMEOUT);
Socket remote = new Socket();
remote.setSoTimeout(TIMEOUT);
Expand All @@ -82,9 +85,10 @@ boolean start() {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(connectedPort), 10000);
responding = true;
} catch (IOException e) {}
// Wait for counter is set to 0
ready.await(5, TimeUnit.SECONDS);
} catch (IOException | InterruptedException e) {}
}
return responding;
}

int counter() {
Expand Down Expand Up @@ -112,7 +116,6 @@ private class MiddleCommunicator {

private static final System.Logger LOGGER = System.getLogger(MiddleCommunicator.class.getName());
private static final int BUFFER_SIZE = 1024 * 1024;
private static final String HOST = "HOST: ";
private final ExecutorService executor;
private final Socket readerSocket;
private final Socket writerSocket;
Expand Down Expand Up @@ -169,7 +172,7 @@ public void run() {
if (originInfo.respondOrigin()) {
if (authenticate(originInfo)) {
// Respond origin
String response = "HTTP/1.1 200 Connection established\r\n\r\n";
String response = "HTTP/1.0 200 Connection established\r\n\r\n";
writerSocket.connect(new InetSocketAddress(originInfo.host, originInfo.port));
LOGGER.log(Level.DEBUG, "Open: " + writerSocket);
readerSocket.getOutputStream()
Expand All @@ -180,7 +183,7 @@ public void run() {
} else {
LOGGER.log(Level.WARNING, "Invalid " + originInfo.user + ":" + originInfo.password);
originInfo = null;
String response = "HTTP/1.1 401 Unauthorized\r\n\r\n";
String response = "HTTP/1.0 401 Unauthorized\r\n\r\n";
readerSocket.getOutputStream().write(response.getBytes());
readerSocket.getOutputStream().flush();
readerSocket.close();
Expand Down Expand Up @@ -222,8 +225,6 @@ private OriginInfo getOriginInfo(byte[] buffer, int read) throws MalformedURLExc
for (String line : lines) {
if (line.startsWith(OriginInfo.CONNECT)) {
request.parseFirstLine(line);
} else if (line.toUpperCase().startsWith(HOST)) {
request.parseHost(line);
} else if (line.toUpperCase().startsWith(OriginInfo.AUTHORIZATION)) {
request.parseAuthorization(line);
}
Expand Down Expand Up @@ -261,12 +262,7 @@ private void parseFirstLine(String line) {
String[] parts = line.split(" ");
this.method = parts[0].trim();
this.protocol = parts[2].trim();
}

// Host: host:port
private void parseHost(String line) {
line = line.substring(HOST.length()).trim();
String[] hostPort = line.split(":");
String[] hostPort = parts[1].split(":");
this.host = hostPort[0];
if (hostPort.length > 1) {
this.port = Integer.parseInt(hostPort[1]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@
import java.net.ProxySelector;

import io.helidon.common.http.Http;
import io.helidon.nima.http2.webclient.Http2Client;
import io.helidon.nima.testing.junit5.webserver.ServerTest;
import io.helidon.nima.testing.junit5.webserver.SetUpRoute;
import io.helidon.nima.webclient.api.HttpClient;
import io.helidon.nima.webclient.api.HttpClientResponse;
import io.helidon.nima.webclient.api.Proxy;
import io.helidon.nima.webclient.api.Proxy.ProxyType;
import io.helidon.nima.webclient.http1.Http1Client;
import io.helidon.nima.webclient.http1.Http1ClientResponse;
import io.helidon.nima.webserver.WebServer;
import io.helidon.nima.webserver.http.HttpRouting;

import org.junit.jupiter.api.AfterEach;
Expand All @@ -43,7 +46,8 @@ class HttpProxyTest {
private int proxyPort;
private HttpProxy httpProxy;

private final Http1Client client;
private final HttpClient<?> clientHttp1;
private final HttpClient<?> clientHttp2;

@SetUpRoute
static void routing(HttpRouting.Builder router) {
Expand All @@ -55,79 +59,121 @@ public void before() {
httpProxy = new HttpProxy(0);
httpProxy.start();
proxyPort = httpProxy.connectedPort();
assertThat(httpProxy.counter(), is(0));
}

@AfterEach
public void after() {
httpProxy.stop();
}

HttpProxyTest(Http1Client client) {
this.client = client;
HttpProxyTest(WebServer server) {
String uri = "http://localhost:" + server.port();
this.clientHttp1 = Http1Client.builder().baseUri(uri).build();
this.clientHttp2 = Http2Client.builder().baseUri(uri).build();
}

@Test
void testNoProxy() {
noProxyChecks();
void testNoProxy1() {
noProxyChecks(clientHttp1);
}

@Test
void testNoProxyTypeDefaultsToNone() {
noProxyChecks();
void testNoProxy2() {
noProxyChecks(clientHttp2);
}

@Test
void testNoHosts() {
Proxy proxy = Proxy.builder().host(PROXY_HOST).port(proxyPort).addNoProxy(PROXY_HOST).build();
try (Http1ClientResponse response = client.get("/get").proxy(proxy).request()) {
assertThat(response.status(), is(Http.Status.OK_200));
String entity = response.entity().as(String.class);
assertThat(entity, is("Hello"));
}
assertThat(httpProxy.counter(), is(0));
void testNoHosts1() {
noHosts(clientHttp1);
}

@Test
void testNoHosts2() {
noHosts(clientHttp2);
}

@Test
void testNoProxyTypeButHasHost() {
void testNoProxyTypeButHasHost1() {
Proxy proxy = Proxy.builder().host(PROXY_HOST).port(proxyPort).build();
successVerify(proxy);
successVerify(proxy, clientHttp1);
}

@Test
void testProxyNoneTypeButHasHost() {
void testNoProxyTypeButHasHost2() {
Proxy proxy = Proxy.builder().host(PROXY_HOST).port(proxyPort).build();
successVerify(proxy, clientHttp2);
}

@Test
void testProxyNoneTypeButHasHost1() {
Proxy proxy = Proxy.builder().type(ProxyType.NONE).host(PROXY_HOST).port(proxyPort).build();
successVerify(proxy, clientHttp1);
}

@Test
void testProxyNoneTypeButHasHost2() {
Proxy proxy = Proxy.builder().type(ProxyType.NONE).host(PROXY_HOST).port(proxyPort).build();
successVerify(proxy);
successVerify(proxy, clientHttp2);
}

@Test
void testSimpleProxy1() {
Proxy proxy = Proxy.builder().type(ProxyType.HTTP).host(PROXY_HOST).port(proxyPort).build();
successVerify(proxy, clientHttp1);
}

@Test
void testSimpleProxy() {
void testSimpleProxy2() {
Proxy proxy = Proxy.builder().type(ProxyType.HTTP).host(PROXY_HOST).port(proxyPort).build();
successVerify(proxy);
successVerify(proxy, clientHttp2);
}

@Test
void testSystemProxy1() {
ProxySelector original = ProxySelector.getDefault();
try {
ProxySelector.setDefault(ProxySelector.of(new InetSocketAddress(PROXY_HOST, proxyPort)));
Proxy proxy = Proxy.create();
successVerify(proxy, clientHttp1);
} finally {
ProxySelector.setDefault(original);
}
}

@Test
void testSystemProxy() {
void testSystemProxy2() {
ProxySelector original = ProxySelector.getDefault();
try {
ProxySelector.setDefault(ProxySelector.of(new InetSocketAddress(PROXY_HOST, proxyPort)));
Proxy proxy = Proxy.create();
successVerify(proxy);
successVerify(proxy, clientHttp2);
} finally {
ProxySelector.setDefault(original);
}
}

private void successVerify(Proxy proxy) {
try (Http1ClientResponse response = client.get("/get").proxy(proxy).request()) {
private void noHosts(HttpClient<?> client) {
Proxy proxy = Proxy.builder().host(PROXY_HOST).port(proxyPort).addNoProxy(PROXY_HOST).build();
try (HttpClientResponse response = client.get("/get").proxy(proxy).request()) {
assertThat(response.status(), is(Http.Status.OK_200));
String entity = response.entity().as(String.class);
assertThat(entity, is("Hello"));
}
assertThat(httpProxy.counter(), is(0));
}

private void successVerify(Proxy proxy, HttpClient<?> client) {
try (HttpClientResponse response = client.get("/get").proxy(proxy).request()) {
assertThat(response.status(), is(Http.Status.OK_200));
String entity = response.entity().as(String.class);
assertThat(entity, is("Hello"));
}
assertThat(httpProxy.counter(), is(1));
}

private void noProxyChecks() {
try (Http1ClientResponse response = client.get("/get").request()) {
private void noProxyChecks(HttpClient<?> client) {
try (HttpClientResponse response = client.get("/get").request()) {
assertThat(response.status(), is(Http.Status.OK_200));
String entity = response.entity().as(String.class);
assertThat(entity, is("Hello"));
Expand Down

0 comments on commit 2749bc2

Please sign in to comment.