summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/http.md11
-rw-r--r--lib/_http_server.js7
-rw-r--r--test/parallel/test-http-header-overflow.js47
3 files changed, 62 insertions, 3 deletions
diff --git a/doc/api/http.md b/doc/api/http.md
index 7f0b39cbb1..149fc53668 100644
--- a/doc/api/http.md
+++ b/doc/api/http.md
@@ -829,6 +829,10 @@ changes:
description: The `rawPacket` is the current buffer that just parsed. Adding
this buffer to the error object of `'clientError'` event is to
make it possible that developers can log the broken packet.
+ - version: REPLACEME
+ pr-url: https://github.com/nodejs/node/pull/25605
+ description: The default behavior will return a 431 Request Header
+ Fields Too Large if a HPE_HEADER_OVERFLOW error occurs.
-->
* `exception` {Error}
@@ -839,8 +843,10 @@ Listener of this event is responsible for closing/destroying the underlying
socket. For example, one may wish to more gracefully close the socket with a
custom HTTP response instead of abruptly severing the connection.
-Default behavior is to close the socket with an HTTP '400 Bad Request' response
-if possible, otherwise the socket is immediately destroyed.
+Default behavior is to try close the socket with a HTTP '400 Bad Request',
+or a HTTP '431 Request Header Fields Too Large' in the case of a
+[`HPE_HEADER_OVERFLOW`][] error. If the socket is not writable it is
+immediately destroyed.
`socket` is the [`net.Socket`][] object that the error originated from.
@@ -2171,3 +2177,4 @@ not abort the request or do anything besides add a `'timeout'` event.
[`url.parse()`]: url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost
[Readable Stream]: stream.html#stream_class_stream_readable
[Stream]: stream.html#stream_stream
+[`HPE_HEADER_OVERFLOW`]: errors.html#errors_hpe_header_overflow
diff --git a/lib/_http_server.js b/lib/_http_server.js
index 24ebd41bb5..5a714da6b6 100644
--- a/lib/_http_server.js
+++ b/lib/_http_server.js
@@ -507,6 +507,9 @@ const noop = () => {};
const badRequestResponse = Buffer.from(
`HTTP/1.1 400 ${STATUS_CODES[400]}${CRLF}${CRLF}`, 'ascii'
);
+const requestHeaderFieldsTooLargeResponse = Buffer.from(
+ `HTTP/1.1 431 ${STATUS_CODES[431]}${CRLF}${CRLF}`, 'ascii'
+);
function socketOnError(e) {
// Ignore further errors
this.removeListener('error', socketOnError);
@@ -514,7 +517,9 @@ function socketOnError(e) {
if (!this.server.emit('clientError', e, this)) {
if (this.writable) {
- this.write(badRequestResponse);
+ const response = e.code === 'HPE_HEADER_OVERFLOW' ?
+ requestHeaderFieldsTooLargeResponse : badRequestResponse;
+ this.write(response);
}
this.destroy(e);
}
diff --git a/test/parallel/test-http-header-overflow.js b/test/parallel/test-http-header-overflow.js
new file mode 100644
index 0000000000..a9bf5cbfa0
--- /dev/null
+++ b/test/parallel/test-http-header-overflow.js
@@ -0,0 +1,47 @@
+'use strict';
+const assert = require('assert');
+const { createServer, maxHeaderSize } = require('http');
+const { createConnection } = require('net');
+const { expectsError, mustCall } = require('../common');
+
+const CRLF = '\r\n';
+const DUMMY_HEADER_NAME = 'Cookie: ';
+const DUMMY_HEADER_VALUE = 'a'.repeat(
+ // plus one is to make it 1 byte too big
+ maxHeaderSize - DUMMY_HEADER_NAME.length - (2 * CRLF.length) + 1
+);
+const PAYLOAD_GET = 'GET /blah HTTP/1.1';
+const PAYLOAD = PAYLOAD_GET + CRLF +
+ DUMMY_HEADER_NAME + DUMMY_HEADER_VALUE + CRLF.repeat(2);
+
+const server = createServer();
+
+server.on('connection', mustCall((socket) => {
+ socket.on('error', expectsError({
+ type: Error,
+ message: 'Parse Error',
+ code: 'HPE_HEADER_OVERFLOW',
+ bytesParsed: maxHeaderSize + PAYLOAD_GET.length,
+ rawPacket: Buffer.from(PAYLOAD)
+ }));
+}));
+
+server.listen(0, mustCall(() => {
+ const c = createConnection(server.address().port);
+ let received = '';
+
+ c.on('connect', mustCall(() => {
+ c.write(PAYLOAD);
+ }));
+ c.on('data', mustCall((data) => {
+ received += data.toString();
+ }));
+ c.on('end', mustCall(() => {
+ assert.strictEqual(
+ received,
+ 'HTTP/1.1 431 Request Header Fields Too Large\r\n\r\n'
+ );
+ c.end();
+ }));
+ c.on('close', mustCall(() => server.close()));
+}));