2
0
mirror of https://github.com/tenrok/axios.git synced 2026-06-17 19:21:29 +03:00

fix: enforce max body length when max redirects is 0 (#10753)

This commit is contained in:
Jay
2026-04-18 15:45:42 +02:00
committed by GitHub
parent 48fd644be1
commit 1c7f6d76e5
2 changed files with 111 additions and 1 deletions
+35 -1
View File
@@ -967,7 +967,41 @@ export default isHttpAdapterSupported &&
}
});
data.pipe(req);
// Enforce maxBodyLength for streamed uploads on the native http/https
// transport (maxRedirects === 0); follow-redirects enforces it on the
// other path. See GHSA-5c9x-8gcm-mpgx.
let uploadStream = data;
if (config.maxBodyLength > -1 && config.maxRedirects === 0) {
const limit = config.maxBodyLength;
let bytesSent = 0;
uploadStream = stream.pipeline(
[
data,
new stream.Transform({
transform(chunk, _enc, cb) {
bytesSent += chunk.length;
if (bytesSent > limit) {
return cb(
new AxiosError(
'Request body larger than maxBodyLength limit',
AxiosError.ERR_BAD_REQUEST,
config,
req
)
);
}
cb(null, chunk);
},
}),
],
utils.noop
);
uploadStream.on('error', (err) => {
if (!req.destroyed) req.destroy(err);
});
}
uploadStream.pipe(req);
} else {
data && req.write(data);
req.end();
+76
View File
@@ -988,6 +988,82 @@ describe('supports http with nodejs', () => {
}
});
it('should enforce maxBodyLength for streamed uploads with maxRedirects: 0 (GHSA-5c9x-8gcm-mpgx)', async () => {
let bytesReceived = 0;
const server = await startHTTPServer(
(req, res) => {
req.on('data', (chunk) => {
bytesReceived += chunk.length;
});
req.on('end', () => {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ received: bytesReceived }));
});
},
{ port: SERVER_PORT }
);
try {
const size = 2 * 1024 * 1024;
const buf = Buffer.alloc(size, 0x61);
const source = stream.Readable.from([buf]);
await assert.rejects(
axios.post(`http://localhost:${server.address().port}/`, source, {
maxBodyLength: 1024,
maxRedirects: 0,
headers: { 'Content-Type': 'application/octet-stream' },
}),
(error) => {
assert.strictEqual(error.message, 'Request body larger than maxBodyLength limit');
return true;
}
);
assert.ok(
bytesReceived <= 1024 * 4,
`server should not receive full payload; got ${bytesReceived}`
);
} finally {
await stopHTTPServer(server);
}
});
it('should allow streamed uploads under maxBodyLength with maxRedirects: 0', async () => {
let bytesReceived = 0;
const server = await startHTTPServer(
(req, res) => {
req.on('data', (chunk) => {
bytesReceived += chunk.length;
});
req.on('end', () => {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ received: bytesReceived }));
});
},
{ port: SERVER_PORT }
);
try {
const payload = Buffer.alloc(512, 0x62);
const source = stream.Readable.from([payload]);
const response = await axios.post(
`http://localhost:${server.address().port}/`,
source,
{
maxBodyLength: 1024,
maxRedirects: 0,
headers: { 'Content-Type': 'application/octet-stream' },
}
);
assert.strictEqual(response.data.received, payload.length);
} finally {
await stopHTTPServer(server);
}
});
it('should properly support default max body length (follow-redirects as well)', async () => {
// Taken from follow-redirects defaults.
const followRedirectsMaxBodyDefaults = 10 * 1024 * 1024;