Skip to content

Commit

Permalink
[java] JDK Http client - avoid chunking without buffering to memory (#…
Browse files Browse the repository at this point in the history
…11198)

avoid chunking without buffering to memory

Reduce the memory consumption especially while creating a new session.
  • Loading branch information
joerg1985 authored Oct 31, 2022
1 parent f569d7f commit e0ade5c
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 5 deletions.
6 changes: 4 additions & 2 deletions java/src/org/openqa/selenium/remote/ProtocolHandshake.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,7 @@ public Either<SessionNotCreatedException, Result> createSession(HttpHandler clie
Writer writer = new OutputStreamWriter(counter, UTF_8)) {
payload.writeTo(writer);

try (InputStream rawIn = os.asByteSource().openBufferedStream();
BufferedInputStream contentStream = new BufferedInputStream(rawIn)) {
try (InputStream contentStream = os.asByteSource().openBufferedStream()) {
return createSession(client, contentStream, counter.getCount());
}
} finally {
Expand All @@ -113,6 +112,9 @@ private Either<SessionNotCreatedException, Result> createSession(HttpHandler cli
HttpResponse response;
long start = System.currentTimeMillis();

// Setting the CONTENT_LENGTH will allow a http client implementation not to read the data in
// memory. Usually the payload is small and buffering it to memory is okay, except for a new
// session e.g. with profiles.
request.setHeader(CONTENT_LENGTH, String.valueOf(size));
request.setHeader(CONTENT_TYPE, JSON_UTF_8);
request.setContent(() -> newSessionBlob);
Expand Down
27 changes: 24 additions & 3 deletions java/src/org/openqa/selenium/remote/http/jdk/JdkHttpMessages.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpRequest.BodyPublisher;
import java.net.http.HttpRequest.BodyPublishers;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -72,12 +73,11 @@ public java.net.http.HttpRequest createRequest(HttpRequest req) {
break;

case POST:
// Copy the content into a byte array to avoid reading the content inputstream multiple times.
builder = builder.POST(BodyPublishers.ofByteArray(Contents.bytes(req.getContent())));
builder = builder.POST(notChunkingBodyPublisher(req));
break;

case PUT:
builder = builder.PUT(BodyPublishers.ofByteArray(Contents.bytes(req.getContent())));
builder = builder.PUT(notChunkingBodyPublisher(req));
break;

default:
Expand All @@ -103,6 +103,27 @@ public java.net.http.HttpRequest createRequest(HttpRequest req) {
return builder.build();
}

/**
* Some drivers do not support chunked transport, we ensure the http client is not using chunked
* transport. This is done by using a BodyPublisher with a known size, in best case without
* wasting memory by buffering the request.
*
* @return a BodyPublisher with a known size
*/
private BodyPublisher notChunkingBodyPublisher(HttpRequest req) {
String length = req.getHeader("content-length");

if (length == null) {
// read the data into a byte array to know the length
return BodyPublishers.ofByteArray(Contents.bytes(req.getContent()));
}

// we know the length of the request and use it
BodyPublisher chunking = BodyPublishers.ofInputStream(req.getContent());

return BodyPublishers.fromPublisher(chunking, Long.parseLong(length));
}

private String getRawUrl(URI baseUrl, String uri) {
String rawUrl;
if (uri.startsWith("ws://") || uri.startsWith("wss://") ||
Expand Down

0 comments on commit e0ade5c

Please sign in to comment.