mirror of
https://github.com/tenrok/axios.git
synced 2026-06-17 19:21:29 +03:00
Co-authored-by: Jason Saayman <jasonsaayman@gmail.com>
This commit is contained in:
committed by
GitHub
parent
97fb8af785
commit
01e869dd28
@@ -4,4 +4,8 @@
|
||||
|
||||
## Bug Fixes
|
||||
|
||||
- **Proxy Agent Streams:** Guarded Node HTTP adapter TCP keep-alive setup so proxy agents that return generic Duplex streams do not throw when `setKeepAlive` is unavailable. (**#10917**, closes **#10908**)
|
||||
- **HTTP Adapter - socketPath:** Path-only request URLs (e.g. `'/foo'`) now work again with `config.socketPath`, fixing the `TypeError [ERR_INVALID_URL]` regression introduced in 1.7.4 when `new URL()` was added to the dispatch path. A synthetic `http://localhost` base is supplied only when an own `socketPath` is set, so absolute URLs, non-socket requests, and prototype-polluted `socketPath` values are unaffected. (**#6611**)
|
||||
|
||||
## Release Tracking
|
||||
|
||||
- **Proxy Agent Streams:** Guarded Node HTTP adapter TCP keep-alive setup so proxy agents that return generic Duplex streams do not throw when `setKeepAlive` is unavailable. (**#10917**, closes **#10908**)
|
||||
|
||||
@@ -477,6 +477,7 @@ export default isHttpAdapterSupported &&
|
||||
let http2Options = own('http2Options');
|
||||
const responseType = own('responseType');
|
||||
const responseEncoding = own('responseEncoding');
|
||||
const socketPath = own('socketPath');
|
||||
const httpAgent = own('httpAgent');
|
||||
const httpsAgent = own('httpsAgent');
|
||||
const method = own('method').toUpperCase();
|
||||
@@ -603,7 +604,14 @@ export default isHttpAdapterSupported &&
|
||||
|
||||
// Parse url
|
||||
const fullPath = buildFullPath(own('baseURL'), own('url'), own('allowAbsoluteUrls'), config);
|
||||
const parsed = new URL(fullPath, platform.hasBrowserEnv ? platform.origin : undefined);
|
||||
// Unix-socket requests (own socketPath) commonly pass a path-only url
|
||||
// like '/foo'; supply a synthetic base so new URL() can still parse it.
|
||||
// Use the own-property value (not config.socketPath) so a polluted
|
||||
// prototype cannot influence URL base selection.
|
||||
const urlBase = socketPath
|
||||
? 'http://localhost'
|
||||
: (platform.hasBrowserEnv ? platform.origin : undefined);
|
||||
const parsed = new URL(fullPath, urlBase);
|
||||
const protocol = parsed.protocol || supportedProtocols[0];
|
||||
|
||||
if (protocol === 'data:') {
|
||||
@@ -842,7 +850,6 @@ export default isHttpAdapterSupported &&
|
||||
// cacheable-lookup integration hotfix
|
||||
!utils.isUndefined(lookup) && (options.lookup = lookup);
|
||||
|
||||
const socketPath = own('socketPath');
|
||||
if (socketPath) {
|
||||
if (typeof socketPath !== 'string') {
|
||||
return reject(
|
||||
|
||||
@@ -6368,9 +6368,10 @@ describe('supports http with nodejs', () => {
|
||||
: path.join(os.tmpdir(), `${pipe}.sock`);
|
||||
}
|
||||
|
||||
function startUnixServer(socketPath) {
|
||||
function startUnixServer(socketPath, onRequest) {
|
||||
return new Promise((resolveStart, rejectStart) => {
|
||||
const server = http.createServer((req, res) => {
|
||||
onRequest && onRequest(req);
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify({ ok: true, url: req.url }));
|
||||
});
|
||||
@@ -6409,6 +6410,61 @@ describe('supports http with nodejs', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('accepts a path-only url when socketPath is set (regression #6611)', async () => {
|
||||
const socketPath = makeSocketPath();
|
||||
const server = await startUnixServer(socketPath);
|
||||
try {
|
||||
const res = await axios.get('/echo?q=1', { socketPath });
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.data.ok, true);
|
||||
assert.strictEqual(res.data.url, '/echo?q=1');
|
||||
} finally {
|
||||
await stopUnixServer(server, socketPath);
|
||||
}
|
||||
});
|
||||
|
||||
it('accepts a path-only url when socketPath matches allowedSocketPaths', async () => {
|
||||
const socketPath = makeSocketPath();
|
||||
const server = await startUnixServer(socketPath);
|
||||
try {
|
||||
const res = await axios.get('/echo?q=1', {
|
||||
socketPath,
|
||||
allowedSocketPaths: [socketPath],
|
||||
});
|
||||
assert.strictEqual(res.status, 200);
|
||||
assert.strictEqual(res.data.ok, true);
|
||||
assert.strictEqual(res.data.url, '/echo?q=1');
|
||||
} finally {
|
||||
await stopUnixServer(server, socketPath);
|
||||
}
|
||||
});
|
||||
|
||||
it('ignores a prototype-polluted socketPath (security, regression #6611)', async () => {
|
||||
const socketPath = makeSocketPath();
|
||||
let requestCount = 0;
|
||||
const server = await startUnixServer(socketPath, () => {
|
||||
requestCount += 1;
|
||||
});
|
||||
// Pollute the prototype so `socketPath` is visible via the chain but is
|
||||
// NOT an own property of the request config.
|
||||
Object.prototype.socketPath = socketPath;
|
||||
try {
|
||||
// With no own socketPath, the polluted prototype value must not be
|
||||
// honored: the path-only url gets no synthetic base and the request is
|
||||
// never routed to the (attacker-controlled) socket, so it rejects
|
||||
// instead of silently connecting.
|
||||
await assert.rejects(axios.get('/echo?q=1'), (err) => {
|
||||
assert.ok(err instanceof Error);
|
||||
assert.strictEqual(err.code, AxiosError.ERR_INVALID_URL);
|
||||
return true;
|
||||
});
|
||||
assert.strictEqual(requestCount, 0);
|
||||
} finally {
|
||||
delete Object.prototype.socketPath;
|
||||
await stopUnixServer(server, socketPath);
|
||||
}
|
||||
});
|
||||
|
||||
it('allows socketPath when it matches an allowedSocketPaths string', async () => {
|
||||
const socketPath = makeSocketPath();
|
||||
const server = await startUnixServer(socketPath);
|
||||
|
||||
Reference in New Issue
Block a user