diff options
-rw-r--r-- | doc/api/http.md | 12 | ||||
-rw-r--r-- | doc/api/http2.md | 10 | ||||
-rw-r--r-- | lib/_http_client.js | 6 | ||||
-rw-r--r-- | lib/_http_incoming.js | 2 | ||||
-rw-r--r-- | lib/_http_server.js | 1 | ||||
-rw-r--r-- | lib/internal/http2/compat.js | 7 | ||||
-rw-r--r-- | test/parallel/test-http-aborted.js | 26 | ||||
-rw-r--r-- | test/parallel/test-http2-compat-aborted.js | 27 |
8 files changed, 89 insertions, 2 deletions
diff --git a/doc/api/http.md b/doc/api/http.md index d6f738cb81..d3e495ea3d 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -1483,7 +1483,7 @@ following additional events, methods, and properties. added: v0.3.8 --> -Emitted when the request has been aborted and the network socket has closed. +Emitted when the request has been aborted. ### Event: 'close' <!-- YAML @@ -1493,6 +1493,16 @@ added: v0.4.2 Indicates that the underlying connection was closed. Just like `'end'`, this event occurs only once per response. +### message.aborted +<!-- YAML +added: REPLACEME +--> + +* {boolean} + +The `message.aborted` property will be `true` if the request has +been aborted. + ### message.destroy([error]) <!-- YAML added: v0.3.0 diff --git a/doc/api/http2.md b/doc/api/http2.md index 084cc7ad37..c47d4c7e57 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -2417,6 +2417,16 @@ added: v8.4.0 Indicates that the underlying [`Http2Stream`][] was closed. Just like `'end'`, this event occurs only once per response. +#### request.aborted +<!-- YAML +added: REPLACEME +--> + +* {boolean} + +The `request.aborted` property will be `true` if the request has +been aborted. + #### request.destroy([error]) <!-- YAML added: v8.4.0 diff --git a/lib/_http_client.js b/lib/_http_client.js index 22ae85c927..04880182da 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -279,6 +279,7 @@ ClientRequest.prototype.abort = function abort() { if (!this.aborted) { process.nextTick(emitAbortNT.bind(this)); } + // Mark as aborting so we can avoid sending queued request data // This is used as a truthy flag elsewhere. The use of Date.now is for // debugging purposes only. @@ -330,7 +331,10 @@ function socketCloseListener() { var parser = socket.parser; if (req.res && req.res.readable) { // Socket closed before we emitted 'end' below. - if (!req.res.complete) req.res.emit('aborted'); + if (!req.res.complete) { + req.res.aborted = true; + req.res.emit('aborted'); + } var res = req.res; res.on('end', function() { res.emit('close'); diff --git a/lib/_http_incoming.js b/lib/_http_incoming.js index 55c196399c..23ac4d54be 100644 --- a/lib/_http_incoming.js +++ b/lib/_http_incoming.js @@ -54,6 +54,8 @@ function IncomingMessage(socket) { this.readable = true; + this.aborted = false; + this.upgrade = null; // request (server) only diff --git a/lib/_http_server.js b/lib/_http_server.js index bf228de643..9c8b5cb8fb 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -440,6 +440,7 @@ function socketOnClose(socket, state) { function abortIncoming(incoming) { while (incoming.length) { var req = incoming.shift(); + req.aborted = true; req.emit('aborted'); req.emit('close'); } diff --git a/lib/internal/http2/compat.js b/lib/internal/http2/compat.js index 0bdbe7b69f..d2aaa8838e 100644 --- a/lib/internal/http2/compat.js +++ b/lib/internal/http2/compat.js @@ -31,6 +31,7 @@ const kTrailers = Symbol('trailers'); const kRawTrailers = Symbol('rawTrailers'); const kProxySocket = Symbol('proxySocket'); const kSetHeader = Symbol('setHeader'); +const kAborted = Symbol('aborted'); const { HTTP2_HEADER_AUTHORITY, @@ -137,6 +138,7 @@ function onStreamDrain() { function onStreamAbortedRequest() { const request = this[kRequest]; if (request !== undefined && request[kState].closed === false) { + request[kAborted] = true; request.emit('aborted'); } } @@ -233,6 +235,7 @@ class Http2ServerRequest extends Readable { this[kTrailers] = {}; this[kRawTrailers] = []; this[kStream] = stream; + this[kAborted] = false; stream[kProxySocket] = null; stream[kRequest] = this; @@ -248,6 +251,10 @@ class Http2ServerRequest extends Readable { this.on('resume', onRequestResume); } + get aborted() { + return this[kAborted]; + } + get complete() { return this._readableState.ended || this[kState].closed || diff --git a/test/parallel/test-http-aborted.js b/test/parallel/test-http-aborted.js new file mode 100644 index 0000000000..c3d7e4641f --- /dev/null +++ b/test/parallel/test-http-aborted.js @@ -0,0 +1,26 @@ +'use strict'; + +const common = require('../common'); +const http = require('http'); +const assert = require('assert'); + +const server = http.createServer(common.mustCall(function(req, res) { + req.on('aborted', common.mustCall(function() { + assert.strictEqual(this.aborted, true); + server.close(); + })); + assert.strictEqual(req.aborted, false); + res.write('hello'); +})); + +server.listen(0, common.mustCall(() => { + const req = http.get({ + port: server.address().port, + headers: { connection: 'keep-alive' } + }, common.mustCall((res) => { + res.on('aborted', common.mustCall(() => { + assert.strictEqual(res.aborted, true); + })); + req.abort(); + })); +})); diff --git a/test/parallel/test-http2-compat-aborted.js b/test/parallel/test-http2-compat-aborted.js new file mode 100644 index 0000000000..01caf95f98 --- /dev/null +++ b/test/parallel/test-http2-compat-aborted.js @@ -0,0 +1,27 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const h2 = require('http2'); +const assert = require('assert'); + + +const server = h2.createServer(common.mustCall(function(req, res) { + req.on('aborted', common.mustCall(function() { + assert.strictEqual(this.aborted, true); + })); + assert.strictEqual(req.aborted, false); + res.write('hello'); + server.close(); +})); + +server.listen(0, common.mustCall(function() { + const url = `http://localhost:${server.address().port}`; + const client = h2.connect(url, common.mustCall(() => { + const request = client.request(); + request.on('data', common.mustCall((chunk) => { + client.destroy(); + })); + })); +})); |