Skip to content

Commit 055dca1

Browse files
yosuke-furukawajasnell
authored andcommitted
http2: add server push event for client
PR-URL: nodejs#95 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 804db8e commit 055dca1

2 files changed

Lines changed: 63 additions & 1 deletion

File tree

lib/internal/http2/core.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,14 @@ function onSessionHeaders(id, cat, flags, headers) {
105105
return;
106106
}
107107

108+
if (cat === NGHTTP2_HCAT_PUSH_RESPONSE) {
109+
if (stream === undefined) {
110+
stream = new ClientHttp2Stream(owner, { });
111+
streams.set(id, stream);
112+
}
113+
owner.emit('push', stream, headers, flags);
114+
}
115+
108116
let event;
109117
switch (cat) {
110118
case NGHTTP2_HCAT_RESPONSE:
@@ -149,7 +157,9 @@ function onSessionStreamClose(id, code) {
149157
const state = owner[kState];
150158
const streams = state.streams;
151159
const stream = streams.get(id);
152-
assert(stream, 'Internal HTTP/2 Failure. Stream does not exist.');
160+
const alreadyClosed = stream === undefined;
161+
if (alreadyClosed)
162+
return;
153163
timers._unrefActive(this); // Unref the session timer
154164
timers._unrefActive(stream); // Unref the stream timer
155165
// Notify the stream that it has been closed.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const http2 = require('http2');
6+
7+
const server = http2.createServer();
8+
server.on('stream', common.mustCall((stream, headers, flags) => {
9+
const port = server.address().port;
10+
if (headers[':path'] === '/') {
11+
stream.pushStream({
12+
':scheme': 'http',
13+
':path': '/foobar',
14+
':authority': `localhost:${port}`,
15+
}, (stream, headers) => {
16+
stream.respond({
17+
'content-type': 'text/html',
18+
':status': 200,
19+
'x-push-data': 'pushed by server',
20+
});
21+
stream.end('pushed by server data');
22+
});
23+
}
24+
stream.respond({
25+
'content-type': 'text/html',
26+
':status': 200
27+
});
28+
stream.end('test');
29+
}));
30+
31+
server.listen(0, common.mustCall(() => {
32+
const port = server.address().port;
33+
const headers = { ':path': '/' };
34+
const client = http2.connect(`http://localhost:${port}`);
35+
const req = client.request(headers);
36+
37+
client.on('push', common.mustCall((stream, headers, flag) => {
38+
assert.strictEqual(headers[':status'], '200');
39+
assert.strictEqual(headers['content-type'], 'text/html');
40+
assert.strictEqual(headers['x-push-data'], 'pushed by server');
41+
}));
42+
43+
let data = '';
44+
45+
req.on('data', common.mustCall((d) => data += d));
46+
req.on('end', common.mustCall(() => {
47+
assert.strictEqual(data, 'test');
48+
server.close();
49+
client.destroy();
50+
}));
51+
req.end();
52+
}));

0 commit comments

Comments
 (0)