Skip to content

Commit 97039b2

Browse files
committed
Fix request absolute URI handling
When a request uses an absolute request target with scheme and host parts, the current absoluteURI() method simply concatenates the Host header value and the request target URI. For example, with the following request: ``` GET http://www.example.com:1234/path HTTP/1.1 Host: www.example.com:1234 ``` The result of HttpServerRequest.absoluteURI() would then be: `http://www.example.com:1234www.example.com:1234/path` With this change, when the request target is absolute, only the path (and query) are added to the Host value: `http://www.example.com:1234/path` Fixes #2830
1 parent af256dd commit 97039b2

File tree

2 files changed

+92
-2
lines changed

2 files changed

+92
-2
lines changed

vertx-web/src/main/java/io/vertx/ext/web/impl/ForwardedParser.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,16 @@ private void calculate() {
133133
if (host != null) {
134134
this.authority = HostAndPort.create(host, port);
135135
host = host + (port >= 0 ? ":" + port : "");
136-
absoluteURI = scheme + "://" + host + delegate.uri();
136+
137+
String uri = delegate.uri();
138+
if (uri.startsWith(scheme + "://")) {
139+
// URI is already absolute, only append the path and query
140+
uri = delegate.path();
141+
if (delegate.query() != null) {
142+
uri += "?" + delegate.query();
143+
}
144+
}
145+
absoluteURI = scheme + "://" + host + uri;
137146
}
138147
}
139148

@@ -188,7 +197,7 @@ private void calculateXForward() {
188197
}
189198
}
190199

191-
private void setHostAndPort(HostAndPort authority) {
200+
private void setHostAndPort(HostAndPort authority) {
192201
host = authority.host();
193202
port = authority.port();
194203
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2023 Red Hat, Inc.
3+
*
4+
* All rights reserved. This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License v1.0
6+
* and Apache License v2.0 which accompanies this distribution.
7+
*
8+
* The Eclipse Public License is available at
9+
* http://www.eclipse.org/legal/epl-v10.html
10+
*
11+
* The Apache License v2.0 is available at
12+
* http://www.opensource.org/licenses/apache2.0.php
13+
*
14+
* You may elect to redistribute this code under either of these licenses.
15+
*/
16+
package io.vertx.ext.web.tests.impl;
17+
18+
import io.netty.handler.codec.http.HttpResponseStatus;
19+
import io.vertx.core.http.HttpMethod;
20+
import io.vertx.core.net.HostAndPort;
21+
import io.vertx.ext.web.tests.WebTestBase;
22+
import org.junit.Test;
23+
import org.junit.runner.RunWith;
24+
import org.junit.runners.Parameterized;
25+
26+
import java.util.Arrays;
27+
28+
@RunWith(Parameterized.class)
29+
public class AbsoluteUriTest extends WebTestBase {
30+
31+
@Parameterized.Parameters(name = "target={0}, host={1}, query={2}")
32+
public static Iterable<Object[]> data() {
33+
return Arrays.asList(
34+
// absolute URI, no explicit authority, no query -> the authority in the URI is ignored
35+
new Object[]{"http://www.example.com:1234/some/path", null, null, "http://localhost:8080/some/path"},
36+
// absolute URI, no explicit authority, query present -> the authority in the URI is ignored
37+
new Object[]{"http://www.example.com:1234/some/path", null, "a=1&b=2", "http://localhost:8080/some/path?a=1&b=2"},
38+
// absolute URI, same explicit authority, no query
39+
new Object[]{"http://www.example.com:1234/some/path", "www.example.com:1234", null, "http://www.example.com:1234/some/path"},
40+
// absolute URI, same explicit authority, query present
41+
new Object[]{"http://www.example.com:1234/some/path", "www.example.com:1234", "a=1&b=2", "http://www.example.com:1234/some/path?a=1&b=2"},
42+
// absolute URI, different explicit authority, no query
43+
new Object[]{"http://www.example.com:1234/some/path", "another-host.com:5678", null, "http://another-host.com:5678/some/path"},
44+
// absolute URI, different explicit authority, query present
45+
new Object[]{"http://www.example.com:1234/some/path", "another-host.com:5678", "a=1&b=2", "http://another-host.com:5678/some/path?a=1&b=2"},
46+
// relative URI, no query
47+
new Object[]{"/some/path", "www.example.com:1234", null, "http://www.example.com:1234/some/path"},
48+
// relative URI, query present
49+
new Object[]{"/some/path", "www.example.com:1234", "a=1&b=2", "http://www.example.com:1234/some/path?a=1&b=2"}
50+
);
51+
}
52+
53+
private final String target;
54+
private final String authority;
55+
private final String query;
56+
private final String expectedAbsoluteUri;
57+
58+
public AbsoluteUriTest(String target, String authority, String query, String expectedAbsoluteUri) {
59+
this.target = target;
60+
this.authority = authority;
61+
this.query = query;
62+
this.expectedAbsoluteUri = expectedAbsoluteUri;
63+
}
64+
65+
@Test
66+
public void testAbsoluteUri() throws Exception {
67+
String uri = target + (query != null ? "?" + query : "");
68+
69+
router.route().handler(event -> {
70+
assertEquals(expectedAbsoluteUri, event.request().absoluteURI());
71+
assertEquals(uri, event.request().uri());
72+
event.response().end();
73+
});
74+
75+
testRequest(HttpMethod.GET, uri, request -> {
76+
if (authority != null) {
77+
request.authority(HostAndPort.parseAuthority(authority, 80));
78+
}
79+
}, HttpResponseStatus.OK.code(), HttpResponseStatus.OK.reasonPhrase(), null);
80+
}
81+
}

0 commit comments

Comments
 (0)