Skip to content

Commit

Permalink
Ensures chunked encoding is enabled whenever there are trailers to be…
Browse files Browse the repository at this point in the history
… sent, even if a Content-Length header was specified. New test that adds a trailer and sets a Content-Length header. (helidon-io#9334)
  • Loading branch information
spericas authored and barchetta committed Oct 11, 2024
1 parent c9e54f3 commit cc496dc
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Oracle and/or its affiliates.
* Copyright (c) 2023, 2024 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.
Expand Down Expand Up @@ -89,6 +89,16 @@ static void router(HttpRouting.Builder router) {
res.send(DATA);
}
);
router.route(GET, "/stream-with-trailers-and-length",
(req, res) -> {
res.header(HeaderNames.TRAILER, TEST_TRAILER_HEADER.name());
res.header(HeaderNames.CONTENT_LENGTH, String.valueOf(DATA.length())); // must switch to chunked
try (var os = res.outputStream()) {
os.write(DATA.getBytes());
}
res.trailers().add(TEST_TRAILER_HEADER);
}
);
}

@Test
Expand Down Expand Up @@ -149,6 +159,19 @@ void trailersNoTrailers(WebClient client) {
+ "response headers have trailer names definition 'Trailer: <trailer-name>'"));
}

@Test
void streamWithTrailersAndLength(WebClient client) throws IOException {
ClientResponseTyped<InputStream> res = client
.get("/stream-with-trailers-and-length")
.header(HeaderValues.TE_TRAILERS)
.request(InputStream.class);
assertThat(res.headers(), hasHeader(HeaderValues.TRANSFER_ENCODING_CHUNKED)); // trailers need chunked
try (var ins = res.entity()) {
assertThat(ins.readAllBytes(), is(DATA.getBytes()));
}
assertThat(res.trailers(), hasHeader(TEST_TRAILER_HEADER));
}

private void checkCachedConnection(ClientResponseHeaders h) {
if (clientPort == -1) {
clientPort = h.get(CLIENT_PORT_HEADER_NAME).asInt().get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,10 +479,15 @@ private BlockingOutputStream(ServerResponseHeaders headers,
this.validateHeaders = validateHeaders;
}

void checkResponseHeaders(){
this.isChunked = !headers.contains(HeaderNames.CONTENT_LENGTH);
this.forcedChunked = headers.contains(HeaderValues.TRANSFER_ENCODING_CHUNKED)
|| headers.contains(HeaderNames.TRAILER);
void checkResponseHeaders() {
if (headers.contains(HeaderNames.TRAILER)) {
headers.remove(HeaderNames.CONTENT_LENGTH);
isChunked = true;
forcedChunked = true;
} else {
isChunked = !headers.contains(HeaderNames.CONTENT_LENGTH);
forcedChunked = headers.contains(HeaderValues.TRANSFER_ENCODING_CHUNKED);
}
}

@Override
Expand Down Expand Up @@ -557,13 +562,13 @@ void commit() {
}

if (sendTrailers) {
// not optimized, trailers enabled: we need to write trailers
trailers.set(STREAM_RESULT_NAME, streamResult.get());
BufferData buffer = BufferData.growing(128);
writeHeaders(trailers, buffer, this.validateHeaders);
buffer.write('\r'); // "\r\n" - empty line after headers
buffer.write('\n');
dataWriter.write(buffer);
// not optimized, trailers enabled: we need to write trailers
trailers.set(STREAM_RESULT_NAME, streamResult.get());
BufferData buffer = BufferData.growing(128);
writeHeaders(trailers, buffer, this.validateHeaders);
buffer.write('\r'); // "\r\n" - empty line after headers
buffer.write('\n');
dataWriter.write(buffer);
}

responseCloseRunnable.run();
Expand Down

0 comments on commit cc496dc

Please sign in to comment.