Skip to content
This repository was archived by the owner on Jul 6, 2018. It is now read-only.

Commit 6f3335f

Browse files
committed
Http2ServerResponse.createPushRequest
1 parent 0f16f94 commit 6f3335f

4 files changed

Lines changed: 147 additions & 103 deletions

lib/internal/http2/compat.js

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ class Http2ServerResponse extends Stream {
362362
setHeader(name, value) {
363363
var state = this[kState];
364364
if (state.headersSent)
365-
throw new Error('Cannot set status after the HTTP message has been sent');
365+
throw new Error('Cannot set headers after the HTTP message has been sent');
366366
name = String(name).trim().toLowerCase();
367367
assertValidHeader(name, value);
368368
var headers = this[kHeaders];
@@ -452,13 +452,13 @@ class Http2ServerResponse extends Stream {
452452
stream.respond(headers);
453453
}
454454

455-
createPushResponse(headers, options, callback) {
455+
createPushRequest(headers) {
456456
var stream = this[kStream];
457457
if (!stream) {
458-
callback(new Error('HTTP/2 Stream has been closed'));
459-
return;
458+
throw new Error('HTTP/2 Stream has been closed');
460459
}
461-
return stream.pushStream(headers, options, callback);
460+
var request = new Http2PushRequest(stream, headers);
461+
return request;
462462
}
463463

464464
[kBeginSend]() {
@@ -519,4 +519,41 @@ function onServerStream(stream, headers, flags) {
519519
server.emit('request', request, response);
520520
}
521521

522+
class Http2PushRequest {
523+
constructor(stream, headers) {
524+
this[kStream] = stream;
525+
this[kHeaders] = headers || Object.create(null);
526+
this[kState] = {
527+
headersSent: false
528+
};
529+
}
530+
531+
push(callback) {
532+
var state = this[kState];
533+
if (state.headersSent)
534+
throw new Error('Cannot push request headers ' +
535+
'after the HTTP message has been sent');
536+
var stream = this[kStream];
537+
if (!stream)
538+
throw new Error('HTTP/2 Stream has been closed');
539+
var headers = this[kHeaders];
540+
try {
541+
stream.pushStream(
542+
headers,
543+
function(error, promisedStream, headers, options) {
544+
if (error) {
545+
callback(error);
546+
return;
547+
}
548+
var response = new Http2ServerResponse(promisedStream);
549+
callback(null, response);
550+
}
551+
);
552+
state.headersSent = true;
553+
} catch (error) {
554+
callback(error);
555+
}
556+
}
557+
}
558+
522559
module.exports = { onServerStream };
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const h2 = require('http2');
6+
const net = require('net');
7+
8+
function isEven(number) {
9+
return number % 2 === 0;
10+
}
11+
12+
function isOdd(number) {
13+
return number % 2 === 1;
14+
}
15+
16+
// Push a request & response
17+
function requestListener(request, response) {
18+
return new Promise(function(resolve) {
19+
assert.ok(isOdd(response.stream.id));
20+
const headers = {
21+
':path': '/pushed',
22+
':method': 'GET',
23+
':scheme': 'http',
24+
':authority': 'localhost'
25+
};
26+
const pushRequest = response.createPushRequest(headers);
27+
pushRequest.push(common.mustCall(function(error, pushResponse) {
28+
assert.strictEqual(error, null);
29+
assert.ok(isEven(pushResponse.stream.id));
30+
pushResponse.end('This is a server-initiated response');
31+
response.end('This is a client-initiated response');
32+
resolve();
33+
}));
34+
});
35+
}
36+
37+
function clientRequest(client, socket) {
38+
const headers = {
39+
':path': '/',
40+
':method': 'GET',
41+
':scheme': 'http',
42+
':authority': 'localhost'
43+
};
44+
return new Promise(function(resolve) {
45+
const requestStream = client.request(headers);
46+
47+
// TODO seb: fix the missing promised stream id for the pushed stream
48+
// The PUSH_PROMISE frame is received in onHeaders.
49+
// Because the event payload lacks a Promised Stream ID the headers
50+
// are triggered as an event on the parent stream,
51+
// causing this test to fail.
52+
53+
function onStream(pushStream, headers, flags) {
54+
assert.strictEqual(headers[':status'], '200');
55+
assert.strictEqual(headers[':path'], '/pushed');
56+
assert.strictEqual(headers[':method'], 'GET');
57+
assert.strictEqual(headers[':scheme'], 'http');
58+
assert.strictEqual(headers[':authority'], 'localhost');
59+
assert.ok(headers['date']);
60+
assert.strictEqual(flags, h2.constants.NGHTTP2_FLAG_END_HEADERS);
61+
62+
pushStream.on('data', common.mustCall(function(data) {
63+
assert.strictEqual(data.toString(),
64+
'This is a server-initiated response');
65+
}));
66+
67+
pushStream.on('streamClosed', resolve);
68+
}
69+
requestStream.session.on('stream', common.mustCall(onStream));
70+
71+
requestStream.on('response', common.mustCall(function(headers, flags) {
72+
assert.strictEqual(headers[':status'], '200');
73+
assert.strictEqual(headers[':path'], '/');
74+
assert.strictEqual(headers[':method'], 'GET');
75+
assert.strictEqual(headers[':scheme'], 'http');
76+
assert.strictEqual(headers[':authority'], 'localhost');
77+
assert.ok(headers['date']);
78+
assert.strictEqual(flags, h2.constants.NGHTTP2_FLAG_END_HEADERS);
79+
}));
80+
81+
requestStream.on('data', common.mustCall(function(data) {
82+
assert.strictEqual(data.toString(),
83+
'This is a client-initiated response');
84+
}));
85+
});
86+
}
87+
88+
let socket;
89+
const stages = [];
90+
const server = h2.createServer();
91+
server.listen(0, common.mustCall(function() {
92+
console.log(server.address());
93+
server.once('request', common.mustCall(function(request, response) {
94+
stages.push(requestListener(request, response));
95+
Promise.all(stages)
96+
.then(function() {
97+
socket.destroy();
98+
server.close();
99+
});
100+
}));
101+
socket = net.connect(server.address(), common.mustCall(function() {
102+
const client = h2.createClientSession(socket);
103+
stages.push(clientRequest(client, socket));
104+
}));
105+
}));

test/parallel/test-http2-compat-Http2ServerResponse-createPushResponse.js

Lines changed: 0 additions & 95 deletions
This file was deleted.

test/parallel/test-http2-compat-Http2ServerResponse-writeHead.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ function requestListener(request, response) {
1212
response.setHeader('foo-bar', 'def456');
1313
response.writeHead(statusCode, headers);
1414
response.writeHead(statusCode, headers); // Idempotent
15-
16-
response.writeHead = common.mustCall(function mock() {});
17-
response.writeHeader(statusCode, headers);
1815
}
1916

2017
function clientRequest(client, socket) {

0 commit comments

Comments
 (0)