Skip to content

Commit 9819b0c

Browse files
efekrskladuh95
authored andcommitted
http: normalize CONNECT request paths
Signed-off-by: Efe Karasakal <hi@efe.dev> PR-URL: #64876 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Tim Perry <pimterry@gmail.com>
1 parent 1d68f23 commit 9819b0c

2 files changed

Lines changed: 74 additions & 1 deletion

File tree

‎lib/_http_client.js‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const {
2828
NumberIsFinite,
2929
ObjectAssign,
3030
ObjectDefineProperty,
31+
ObjectHasOwn,
3132
ObjectKeys,
3233
ObjectSetPrototypeOf,
3334
ReflectApply,
@@ -331,12 +332,15 @@ function rewriteForProxiedHttp(req, reqOptions, proxyAuthority, userHostHeader,
331332
function ClientRequest(input, options, cb) {
332333
OutgoingMessage.call(this);
333334

335+
let pathIsFromURL = false;
334336
if (typeof input === 'string') {
335337
const urlStr = input;
336338
input = urlToHttpOptions(new URL(urlStr));
339+
pathIsFromURL = true;
337340
} else if (isURL(input)) {
338341
// url.URL instance
339342
input = urlToHttpOptions(input);
343+
pathIsFromURL = true;
340344
} else {
341345
cb = options;
342346
options = input;
@@ -347,6 +351,13 @@ function ClientRequest(input, options, cb) {
347351
cb = options;
348352
options = input || kEmptyObject;
349353
} else {
354+
const hasPathOverride = pathIsFromURL &&
355+
options != null &&
356+
ObjectHasOwn(options, 'path');
357+
if (hasPathOverride) {
358+
pathIsFromURL = false;
359+
}
360+
350361
options = ObjectAssign({ __proto__: null }, input, options);
351362
}
352363

@@ -466,7 +477,13 @@ function ClientRequest(input, options, cb) {
466477

467478
this.joinDuplicateHeaders = options.joinDuplicateHeaders;
468479

469-
this[kPath] = options.path || '/';
480+
let path = options.path || '/';
481+
// Strip the leading slash added when the CONNECT target comes from a URL.
482+
if (method === 'CONNECT' && pathIsFromURL && path[0] === '/') {
483+
path = path.slice(1) || '/';
484+
}
485+
486+
this[kPath] = path;
470487
if (cb) {
471488
this.once('response', cb);
472489
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const http = require('http');
6+
7+
{
8+
const server = http.createServer(common.mustNotCall());
9+
10+
server.on('connect', common.mustCall((req, socket) => {
11+
assert.strictEqual(req.url, 'example.com');
12+
socket.end('HTTP/1.1 501 Not Implemented\r\n\r\n');
13+
}));
14+
15+
server.listen(0, common.mustCall(() => {
16+
const port = server.address().port;
17+
const req = http.request(
18+
new URL(`http://localhost:${port}/example.com`),
19+
{ method: 'CONNECT' },
20+
);
21+
22+
req.on('connect', common.mustCall((res, socket) => {
23+
assert.strictEqual(res.statusCode, 501);
24+
socket.destroy();
25+
server.close();
26+
}));
27+
28+
req.end();
29+
}));
30+
}
31+
32+
{
33+
const server = http.createServer(common.mustNotCall());
34+
35+
server.on('connect', common.mustCall((req, socket) => {
36+
assert.strictEqual(req.url, '/example.com');
37+
socket.end('HTTP/1.1 501 Not Implemented\r\n\r\n');
38+
}));
39+
40+
server.listen(0, common.mustCall(() => {
41+
const req = http.request({
42+
host: 'localhost',
43+
port: server.address().port,
44+
method: 'CONNECT',
45+
path: '/example.com',
46+
});
47+
48+
req.on('connect', common.mustCall((res, socket) => {
49+
assert.strictEqual(res.statusCode, 501);
50+
socket.destroy();
51+
server.close();
52+
}));
53+
54+
req.end();
55+
}));
56+
}

0 commit comments

Comments
 (0)