Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

http: added aborted property to request #20094

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 11 additions & 1 deletion doc/api/http.md
Expand Up @@ -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
Expand All @@ -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
Expand Down
10 changes: 10 additions & 0 deletions doc/api/http2.md
Expand Up @@ -2414,6 +2414,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 @@ -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.
Expand Down Expand Up @@ -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');
Expand Down
2 changes: 2 additions & 0 deletions lib/_http_incoming.js
Expand Up @@ -52,6 +52,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 @@ -444,6 +444,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 @@ -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,
Expand Down Expand Up @@ -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');
}
}
Expand Down Expand Up @@ -233,6 +235,7 @@ class Http2ServerRequest extends Readable {
this[kTrailers] = {};
this[kRawTrailers] = [];
this[kStream] = stream;
this[kAborted] = false;
stream[kProxySocket] = null;
stream[kRequest] = this;

Expand All @@ -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 ||
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

server should be closed or the test times out.

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();
}));
}));
}));