Skip to content

Commit 818fd8a

Browse files
Filter out Host header when proxying websockets (#134) (#136)
Co-authored-by: Björn Husberg <[email protected]>
1 parent 512a45b commit 818fd8a

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@
2121

2222
import java.util.*;
2323

24-
import static io.vertx.core.http.HttpHeaders.CONNECTION;
25-
import static io.vertx.core.http.HttpHeaders.UPGRADE;
24+
import static io.vertx.core.http.HttpHeaders.*;
2625

2726
public class ReverseProxy implements HttpProxy {
2827

@@ -95,7 +94,18 @@ private void handleWebSocketUpgrade(ProxyContext proxyContext) {
9594
HttpClientRequest request = ar.result();
9695
request.setMethod(HttpMethod.GET);
9796
request.setURI(proxiedRequest.uri());
98-
request.headers().addAll(proxiedRequest.headers()).set(CONNECTION, UPGRADE);
97+
for (Map.Entry<String, String> header : proxiedRequest.headers()) {
98+
String name = header.getKey();
99+
if (name.equalsIgnoreCase(CONNECTION.toString())) {
100+
// Firefox is known to send an unexpected connection header value
101+
// Connection=keep-alive, Upgrade
102+
// It leads to a failure in websocket proxying
103+
// So we make sure the standard value is sent to the backend
104+
request.headers().set(CONNECTION, UPGRADE);
105+
} else if (!name.equalsIgnoreCase(HOST.toString())) {
106+
request.headers().add(name, header.getValue());
107+
}
108+
}
99109
Future<HttpClientResponse> fut2 = request.connect();
100110
proxiedRequest.handler(request::write);
101111
proxiedRequest.endHandler(v -> request.end());

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,37 @@ public void testWebSocketFirefox(TestContext ctx) {
144144
}));
145145
}
146146

147+
@Test
148+
public void testWebSocketHostHeader(TestContext ctx) {
149+
Async async = ctx.async();
150+
SocketAddress backend = startHttpBackend(ctx, 8081, req -> {
151+
ctx.assertEquals("localhost:8081", req.headers().get("Host"));
152+
Future<ServerWebSocket> fut = req.toWebSocket();
153+
fut.onComplete(ctx.asyncAssertSuccess(ws -> {
154+
ws.closeHandler(v -> {
155+
async.complete();
156+
});
157+
}));
158+
});
159+
startProxy(backend);
160+
HttpClient httpClient = vertx.createHttpClient();
161+
RequestOptions options = new RequestOptions()
162+
.setPort(8080)
163+
.setHost("localhost")
164+
.setURI("/ws")
165+
.putHeader("Origin", "http://localhost:8080")
166+
.putHeader("Connection", "Upgrade")
167+
.putHeader("Upgrade", "Websocket")
168+
.putHeader("Sec-WebSocket-Version", "13")
169+
.putHeader("Sec-WebSocket-Key", "xy6UoM3l3TcREmAeAhZuYQ==");
170+
httpClient.request(options).onComplete(ctx.asyncAssertSuccess(clientRequest -> {
171+
clientRequest.connect().onComplete(ctx.asyncAssertSuccess(response -> {
172+
ctx.assertEquals(101, response.statusCode());
173+
response.netSocket().close();
174+
}));
175+
}));
176+
}
177+
147178
@Test
148179
public void testWebSocketExtensionsNegotiatedBetweenClientAndBackend(TestContext ctx) {
149180
Async async = ctx.async();

0 commit comments

Comments
 (0)