Skip to content

Commit a4eaffd

Browse files
committed
Vert.x HTTP client should sanitize chunked transfer encoding header for HTTP/2
Motivation: One should use setChunked on HttpClientRequest to set the chunked encoding header when necessary, however the user of the request might not be aware of this and set manually a chunked transfer-encoding header, such as the client form API. Changes: Remove the transfer encoding header in HTTP/2 client stream before passing headers to the actual implementation. Add client multipart / form tests.
1 parent 5a813c8 commit a4eaffd

File tree

8 files changed

+120
-6
lines changed

8 files changed

+120
-6
lines changed

vertx-core/src/main/java/io/vertx/core/http/impl/HttpClientRequestImpl.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,6 @@ private Future<Void> doWrite(ByteBuf buff, boolean end, boolean connect) {
527527
if (uri.isEmpty()) {
528528
uri = "/";
529529
}
530-
HostAndPort a;
531530
HttpRequestHead head = new HttpRequestHead(method, uri, headers, authority(), absoluteURI(), traceOperation);
532531
future = stream.writeHead(head, chunked, buff, writeEnd, priority, connect);
533532
} else {

vertx-core/src/main/java/io/vertx/core/http/impl/http2/Http2ClientStreamImpl.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111
package io.vertx.core.http.impl.http2;
1212

1313
import io.netty.buffer.ByteBuf;
14+
import io.netty.handler.codec.http.HttpHeaderValidationUtil;
1415
import io.netty.handler.codec.http.HttpResponseStatus;
1516
import io.vertx.core.Future;
1617
import io.vertx.core.Handler;
1718
import io.vertx.core.MultiMap;
1819
import io.vertx.core.Promise;
1920
import io.vertx.core.buffer.Buffer;
2021
import io.vertx.core.http.HttpFrame;
22+
import io.vertx.core.http.HttpHeaders;
2123
import io.vertx.core.http.HttpVersion;
2224
import io.vertx.core.http.StreamPriority;
2325
import io.vertx.core.http.StreamResetException;
@@ -30,6 +32,9 @@
3032
import io.vertx.core.spi.metrics.ClientMetrics;
3133
import io.vertx.core.tracing.TracingPolicy;
3234

35+
import java.util.Iterator;
36+
import java.util.Map;
37+
3338
/**
3439
* @author <a href="mailto:julien@julienviet.com">Julien Viet</a>
3540
*/
@@ -210,11 +215,12 @@ public HttpVersion version() {
210215
@Override
211216
public Future<Void> writeHead(HttpRequestHead request, boolean chunked, ByteBuf buf, boolean end, StreamPriority priority, boolean connect) {
212217
PromiseInternal<Void> promise = context.promise();
213-
214218
stream = new Http2ClientStream(conn, context, tracingPolicy, decompressionSupported, clientMetrics);
215-
216219
stream.handler(this);
217-
220+
MultiMap headers = request.headers;
221+
if (headers != null) {
222+
headers.remove(HttpHeaders.TRANSFER_ENCODING);
223+
}
218224
stream.writeHeaders(request, buf, end, priority, promise);
219225
return promise.future();
220226
}

vertx-core/src/main/java/io/vertx/core/http/impl/http2/codec/Http1xUpgradeToH2CHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
110110
request.headers().remove("host");
111111
request.headers().forEach(header -> {
112112
if (!HttpHeaderValidationUtil.isConnectionHeader(header.getKey(), true)) {
113-
headers.set(header.getKey().toLowerCase(), header.getValue());
113+
headers.add(header.getKey().toLowerCase(), header.getValue());
114114
}
115115
});
116116
ctx.fireChannelRead(new DefaultHttp2HeadersFrame(headers, false));
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright (c) 2011-2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
package io.vertx.tests.http.fileupload;
12+
13+
public class Http1xClientFileUploadTest extends HttpClientFileUploadTest {
14+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (c) 2011-2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
package io.vertx.tests.http.fileupload;
12+
13+
import io.vertx.core.http.HttpClientOptions;
14+
import io.vertx.core.http.HttpServerOptions;
15+
import io.vertx.test.http.HttpTestBase;
16+
import io.vertx.tests.http.Http2TestBase;
17+
18+
public class Http2ClientFileUploadTest extends HttpClientFileUploadTest {
19+
20+
@Override
21+
protected HttpServerOptions createBaseServerOptions() {
22+
return Http2TestBase.createHttp2ServerOptions(HttpTestBase.DEFAULT_HTTP_PORT, DEFAULT_HTTP_HOST);
23+
}
24+
25+
@Override
26+
protected HttpClientOptions createBaseClientOptions() {
27+
return Http2TestBase.createHttp2ClientOptions();
28+
}
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (c) 2011-2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
package io.vertx.tests.http.fileupload;
12+
13+
import io.vertx.core.http.HttpClientOptions;
14+
import io.vertx.core.http.HttpServerOptions;
15+
import io.vertx.test.http.HttpTestBase;
16+
import io.vertx.tests.http.Http2TestBase;
17+
18+
public class Http2MultiplexClientFileUploadTest extends Http2ClientFileUploadTest {
19+
20+
@Override
21+
protected HttpServerOptions createBaseServerOptions() {
22+
return super.createBaseServerOptions().setHttp2MultiplexImplementation(true);
23+
}
24+
25+
@Override
26+
protected HttpClientOptions createBaseClientOptions() {
27+
return super.createBaseClientOptions().setHttp2MultiplexImplementation(true);
28+
}
29+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright (c) 2011-2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
11+
package io.vertx.tests.http.fileupload;
12+
13+
import io.vertx.core.http.HttpClientOptions;
14+
import io.vertx.core.http.HttpVersion;
15+
16+
public class Http2WithUpgradeClientFileUploadTest extends HttpClientFileUploadTest {
17+
18+
@Override
19+
protected HttpClientOptions createBaseClientOptions() {
20+
return new HttpClientOptions()
21+
.setProtocolVersion(HttpVersion.HTTP_2)
22+
.setHttp2ClearTextUpgrade(true);
23+
}
24+
}

vertx-core/src/test/java/io/vertx/tests/http/fileupload/HttpClientFileUploadTest.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
1+
/*
2+
* Copyright (c) 2011-2025 Contributors to the Eclipse Foundation
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7+
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10+
*/
111
package io.vertx.tests.http.fileupload;
212

313
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder;
414
import io.vertx.core.Future;
515
import io.vertx.core.MultiMap;
616
import io.vertx.core.buffer.Buffer;
717
import io.vertx.core.http.*;
18+
import io.vertx.core.impl.Utils;
819
import io.vertx.test.core.TestUtils;
920
import io.vertx.test.http.HttpTestBase;
21+
import org.junit.Assume;
1022
import org.junit.Rule;
1123
import org.junit.Test;
1224
import org.junit.rules.TemporaryFolder;
@@ -22,7 +34,7 @@
2234
import java.util.List;
2335
import java.util.function.BiConsumer;
2436

25-
public class HttpClientFileUploadTest extends HttpTestBase {
37+
public abstract class HttpClientFileUploadTest extends HttpTestBase {
2638

2739
@Rule
2840
public TemporaryFolder testFolder = new TemporaryFolder();
@@ -163,6 +175,7 @@ public void testFileUploadFormMultipart32K() throws Exception {
163175

164176
@Test
165177
public void testFileUploadFormMultipart32M() throws Exception {
178+
Assume.assumeTrue(!Utils.isWindows());
166179
testFileUploadFormMultipart(32 * 1024 * 1024, false);
167180
}
168181

0 commit comments

Comments
 (0)