summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/http.md12
-rw-r--r--doc/api/http2.md10
-rw-r--r--lib/_http_client.js6
-rw-r--r--lib/_http_incoming.js2
-rw-r--r--lib/_http_server.js1
-rw-r--r--lib/internal/http2/compat.js7
-rw-r--r--test/parallel/test-http-aborted.js26
-rw-r--r--test/parallel/test-http2-compat-aborted.js27
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();
+ }));
+ }));
+}));