Skip to content

Commit 05435e7

Browse files
committed
The proxy uses and expose the authority as a host header, performing limited host header parsing (IPV6 host are not parsed).
Instead of relying on the HttpServerRequest#host() method, use HttpServerRequest#authority() which provides the same value parsed as an HostAndPort instance.
1 parent 2824360 commit 05435e7

File tree

4 files changed

+71
-16
lines changed

4 files changed

+71
-16
lines changed

src/main/java/examples/HttpProxyExamples.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import io.vertx.core.http.HttpServer;
99
import io.vertx.core.http.HttpServerRequest;
1010
import io.vertx.core.http.RequestOptions;
11+
import io.vertx.core.net.HostAndPort;
1112
import io.vertx.core.net.SocketAddress;
1213
import io.vertx.httpproxy.Body;
1314
import io.vertx.httpproxy.HttpProxy;
@@ -169,7 +170,7 @@ public void overrideAuthority(HttpProxy proxy) {
169170
@Override
170171
public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
171172
ProxyRequest proxyRequest = context.request();
172-
proxyRequest.setAuthority("example.com:80");
173+
proxyRequest.setAuthority(HostAndPort.create("example.com", 80));
173174
return ProxyInterceptor.super.handleProxyRequest(context);
174175
}
175176
});

src/main/java/io/vertx/httpproxy/ProxyRequest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import io.vertx.core.http.HttpMethod;
2020
import io.vertx.core.http.HttpServerRequest;
2121
import io.vertx.core.http.HttpVersion;
22+
import io.vertx.core.net.HostAndPort;
2223
import io.vertx.httpproxy.impl.ProxiedRequest;
2324

2425
/**
@@ -113,12 +114,12 @@ static ProxyRequest reverseProxy(HttpServerRequest proxiedRequest) {
113114
* @return a reference to this, so the API can be used fluently
114115
*/
115116
@Fluent
116-
ProxyRequest setAuthority(String authority);
117+
ProxyRequest setAuthority(HostAndPort authority);
117118

118119
/**
119120
* @return the request authority, for HTTP2 the {@literal :authority} pseudo header otherwise the {@literal Host} header
120121
*/
121-
String getAuthority();
122+
HostAndPort getAuthority();
122123

123124
/**
124125
* @return the headers that will be sent to the origin server, the returned headers can be modified. The headers

src/main/java/io/vertx/httpproxy/impl/ProxiedRequest.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,15 @@ public ProxyRequest setBody(Body body) {
110110
}
111111

112112
@Override
113-
public ProxyRequest setAuthority(String authority) {
113+
public ProxyRequest setAuthority(HostAndPort authority) {
114114
Objects.requireNonNull(authority);
115-
this.authority= HostAndPortImpl.parseHostAndPort(authority, -1);
115+
this.authority= authority;
116116
return this;
117117
}
118118

119119
@Override
120-
public String getAuthority() {
121-
return authority.toString();
120+
public HostAndPort getAuthority() {
121+
return authority;
122122
}
123123

124124
@Override
@@ -176,10 +176,13 @@ void sendRequest(Handler<AsyncResult<ProxyResponse>> responseHandler) {
176176
}
177177

178178
//
179-
HostAndPort proxiedAuthority = proxiedRequest.authority();
180-
request.authority(authority);
181-
if (!proxiedAuthority.host().equals(authority.host()) || proxiedAuthority.port() != authority.port()) {
182-
request.putHeader(X_FORWARDED_HOST, proxiedAuthority.toString());
179+
if (authority != null) {
180+
request.authority(authority);
181+
HostAndPort proxiedAuthority = proxiedRequest.authority();
182+
if (!equals(authority, proxiedAuthority)) {
183+
// Should cope with existing forwarded host headers
184+
request.putHeader(X_FORWARDED_HOST, proxiedAuthority.toString());
185+
}
183186
}
184187

185188
long len = body.length();
@@ -200,6 +203,13 @@ void sendRequest(Handler<AsyncResult<ProxyResponse>> responseHandler) {
200203
});
201204
}
202205

206+
private static boolean equals(HostAndPort hp1, HostAndPort hp2) {
207+
if (hp1 == null || hp2 == null) {
208+
return false;
209+
}
210+
return hp1.host().equals(hp2.host()) && hp1.port() == hp2.port();
211+
}
212+
203213
@Override
204214
public ProxyRequest putHeader(CharSequence name, CharSequence value) {
205215
headers.set(name, value);

src/test/java/io/vertx/httpproxy/ProxyClientKeepAliveTest.java

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
import io.vertx.core.Promise;
1515
import io.vertx.core.buffer.Buffer;
1616
import io.vertx.core.http.*;
17+
import io.vertx.core.net.HostAndPort;
1718
import io.vertx.core.net.NetClient;
1819
import io.vertx.core.net.SocketAddress;
1920
import io.vertx.core.streams.WriteStream;
2021
import io.vertx.ext.unit.Async;
2122
import io.vertx.ext.unit.TestContext;
23+
import org.junit.Ignore;
2224
import org.junit.Test;
2325

2426
import java.io.Closeable;
@@ -736,22 +738,62 @@ public void testPropagateHeaders(TestContext ctx) {
736738
}));
737739
}
738740

741+
@Test
742+
public void testIPV6Authority(TestContext ctx) {
743+
testAuthority(ctx, HostAndPort.authority("[7a03:908:671:b520:ba27:bbff:ffff:fed2]", 1234));
744+
}
745+
746+
@Test
747+
public void testIPV4Authority(TestContext ctx) {
748+
testAuthority(ctx, HostAndPort.authority("192.168.0.1", 1234));
749+
}
750+
751+
@Test
752+
public void testMissingPortAuthority(TestContext ctx) {
753+
testAuthority(ctx, HostAndPort.authority("localhost", -1));
754+
}
755+
756+
private void testAuthority(TestContext ctx, HostAndPort requestAuthority) {
757+
SocketAddress backend = startHttpBackend(ctx, 8081, req -> {
758+
ctx.assertEquals("/somepath", req.uri());
759+
ctx.assertEquals(requestAuthority.host(), req.authority().host());
760+
ctx.assertEquals(requestAuthority.port(), req.authority().port());
761+
ctx.assertEquals(null, req.getHeader("x-forwarded-host"));
762+
req.response().end("Hello World");
763+
});
764+
startProxy(proxy -> {
765+
proxy.origin(backend);
766+
});
767+
HttpClient client = vertx.createHttpClient();
768+
client.request(GET, 8080, "localhost", "/somepath")
769+
.compose(req -> req
770+
.authority(requestAuthority)
771+
.send()
772+
.compose(resp -> {
773+
ctx.assertEquals(200, resp.statusCode());
774+
return resp.body();
775+
}))
776+
.onComplete(ctx.asyncAssertSuccess(body -> {
777+
ctx.assertEquals("Hello World", body.toString());
778+
}));
779+
}
780+
739781
@Test
740782
public void testAuthorityOverride1(TestContext ctx) {
741-
testAuthorityOverride(ctx, "foo:8080", "foo:8080", "localhost:8080");
783+
testAuthorityOverride(ctx, HostAndPort.authority("foo", 8080), "foo:8080", "localhost:8080");
742784
}
743785

744786
@Test
745787
public void testAuthorityOverride2(TestContext ctx) {
746-
testAuthorityOverride(ctx, "foo", "foo", "localhost:8080");
788+
testAuthorityOverride(ctx, HostAndPort.authority("foo"), "foo", "localhost:8080");
747789
}
748790

749791
@Test
750792
public void testAuthorityOverride3(TestContext ctx) {
751-
testAuthorityOverride(ctx, "localhost:8080", "localhost:8080", null);
793+
testAuthorityOverride(ctx, HostAndPort.authority("localhost", 8080), "localhost:8080", null);
752794
}
753795

754-
private void testAuthorityOverride(TestContext ctx, String authority, String expectedAuthority, String expectedForwardedHost) {
796+
private void testAuthorityOverride(TestContext ctx, HostAndPort authority, String expectedAuthority, String expectedForwardedHost) {
755797
SocketAddress backend = startHttpBackend(ctx, 8081, req -> {
756798
ctx.assertEquals("/somepath", req.uri());
757799
ctx.assertEquals(expectedAuthority, req.authority().toString());
@@ -764,7 +806,8 @@ private void testAuthorityOverride(TestContext ctx, String authority, String exp
764806
@Override
765807
public Future<ProxyResponse> handleProxyRequest(ProxyContext context) {
766808
ProxyRequest request = context.request();
767-
ctx.assertEquals("localhost:8080", request.getAuthority());
809+
ctx.assertEquals("localhost", request.getAuthority().host());
810+
ctx.assertEquals(8080, request.getAuthority().port());
768811
request.setAuthority(authority);
769812
return ProxyInterceptor.super.handleProxyRequest(context);
770813
}

0 commit comments

Comments
 (0)