Skip to content

Commit

Permalink
http: added aborted property to request
Browse files Browse the repository at this point in the history
Backport-PR-URL: #22850
PR-URL: #20094
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
  • Loading branch information
ronag authored and BethGriggs committed Oct 16, 2018
1 parent 98ed30f commit 1edd7f6
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 2 deletions.
12 changes: 11 additions & 1 deletion doc/api/http.md
Expand Up @@ -1401,7 +1401,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
Expand All @@ -1411,6 +1411,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
Expand Down
10 changes: 10 additions & 0 deletions doc/api/http2.md
Expand Up @@ -2422,6 +2422,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
Expand Down
6 changes: 5 additions & 1 deletion lib/_http_client.js
Expand Up @@ -299,6 +299,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.
Expand Down Expand Up @@ -350,7 +351,10 @@ function socketCloseListener() {
req.emit('close');
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');
Expand Down
2 changes: 2 additions & 0 deletions lib/_http_incoming.js
Expand Up @@ -59,6 +59,8 @@ function IncomingMessage(socket) {

this.readable = true;

this.aborted = false;

this.upgrade = null;

// request (server) only
Expand Down
1 change: 1 addition & 0 deletions lib/_http_server.js
Expand Up @@ -436,6 +436,7 @@ function socketOnClose(socket, state) {
function abortIncoming(incoming) {
while (incoming.length) {
var req = incoming.shift();
req.aborted = true;
req.emit('aborted');
req.emit('close');
}
Expand Down
7 changes: 7 additions & 0 deletions lib/internal/http2/compat.js
Expand Up @@ -19,6 +19,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,
Expand Down Expand Up @@ -125,6 +126,7 @@ function onStreamDrain() {
function onStreamAbortedRequest() {
const request = this[kRequest];
if (request !== undefined && request[kState].closed === false) {
request[kAborted] = true;
request.emit('aborted');
}
}
Expand Down Expand Up @@ -221,6 +223,7 @@ class Http2ServerRequest extends Readable {
this[kTrailers] = {};
this[kRawTrailers] = [];
this[kStream] = stream;
this[kAborted] = false;
stream[kProxySocket] = null;
stream[kRequest] = this;

Expand All @@ -236,6 +239,10 @@ class Http2ServerRequest extends Readable {
this.on('resume', onRequestResume);
}

get aborted() {
return this[kAborted];
}

get complete() {
return this._readableState.ended ||
this[kState].closed ||
Expand Down
26 changes: 26 additions & 0 deletions 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();
}));
}));
27 changes: 27 additions & 0 deletions 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();
}));
}));
}));

0 comments on commit 1edd7f6

Please sign in to comment.