Skip to content

Commit

Permalink
noncompliant httpclient
Browse files Browse the repository at this point in the history
  • Loading branch information
wagyourtail committed Jul 28, 2024
1 parent 633be8f commit a632b07
Show file tree
Hide file tree
Showing 15 changed files with 1,136 additions and 47 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package xyz.wagyourtail.downgradetest;

import com.sun.net.httpserver.Filter;
import com.sun.net.httpserver.HttpServer;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Objects;
import java.util.concurrent.ForkJoinPool;

public class TestHttpClient {

public static int servermain() throws IOException, InterruptedException {
HttpServer server = HttpServer.create();
server.bind(new InetSocketAddress(0), 0);
server.setExecutor(ForkJoinPool.commonPool());
server.createContext("/", (e) -> {
e.sendResponseHeaders(200, 0);
// read body
if (!Objects.equals(e.getRequestMethod(), "GET")) {
byte[] b = e.getRequestBody().readAllBytes();
System.out.println(new String(b));
OutputStream os = e.getResponseBody();
os.write("response: ".getBytes());
os.write(b);
} else {
e.getResponseBody().write("response".getBytes());
}
e.close();
});
Thread t = new Thread(server::start);
t.setDaemon(true);
t.start();
Thread.sleep(250);
return server.getAddress().getPort();
}

public static void main(String[] args) throws IOException, InterruptedException {
int port = servermain();
System.out.println(Filter.afterHandler("test", (e) -> System.out.println("test")).description());

try (HttpClient client = HttpClient.newHttpClient()) {
HttpRequest request = HttpRequest.newBuilder()
.header("User-Agent", "JVMDG Test 1.0")
.uri(URI.create("http://localhost:" + port))
.build();

HttpResponse<String> resp = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());

HttpRequest request2 = HttpRequest.newBuilder()
.header("User-Agent", "JVMDG Test 1.0")
.uri(URI.create("http://localhost:" + port))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString("test body"))
.build();

HttpResponse<String> resp2 = client.send(request2, HttpResponse.BodyHandlers.ofString());
System.out.println(resp2.body());
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
package xyz.wagyourtail.jvmdg.j11.impl.http;

import xyz.wagyourtail.jvmdg.exc.MissingStubError;
import xyz.wagyourtail.jvmdg.j11.stub.java_net_http.J_N_H_HttpClient;
import xyz.wagyourtail.jvmdg.j11.stub.java_net_http.J_N_H_HttpHeaders;
import xyz.wagyourtail.jvmdg.j11.stub.java_net_http.J_N_H_HttpRequest;
import xyz.wagyourtail.jvmdg.j11.stub.java_net_http.J_N_H_HttpResponse;
import xyz.wagyourtail.jvmdg.util.Utils;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Authenticator;
import java.net.CookieHandler;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.ProxySelector;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Flow;
import java.util.concurrent.ForkJoinPool;


public class HttpClientImpl extends J_N_H_HttpClient {
Expand Down Expand Up @@ -90,17 +102,119 @@ public Optional<Executor> executor() {

@Override
public <T> J_N_H_HttpResponse<T> send(J_N_H_HttpRequest var1, J_N_H_HttpResponse.BodyHandler<T> handler) throws IOException, InterruptedException {
throw MissingStubError.create();
return sendImpl(var1, handler, null);
}

protected <T> J_N_H_HttpResponse<T> sendImpl(J_N_H_HttpRequest var1, J_N_H_HttpResponse.BodyHandler<T> handler, J_N_H_HttpResponse.PushPromiseHandler<T> pushPromiseHandler) throws IOException, InterruptedException {
HttpURLConnection connection;
Objects.requireNonNull(var1);
Objects.requireNonNull(handler);

if (var1.method().equals("CONNECT")) {
throw new IllegalArgumentException("Unsupported method CONNECT");
}

if (proxy != null) {
Proxy p = proxy.select(var1.uri()).stream().findFirst().orElse(Proxy.NO_PROXY);
connection = (HttpURLConnection) var1.uri().toURL().openConnection(p);
} else {
connection = (HttpURLConnection) var1.uri().toURL().openConnection();
}

connection.setRequestMethod(var1.method());
connection.setInstanceFollowRedirects(followRedirects != Redirect.NEVER);
if (connectTimeout != null) {
connection.setConnectTimeout((int) connectTimeout.toMillis());
}
var1.timeout().ifPresent(t -> connection.setReadTimeout((int) t.toMillis()));
connection.setDoOutput(var1.bodyPublisher().isPresent());
connection.setDoInput(handler != J_N_H_HttpResponse.BodyHandlers.discarding());
connection.setAllowUserInteraction(false);

HttpRequestImpl request = (HttpRequestImpl) var1;

request.headers.forEach((k, v) -> connection.setRequestProperty(k, String.join(",", v)));

J_N_H_HttpRequest.BodyPublisher publisher = request.publisher;

if (connection instanceof HttpsURLConnection) {
HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
if (sslContext != null) {
httpsConnection.setSSLSocketFactory(sslContext.getSocketFactory());
}
}

connection.connect();

if (publisher != null) {
OutputStream out = connection.getOutputStream();
publisher.subscribe(new Flow.Subscriber<>() {


@Override
public void onSubscribe(Flow.Subscription subscription) {
subscription.request(Long.MAX_VALUE);
}

@Override
public void onNext(ByteBuffer item) {
try {
out.write(item.array());
} catch (IOException e) {
Utils.sneakyThrow(e);
}
}

@Override
public void onError(Throwable throwable) {
try {
out.close();
} catch (IOException e) {
e.addSuppressed(throwable);
Utils.sneakyThrow(e);
}
Utils.sneakyThrow(throwable);
}

@Override
public void onComplete() {
try {
out.close();
} catch (IOException e) {
Utils.sneakyThrow(e);
}
}

});
}

int responseCode = connection.getResponseCode();
Map<String, List<String>> headers = connection.getHeaderFields();
Version version = J_N_H_HttpClient.Version.HTTP_1_1;
HttpResponseInfo info = new HttpResponseInfo(responseCode, new J_N_H_HttpHeaders(headers), version);
J_N_H_HttpResponse.BodySubscriber<T> subscriber = handler.apply(info);
subscriber.onNext(List.of(ByteBuffer.wrap(connection.getInputStream().readAllBytes())));
subscriber.onComplete();
T body = subscriber.getBody().toCompletableFuture().join();

return new HttpResponseImpl<>(var1, info, body, null);
}

@Override
public <T> CompletableFuture<J_N_H_HttpResponse<T>> sendAsync(J_N_H_HttpRequest var1, J_N_H_HttpResponse.BodyHandler<T> handler) {
throw MissingStubError.create();
return sendAsync(var1, handler, null);
}

@Override
public <T> CompletableFuture<J_N_H_HttpResponse<T>> sendAsync(J_N_H_HttpRequest var1, J_N_H_HttpResponse.BodyHandler<T> handler, J_N_H_HttpResponse.PushPromiseHandler<T> pushPromiseHandler) {
throw MissingStubError.create();
return CompletableFuture.supplyAsync(() -> {
try {
return sendImpl(var1, handler, pushPromiseHandler);
} catch (IOException | InterruptedException e) {
Utils.sneakyThrow(e);
}
return null;
}, executor == null ? ForkJoinPool.commonPool() : executor);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package xyz.wagyourtail.jvmdg.j11.impl.http;

import xyz.wagyourtail.jvmdg.j11.stub.java_net_http.J_N_H_HttpClient;
import xyz.wagyourtail.jvmdg.j11.stub.java_net_http.J_N_H_HttpRequest;

import java.net.URI;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class HttpRequestBuilderImpl implements J_N_H_HttpRequest.Builder {
URI uri;
boolean expectContinue = false;
J_N_H_HttpClient.Version version;
Map<String, List<String>> headers = new HashMap<>();
Duration timeout;
String method = "GET";
J_N_H_HttpRequest.BodyPublisher publisher;

@Override
public J_N_H_HttpRequest.Builder uri(URI uri) {
this.uri = uri;
return this;
}

@Override
public J_N_H_HttpRequest.Builder expectContinue(boolean expectContinue) {
this.expectContinue = expectContinue;
return this;
}

@Override
public J_N_H_HttpRequest.Builder version(J_N_H_HttpClient.Version version) {
this.version = version;
return this;
}

@Override
public J_N_H_HttpRequest.Builder header(String name, String value) {
if (!headers.containsKey(name)) {
headers.put(name, new ArrayList<>(List.of(value)));
} else {
headers.get(name).add(value);
}
return this;
}

@Override
public J_N_H_HttpRequest.Builder headers(String... headers) {
for (int i = 0; i < headers.length; i += 2) {
header(headers[i], headers[i + 1]);
}
return this;
}

@Override
public J_N_H_HttpRequest.Builder timeout(Duration duration) {
this.timeout = duration;
return this;
}

@Override
public J_N_H_HttpRequest.Builder setHeader(String name, String value) {
headers.put(name, new ArrayList<>(List.of(value)));
return this;
}

@Override
public J_N_H_HttpRequest.Builder GET() {
return method("GET", null);
}

@Override
public J_N_H_HttpRequest.Builder POST(J_N_H_HttpRequest.BodyPublisher publisher) {
return method("POST", publisher);
}

@Override
public J_N_H_HttpRequest.Builder PUT(J_N_H_HttpRequest.BodyPublisher publisher) {
return method("PUT", publisher);
}

@Override
public J_N_H_HttpRequest.Builder DELETE() {
return method("DELETE", null);
}

@Override
public J_N_H_HttpRequest.Builder method(String name, J_N_H_HttpRequest.BodyPublisher publisher) {
this.method = name;
this.publisher = publisher;
return this;
}

@Override
public J_N_H_HttpRequest build() {
return new HttpRequestImpl(this);
}

@Override
public J_N_H_HttpRequest.Builder copy() {
HttpRequestBuilderImpl copy = new HttpRequestBuilderImpl();
copy.uri = uri;
copy.expectContinue = expectContinue;
copy.version = version;
// deep copy headers
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
copy.headers.put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
copy.timeout = timeout;
copy.method = method;
copy.publisher = publisher;
return copy;
}
}
Loading

0 comments on commit a632b07

Please sign in to comment.