Skip to content

Commit 5a2dc06

Browse files
committed
Prioritise the explicit tunnel destination over headers
If you connect, request to talk to A.host and then send a request, we should assume you wanted to send it to A.host (even if the host header is different - there are some interesting & unusual testing cases where this is actively desireable, e.g. testing a server before updating the DNS.
1 parent 8b3e4c1 commit 5a2dc06

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

src/server/mockttp-server.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import {
5050
buildSocketEventData,
5151
ClientErrorInProgress,
5252
LastHopEncrypted,
53+
LastTunnelAddress,
5354
TlsSetupCompleted,
5455
isSocketLoop,
5556
resetOrDestroy
@@ -66,6 +67,7 @@ import {
6667
} from "../util/request-utils";
6768
import { asBuffer } from "../util/buffer-utils";
6869
import {
70+
getHeaderValue,
6971
pairFlatRawHeaders,
7072
rawHeadersToObject
7173
} from "../util/header-utils";
@@ -566,6 +568,10 @@ export class MockttpServer extends AbstractMockttp implements Mockttp {
566568
});
567569
}
568570

571+
/**
572+
* For both normal requests & websockets, we do some standard preprocessing to ensure we have the absolute
573+
* URL destination in place, and timing, tags & id metadata all ready for an OngoingRequest.
574+
*/
569575
private preprocessRequest(req: ExtendedRawRequest, type: 'request' | 'websocket'): OngoingRequest {
570576
parseRequestBody(req, { maxSize: this.maxBodySize });
571577

@@ -576,7 +582,10 @@ export class MockttpServer extends AbstractMockttp implements Mockttp {
576582
(req.socket[LastHopEncrypted] ? 'https' : 'http');
577583
req.path = req.url;
578584

579-
const host = req.headers[':authority'] || req.headers['host'];
585+
const host = req.socket[LastTunnelAddress] // If you explicitly tunnel to a host, that's the host
586+
?? getHeaderValue(req.headers, ':authority') // Otherwise, we infer based on headers: HTTP/2
587+
?? getHeaderValue(req.headers, 'host'); // or HTTP/1.1
588+
580589
const absoluteUrl = `${req.protocol}://${host}${req.path}`;
581590

582591
if (!req.headers[':path']) {

test/integration/proxying/socks-proxying.spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,5 +134,32 @@ nodeOnly(() => {
134134
expect(body.toString()).to.equal("Hello world!");
135135
});
136136

137+
it("should use the SOCKS destination over the Host header", async () => {
138+
await remoteServer.forGet("/").thenReply(200, "Hello world!");
139+
await server.forAnyRequest().thenPassThrough();
140+
141+
const socksConn = await SocksClient.createConnection({
142+
proxy: {
143+
host: '127.0.0.1',
144+
port: server.port,
145+
type: 5
146+
},
147+
command: 'connect',
148+
destination: {
149+
host: 'localhost',
150+
port: remoteServer.port
151+
}
152+
});
153+
154+
const response = await h1RequestOverSocket(socksConn.socket, remoteServer.url, {
155+
headers: {
156+
Host: "invalid.example" // This should be ignored - tunnel sets destination
157+
}
158+
});
159+
expect(response.statusCode).to.equal(200);
160+
const body = await streamToBuffer(response);
161+
expect(body.toString()).to.equal("Hello world!");
162+
});
163+
137164
});
138165
});

0 commit comments

Comments
 (0)