diff --git a/lib/internal/http2/compat.js b/lib/internal/http2/compat.js index 1fe118b20f..b16631e752 100644 --- a/lib/internal/http2/compat.js +++ b/lib/internal/http2/compat.js @@ -416,8 +416,18 @@ class Http2ServerResponse extends Stream { write(chunk, encoding, cb) { var stream = this[kStream]; + + if (typeof encoding === 'function') { + cb = encoding; + encoding = 'utf8'; + } + if (stream === undefined) { - cb(new Error('HTTP/2 Stream has been closed')); + var err = new Error('HTTP/2 Stream has been closed'); + if (cb) + cb(err); + else + this.emit('error', err); return; } var beginSend = this[kBeginSend]; diff --git a/test/parallel/test-http2-compat-serverresponse-write-no-cb.js b/test/parallel/test-http2-compat-serverresponse-write-no-cb.js new file mode 100644 index 0000000000..7d7aaa9d2d --- /dev/null +++ b/test/parallel/test-http2-compat-serverresponse-write-no-cb.js @@ -0,0 +1,95 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const h2 = require('http2'); + +// Http2ServerResponse.write does not imply there is a callback + +{ + const server = h2.createServer(); + server.listen(0, common.mustCall(function() { + const port = server.address().port; + const url = `http://localhost:${port}`; + const client = h2.connect(url, common.mustCall(function() { + const headers = { + ':path': '/', + ':method': 'GET', + ':scheme': 'http', + ':authority': `localhost:${port}` + }; + const request = client.request(headers); + request.end(); + request.resume(); + })); + + server.once('request', common.mustCall(function(request, response) { + client.destroy(); + response.stream.session.on('close', common.mustCall(function() { + response.on('error', common.mustCall(function(err) { + assert.strictEqual(err.message, 'HTTP/2 Stream has been closed'); + })); + response.write('muahaha'); + server.close(); + })); + })); + })); +} + +{ + const server = h2.createServer(); + server.listen(0, common.mustCall(function() { + const port = server.address().port; + const url = `http://localhost:${port}`; + const client = h2.connect(url, common.mustCall(function() { + const headers = { + ':path': '/', + ':method': 'get', + ':scheme': 'http', + ':authority': `localhost:${port}` + }; + const request = client.request(headers); + request.end(); + request.resume(); + })); + + server.once('request', common.mustCall(function(request, response) { + client.destroy(); + response.stream.session.on('close', common.mustCall(function() { + response.write('muahaha', common.mustCall(function(err) { + assert.strictEqual(err.message, 'HTTP/2 Stream has been closed'); + })); + server.close(); + })); + })); + })); +} + +{ + const server = h2.createServer(); + server.listen(0, common.mustCall(function() { + const port = server.address().port; + const url = `http://localhost:${port}`; + const client = h2.connect(url, common.mustCall(function() { + const headers = { + ':path': '/', + ':method': 'get', + ':scheme': 'http', + ':authority': `localhost:${port}` + }; + const request = client.request(headers); + request.end(); + request.resume(); + })); + + server.once('request', common.mustCall(function(request, response) { + response.stream.session.on('close', common.mustCall(function() { + response.write('muahaha', 'utf8', common.mustCall(function(err) { + assert.strictEqual(err.message, 'HTTP/2 Stream has been closed'); + })); + server.close(); + })); + client.destroy(); + })); + })); +}