nodejs / http2 Goto Github PK
View Code? Open in Web Editor NEWWorking on an HTTP/2 implementation for Node.js Core
License: Other
Working on an HTTP/2 implementation for Node.js Core
License: Other
I am using http2 in a project that is using SSL from Let's encrypt.
If i use http2 i get this error, instead if i switch over https module all work good.
(node:60502) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 close listeners added. Use emitter.setMaxListeners() to increase limit
This works:
function onStream (stream) {
stream.respond({
':status': 200,
'content-type': 'text/html'
})
stream.end('<html><head></head><body><h1>this is some data</h2></body></html>');
}
This doesn't:
function onStream (stream) {
stream.respond({
'content-type': 'text/html',
':status': 200
})
stream.end('<html><head></head><body><h1>this is some data</h2></body></html>');
}
This is the output
$ nghttp -v http://localhost:8000/hello
[ 0.003] Connected
[ 0.003] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[ 0.003] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
(dep_stream_id=0, weight=201, exclusive=0)
[ 0.003] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
(dep_stream_id=0, weight=101, exclusive=0)
[ 0.003] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
(dep_stream_id=0, weight=1, exclusive=0)
[ 0.003] send PRIORITY frame <length=5, flags=0x00, stream_id=9>
(dep_stream_id=7, weight=1, exclusive=0)
[ 0.003] send PRIORITY frame <length=5, flags=0x00, stream_id=11>
(dep_stream_id=3, weight=1, exclusive=0)
[ 0.003] send HEADERS frame <length=44, flags=0x25, stream_id=13>
; END_STREAM | END_HEADERS | PRIORITY
(padlen=0, dep_stream_id=11, weight=16, exclusive=0)
; Open new stream
:method: GET
:path: /hello
:scheme: http
:authority: localhost:8000
accept: */*
accept-encoding: gzip, deflate
user-agent: nghttp2/1.17.0
[ 0.007] recv SETTINGS frame <length=0, flags=0x00, stream_id=0>
(niv=0)
[ 0.007] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[ 0.007] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[ 0.016] recv (stream_id=13) content-type: text/html
[ 0.016] [ERROR] Invalid HTTP header field was received: frame type: 1, stream: 13, name: [:status], value: [200]
[ 0.016] [INVALID; error=Invalid HTTP header field was received] recv HEADERS frame <length=34, flags=0x04, stream_id=13>
; END_HEADERS
(padlen=0)
; First response header
[ 0.016] send RST_STREAM frame <length=4, flags=0x00, stream_id=13>
(error_code=PROTOCOL_ERROR(0x01))
[ 0.016] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
(last_stream_id=0, error_code=NO_ERROR(0x00), opaque_data(0)=[])
Some requests were not processed. total=1, processed=0
cc @jasnell I think we should send :status
before everything
Now that we have quite a few more people looking at this and looking to contribute, we should start formalizing the process. I talked about some of this at the collaborator summit meeting yesterday, so I apologize if it's a repeat for some of you.
Up to this point, it's largely been @mcollina and I working on this so we hadn't been following a more formal review and sign off process. Now that there are more of us, we'll do the sign off on PRs like we do in core. We may not need to wait the full 48 hours to land stuff, but we still will need sign off before landing things.
Force pushes to master will happen. I will only do these when either (a) rebasing nodejs/http2 master with nodejs/node master to keep things up to date or (b) squashing commits to clean up the history (see item 3 below).
For the most part, we're going to start maintaining separate commits rather than squashing those down like we have been. This will ensure a proper history to be maintained, which will be important once we get around to opening the PR to nodejs/master. That said, there are no doubt going to be smaller commits that can be squashed (usually small trivial type fixes). If you're ok with your commits being squashed into the history. Put (Squash)
in some way in the commit message and I'll use that as a guide.
We have the nodejs/http2 team that will have commit rights to this repo. If you'd like to join that team, let either myself or @mcollina know and we'll get you added.
A number of tracking issues with the outstanding todos have been opened following the discussion at collab summit yesterday. These do not yet have a lot of detail in them and I will be working to fill out that detail. These will be he ideal areas of jumping in to help. If you'd like to work on a particular area, please drop a comment into the thread so that others know what you're working on in order to avoid accidentally duplicating work.
I will be scheduling a weekly status hangout to discuss ongoing progress. I have no idea what times will work yet. Expect a doodle poll to be posted.
https://tools.ietf.org/html/rfc7540#section-8.3 of the spec has a whole list of requirements for implementing the CONNECT
method properly. I have yet to look at those at all.
cc: @jasnell, @mcollina, @addaleax
I start working on the test list today, I will be updating the list while gathering more information. I'm open the issue that way everyone can give feedback about what should be in/out/priority, etc...
On several of the linux images in CI, we're getting segfaults in test/parallel/test-async-wrap-check-providers: https://ci.nodejs.org/job/node-test-commit-linux/9842/nodes=ubuntu1610-x64/console
not ok 6 parallel/test-async-wrap-check-providers
---
duration_ms: 0.711
severity: fail
stack: |-
*** Error in `out/Release/node': free(): invalid pointer: 0x000055abb0dd4218 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x790cb)[0x7f007c9970cb]
/lib/x86_64-linux-gnu/libc.so.6(+0x8275a)[0x7f007c9a075a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f007c9a418c]
out/Release/node(_ZN2v88internal11MemoryChunk20ReleaseOldToNewSlotsEv+0x16d)[0x55abae787d0d]
out/Release/node(_ZN2v88internal11MemoryChunk22ReleaseAllocatedMemoryEv+0x52)[0x55abae787fa2]
out/Release/node(_ZN2v88internal15MemoryAllocator17PerformFreeMemoryEPNS0_11MemoryChunkE+0x1b)[0x55abae78804b]
out/Release/node(_ZN2v88internal10PagedSpace8TearDownEv+0x45)[0x55abae788825]
out/Release/node(_ZN2v88internal8OldSpaceD0Ev+0x19)[0x55abae7229c9]
out/Release/node(_ZN2v88internal4Heap8TearDownEv+0x2d7)[0x55abae737177]
out/Release/node(_ZN2v88internal7Isolate6DeinitEv+0x1d9)[0x55abae8150a9]
out/Release/node(_ZN2v88internal7Isolate8TearDownEv+0x53)[0x55abae8152f3]
out/Release/node(_ZN4node5StartEP9uv_loop_siPKPKciS5_+0xdc7)[0x55abaed05a97]
out/Release/node(_ZN4node5StartEiPPc+0x11c)[0x55abaed0034c]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f007c93e3f1]
out/Release/node(_start+0x2a)[0x55abae09fa1a]
======= Memory map: ========
acbb9880000-acbb9900000 ---p 00000000 00:00 0
c2e1ba00000-c2e1ba80000 ---p 00000000 00:00 0
100d88880000-100d88885000 rw-p 00000000 00:00 0
100d88885000-100d88900000 ---p 00000000 00:00 0
105e49387000-105e49580000 ---p 00000000 00:00 0
105e49580000-105e49583000 rw-p 00000000 00:00 0
105e49583000-105e49584000 ---p 00000000 00:00 0
105e49584000-105e495fe000 rwxp 00000000 00:00 0
105e495fe000-105e49600000 ---p 00000000 00:00 0
105e49600000-105e49603000 rw-p 00000000 00:00 0
105e49603000-105e49604000 ---p 00000000 00:00 0
105e49604000-105e49674000 rwxp 00000000 00:00 0
105e49674000-105e49680000 ---p 00000000 00:00 0
105e49680000-105e49683000 rw-p 00000000 00:00 0
105e49683000-105e49684000 ---p 00000000 00:00 0
105e49684000-105e496ff000 rwxp 00000000 00:00 0
105e496ff000-105e49700000 ---p 00000000 00:00 0
105e49700000-105e49703000 rw-p 00000000 00:00 0
105e49703000-105e49704000 ---p 00000000 00:00 0
105e49704000-105e4977f000 rwxp 00000000 00:00 0
105e4977f000-105e69387000 ---p 00000000 00:00 0
15d002e00000-15d002e80000 ---p 00000000 00:00 0
1a7f63400000-1a7f63480000 ---p 00000000 00:00 0
1e9256500000-1e9256580000 ---p 00000000 00:00 0
230d93f80000-230d94000000 ---p 00000000 00:00 0
24363b500000-24363b580000 rw-p 00000000 00:00 0
305658b00000-305658b80000 ---p 00000000 00:00 0
34938d480000-34938d500000 rw-p 00000000 00:00 0
370310c53000-370310c54000 ---p 00000000 00:00 0
370310c54000-370310c5c000 rw-p 00000000 00:00 0
370310c5c000-370310c5f000 ---p 00000000 00:00 0
3de472d80000-3de472e00000 ---p 00000000 00:00 0
55abadafd000-55abaf993000 r-xp 00000000 fd:01 1074288 /home/iojs/build/workspace/node-test-commit-linux/nodes/ubuntu1610-x64/out/Release/node
55abafb93000-55abafc1d000 r--p 01e96000 fd:01 1074288 /home/iojs/build/workspace/node-test-commit-linux/nodes/ubuntu1610-x64/out/Release/node
55abafc1d000-55abafc37000 rw-p 01f20000 fd:01 1074288 /home/iojs/build/workspace/node-test-commit-linux/nodes/ubuntu1610-x64/out/Release/node
55abafc37000-55abafc50000 rw-p 00000000 00:00 0
55abb0bb5000-55abb0e19000 rw-p 00000000 00:00 0 [heap]
7f005c000000-7f005c021000 rw-p 00000000 00:00 0
7f005c021000-7f0060000000 ---p 00000000 00:00 0
7f0060000000-7f0060021000 rw-p 00000000 00:00 0
7f0060021000-7f0064000000 ---p 00000000 00:00 0
7f0064000000-7f0064021000 rw-p 00000000 00:00 0
7f0064021000-7f0068000000 ---p 00000000 00:00 0
7f0068000000-7f0068021000 rw-p 00000000 00:00 0
7f0068021000-7f006c000000 ---p 00000000 00:00 0
7f006c000000-7f006c021000 rw-p 00000000 00:00 0
7f006c021000-7f0070000000 ---p 00000000 00:00 0
7f0070000000-7f0070021000 rw-p 00000000 00:00 0
7f0070021000-7f0074000000 ---p 00000000 00:00 0
7f0074000000-7f0074021000 rw-p 00000000 00:00 0
7f0074021000-7f0078000000 ---p 00000000 00:00 0
7f0078704000-7f007870f000 r-xp 00000000 fd:01 24067 /lib/x86_64-linux-gnu/libnss_files-2.24.so
7f007870f000-7f007890e000 ---p 0000b000 fd:01 24067 /lib/x86_64-linux-gnu/libnss_files-2.24.so
7f007890e000-7f007890f000 r--p 0000a000 fd:01 24067 /lib/x86_64-linux-gnu/libnss_files-2.24.so
7f007890f000-7f0078910000 rw-p 0000b000 fd:01 24067 /lib/x86_64-linux-gnu/libnss_files-2.24.so
7f0078910000-7f0078916000 rw-p 00000000 00:00 0
7f0078916000-7f0078917000 ---p 00000000 00:00 0
7f0078917000-7f0079117000 rw-p 00000000 00:00 0
7f0079117000-7f0079118000 ---p 00000000 00:00 0
7f0079118000-7f0079918000 rw-p 00000000 00:00 0
7f0079918000-7f0079919000 ---p 00000000 00:00 0
7f0079919000-7f007a119000 rw-p 00000000 00:00 0
7f007a119000-7f007a11a000 ---p 00000000 00:00 0
7f007a11a000-7f007a91a000 rw-p 00000000 00:00 0
7f007a91a000-7f007a91b000 ---p 00000000 00:00 0
7f007a91b000-7f007b11b000 rw-p 00000000 00:00 0
7f007b11b000-7f007b11c000 ---p 00000000 00:00 0
7f007b11c000-7f007b91c000 rw-p 00000000 00:00 0
7f007b91c000-7f007b91d000 ---p 00000000 00:00 0
7f007b91d000-7f007c11d000 rw-p 00000000 00:00 0
7f007c11d000-7f007c11e000 ---p 00000000 00:00 0
7f007c11e000-7f007c91e000 rw-p 00000000 00:00 0
7f007c91e000-7f007cadb000 r-xp 00000000 fd:01 24057 /lib/x86_64-linux-gnu/libc-2.24.so
7f007cadb000-7f007ccdb000 ---p 001bd000 fd:01 24057 /lib/x86_64-linux-gnu/libc-2.24.so
7f007ccdb000-7f007ccdf000 r--p 001bd000 fd:01 24057 /lib/x86_64-linux-gnu/libc-2.24.so
7f007ccdf000-7f007cce1000 rw-p 001c1000 fd:01 24057 /lib/x86_64-linux-gnu/libc-2.24.so
7f007cce1000-7f007cce5000 rw-p 00000000 00:00 0
7f007cce5000-7f007ccfd000 r-xp 00000000 fd:01 24072 /lib/x86_64-linux-gnu/libpthread-2.24.so
7f007ccfd000-7f007cefd000 ---p 00018000 fd:01 24072 /lib/x86_64-linux-gnu/libpthread-2.24.so
7f007cefd000-7f007cefe000 r--p 00018000 fd:01 24072 /lib/x86_64-linux-gnu/libpthread-2.24.so
7f007cefe000-7f007ceff000 rw-p 00019000 fd:01 24072 /lib/x86_64-linux-gnu/libpthread-2.24.so
7f007ceff000-7f007cf03000 rw-p 00000000 00:00 0
7f007cf03000-7f007cf19000 r-xp 00000000 fd:01 1908 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f007cf19000-7f007d118000 ---p 00016000 fd:01 1908 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f007d118000-7f007d119000 r--p 00015000 fd:01 1908 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f007d119000-7f007d11a000 rw-p 00016000 fd:01 1908 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f007d11a000-7f007d222000 r-xp 00000000 fd:01 24061 /lib/x86_64-linux-gnu/libm-2.24.so
7f007d222000-7f007d421000 ---p 00108000 fd:01 24061 /lib/x86_64-linux-gnu/libm-2.24.so
7f007d421000-7f007d422000 r--p 00107000 fd:01 24061 /lib/x86_64-linux-gnu/libm-2.24.so
7f007d422000-7f007d423000 rw-p 00108000 fd:01 24061 /lib/x86_64-linux-gnu/libm-2.24.so
7f007d423000-7f007d59b000 r-xp 00000000 fd:01 6389 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22
7f007d59b000-7f007d79b000 ---p 00178000 fd:01 6389 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22
7f007d79b000-7f007d7a5000 r--p 00178000 fd:01 6389 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22
7f007d7a5000-7f007d7a7000 rw-p 00182000 fd:01 6389 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22
7f007d7a7000-7f007d7ab000 rw-p 00000000 00:00 0
7f007d7ab000-7f007d7b2000 r-xp 00000000 fd:01 24074 /lib/x86_64-linux-gnu/librt-2.24.so
7f007d7b2000-7f007d9b1000 ---p 00007000 fd:01 24074 /lib/x86_64-linux-gnu/librt-2.24.so
7f007d9b1000-7f007d9b2000 r--p 00006000 fd:01 24074 /lib/x86_64-linux-gnu/librt-2.24.so
7f007d9b2000-7f007d9b3000 rw-p 00007000 fd:01 24074 /lib/x86_64-linux-gnu/librt-2.24.so
7f007d9b3000-7f007d9b6000 r-xp 00000000 fd:01 24060 /lib/x86_64-linux-gnu/libdl-2.24.so
7f007d9b6000-7f007dbb5000 ---p 00003000 fd:01 24060 /lib/x86_64-linux-gnu/libdl-2.24.so
7f007dbb5000-7f007dbb6000 r--p 00002000 fd:01 24060 /lib/x86_64-linux-gnu/libdl-2.24.so
7f007dbb6000-7f007dbb7000 rw-p 00003000 fd:01 24060 /lib/x86_64-linux-gnu/libdl-2.24.so
7f007dbb7000-7f007dbdc000 r-xp 00000000 fd:01 24053 /lib/x86_64-linux-gnu/ld-2.24.so
7f007ddca000-7f007ddd0000 rw-p 00000000 00:00 0
7f007ddd3000-7f007ddd4000 rw-p 00000000 00:00 0
7f007ddd4000-7f007ddd5000 ---p 00000000 00:00 0
7f007ddd5000-7f007dddb000 rw-p 00000000 00:00 0
7f007dddb000-7f007dddc000 r--p 00024000 fd:01 24053 /lib/x86_64-linux-gnu/ld-2.24.so
7f007dddc000-7f007dddd000 rw-p 00025000 fd:01 24053 /lib/x86_64-linux-gnu/ld-2.24.so
7f007dddd000-7f007ddde000 rw-p 00000000 00:00 0
7ffcb3126000-7ffcb3147000 rw-p 00000000 00:00 0 [stack]
7ffcb3164000-7ffcb3166000 r--p 00000000 00:00 0 [vvar]
7ffcb3166000-7ffcb3168000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
...
REPL has 'http' and 'https' as built-in libraries.
But 'http2' is not included.
For anyone who wants to take on the challenge of implementing support for automatic upgrades from HTTP/1 to HTTP/2, here are the basic requirements from the spec:
Starting HTTP/2 for "http" URIs
A client that makes a request for an "http" URI without prior knowledge about support for HTTP/2 on the next hop uses the HTTP Upgrade mechanism (Section 6.7 of [RFC7230]). The client does so by making an HTTP/1.1 request that includes an Upgrade header field with the "h2c" token. Such an HTTP/1.1 request MUST include exactly one HTTP2-Settings (Section 3.2.1) header field.
For example:
GET / HTTP/1.1
Host: server.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
Requests that contain a payload body MUST be sent in their entirety before the client can send HTTP/2 frames. This means that a large request can block the use of the connection until it is completely sent.
If concurrency of an initial request with subsequent requests is important, an OPTIONS request can be used to perform the upgrade to HTTP/2, at the cost of an additional round trip.
A server that does not support HTTP/2 can respond to the request as though the Upgrade header field were absent:
HTTP/1.1 200 OK
Content-Length: 243
Content-Type: text/html
...
A server MUST ignore an "h2" token in an Upgrade header field. Presence of a token with "h2" implies HTTP/2 over TLS, which is instead negotiated as described in Section 3.3.
A server that supports HTTP/2 accepts the upgrade with a 101 (Switching Protocols) response. After the empty line that terminates the 101 response, the server can begin sending HTTP/2 frames. These frames MUST include a response to the request that initiated the upgrade.
For example:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
[ HTTP/2 connection ...
The first HTTP/2 frame sent by the server MUST be a server connection preface (Section 3.5) consisting of a SETTINGS frame (Section 6.5). Upon receiving the 101 response, the client MUST send a connection preface (Section 3.5), which includes a SETTINGS frame.
The HTTP/1.1 request that is sent prior to upgrade is assigned a stream identifier of 1 (see Section 5.1.1) with default priority values (Section 5.3.5). Stream 1 is implicitly "half-closed" from the client toward the server (see Section 5.1), since the request is completed as an HTTP/1.1 request. After commencing the HTTP/2 connection, stream 1 is used for the response.
As far as implementation is concerned, the upgrade path can essentially be handled either as a special handler for the 'upgrade'
event or as a special case inside the existing HTTP implementation.
As titled, we need a bunch of tests (and probably bug fix) for trailers. Who wants to add those?
This method is not covered: https://github.com/nodejs/http2/blob/master/lib/internal/http2/compat.js#L316
I'm trying to add "delayed open" scenario, and I am trying to create an Http2Stream
before we have a connected socket.
I have a prototype that defers handle.consume(socket._handle._externalStream);
, but then I get into:
frame #0: 0x00000001009ab8b0 node`node::http2::Http2Session::Send(this=0x0000000103803400, buf=0x00000001023292d0, length=58) + 38 at node_http2.cc:697 [opt]
694 void Http2Session::Send(uv_buf_t* buf,
695 size_t length) {
696 // Do not attempt to write data if the stream is not alive or is closing
-> 697 if (stream_ == nullptr || !stream_->IsAlive() || stream_->IsClosing()) {
698 return;
699 }
700
@jasnell do you think what I am trying to achieve is feasible?
The status code is a string now, not of type number any more.
Apart from the compat change, from a user perspective its a bit unhandy to get back the statuscode as a string, as you have to cast it before you make something like:
if (statusCode >= 200) { // todo ... }
Example for failing, ported http1 test:
'use strict';
const common = require('../common');
const assert = require('assert');
const http2 = require('http2');
const server = http2.createServer(function(request, response) {
console.log('responding to ' + request.url);
response.writeHead(200, {'Content-Type': 'text/plain'});
response.write('1\n');
response.write('');
response.write('2\n');
response.write('');
response.end('3\n');
this.close();
});
server.listen(0, common.mustCall(function() {
const client = http2.connect(`http://localhost:${this.address().port}`);
const headers = { ':path': '/' };
const req = client.request(headers).setEncoding('ascii');
let response = '';
req.on('response', (headers) => {
assert.strictEqual(200, headers[':status']);
});
req.on('data', function(chunk) {
response += chunk;
});
req.on('end', common.mustCall(function(a,b,c) {
assert.strictEqual('1\n2\n3\n', response);
}));
req.end();
}));
fails with:
assert.js:86
throw new assert.AssertionError({
^
AssertionError: 200 === '200'
at ClientHttp2Stream.req.on (/Users/robert/projects/http2/test/parallel/test-http2-write-empty-string.js:30:12)
at emitTwo (events.js:125:13)
at ClientHttp2Stream.emit (events.js:213:7)
at Http2Session.onSessionHeaders [as onheaders] (internal/http2/core.js:194:12)
node -v 6.9.2
One error
Debug: internal, implementation, error
Error: Sending illegal frame (DATA) in CLOSED state.
at Stream.transition [as _transition] (/var/www/revizor-game.ru/node_modules/http2/lib/protocol/stream.js:628:33)
at Stream._finishing (/var/www/revizor-game.ru/node_modules/http2/lib/protocol/stream.js:349:10)
at emitNone (events.js:67:13)
at Stream.emit (events.js:166:7)
at finishMaybe (_stream_writable.js:468:14)
at endWritable (_stream_writable.js:478:3)
at Stream.Writable.end (_stream_writable.js:443:5)
at OutgoingResponse._finish (/var/www/revizor-game.ru/node_modules/http2/lib/http.js:352:17)
at emitNone (events.js:72:20)
at OutgoingResponse.emit (events.js:166:7)
at finishMaybe (_stream_writable.js:468:14)
at endWritable (_stream_writable.js:478:3)
at OutgoingResponse.Writable.end (_stream_writable.js:443:5)
at OutgoingResponse.end (/var/www/revizor-game.ru/node_modules/http2/lib/http.js:753:40)
at ReadStream.onend (_stream_readable.js:490:10)
at ReadStream.g (events.js:260:16)
second
Debug: internal, implementation, error
AssertionError: false == true
at Connection._send (/var/www/revizor-game.ru/node_modules/http2/lib/protocol/connection.js:326:9)
at runCallback (timers.js:637:20)
at tryOnImmediate (timers.js:610:5)
at processImmediate [as _immediateCallback] (timers.js:582:5)
My server.js
$lib.s = new Hapi.Server();
var listener = http2.createServer({
key: fs.readFileSync('/var/www/revizor-game.ru.key', 'utf8'),
cert: fs.readFileSync('/var/www/ca.crt', 'utf8'),
pfx: fs.readFileSync('/var/www/pfx.pfx')
});
$lib.s.connection({
listener: listener,
host: 'revizor-game.ru',
port: 443,
tls: true
// tls: {
// key: fs.readFileSync('/var/www/revizor-game.ru.key', 'utf8'),
// cert: fs.readFileSync('/var/www/ca.crt', 'utf8')
// }
});
and boot.js (clustering) - http://pastebin.com/YzGsJVUk
Command: h2load -n 1000 http://localhost:8000/
.
Error:
assert.js:86
throw new assert.AssertionError({
^
AssertionError: Internal HTTP/2 Failure. Stream does not exist.
at Http2Session.onSessionStreamClose [as onstreamclose] (internal/http2/core.js:152:3)
The reason this happens is because onSessionStreamClose
is called after onSessionClose
.
server:
const fs = require('fs');
const http2 = require('http2');
const options = {
key: fs.readFileSync('./key.pem'),
cert: fs.readFileSync('./cert.pem')
};
function handler(req, res) {
res.writeHead(200, {'content-type': 'text/html'});
res.end('<html><head></head><body><h1>this is some data</h2></body></html>');
}
function onStream (stream) {
stream.respond({
'content-type': 'text/html',
':status': 200
})
stream.end('<html><head></head><body><h1>this is some data</h2></body></html>');
}
const server = http2.createServer(options);
// server.on('request', handler)
server.on('stream', onStream)
server.setTimeout(10 * 1000);
server.listen(8000);
process.on('SIGINT', quit)
process.on('SIGHUP', quit)
process.on('SIGTERM', quit)
function quit () {
server.close()
console.log('closing server')
process.exit(0)
}
Issue was submitted by mistake and moved to appropriate section.
Issue was submitted by mistake and moved to appropriate section.
As titled, memory usage grows as more data is pushed.
The set-cookie
header may appear multiple times. Its values should be handled as an Array in all response header methods.
To me it looks getting the path and/or headers is broken:
internal/http2/compat.js:253
return headers.get(constants.HTTP2_HEADER_PATH);
^
TypeError: Cannot read property 'get' of undefined
at Http2ServerRequest.get path [as path] (internal/http2/compat.js:253:19)
at Http2Server.http2.createServer (/Users/robert/projects/http2/test/parallel/test-http2-set-cookies.js:31:18)
at emitTwo (events.js:125:13)
at Http2Server.emit (events.js:213:7)
at Http2Server.onServerStream (internal/http2/compat.js:501:10)
at emitThree (events.js:135:13)
at Http2Server.emit (events.js:216:7)
at Http2Session.sessionOnStream (internal/http2/core.js:1035:10)
at emitThree (events.js:135:13)
at Http2Session.emit (events.js:216:7)
still haven't found out if the client doesn't send a path in general or if the issue is on the server side
'use strict';
require('../common');
const assert = require('assert');
const http2 = require('http2');
const server = http2.createServer((req, res) => {
console.log(req.path)
});
server.listen(0);
server.on('listening', function() {
const client = http2.connect(`http://localhost:${this.address().port}`);
const headers = { ':path': '/' };
const req = client.request(headers).setEncoding('utf8');
});
process.on('exit', function() {
assert.strictEqual(2, nresponses);
});
depends on #75 -- without #75 a request crashes with:
internal/http2/compat.js:282
this[kHeaders] = linkedList.create();
^
TypeError: linkedList.create is not a function
at new Http2ServerResponse (internal/http2/compat.js:282:33)
at Http2Server.onServerStream (internal/http2/compat.js:456:5)
at emitThree (events.js:135:13)
at Http2Server.emit (events.js:216:7)
at Http2Session.sessionOnStream (internal/http2/core.js:1035:10)
at emitThree (events.js:135:13)
at Http2Session.emit (events.js:216:7)
at Http2Session.onSessionHeaders [as onheaders] (internal/http2/core.js:104:11)
Thanks for your nice work.
Seems that the doc for the http2
is not updated, I know that the http2
module itself implemented as a separate module named http2
but cannot find the res.createPushResponse
method. Can you please help me?
Thanks again.
How this is supported in HTTP2?
placeholder from the collab summit in Berlin
It seems the TLS socket is initialized as tls.connect(port, host, options)
in http2.connect
. Some existing HTTP2 servers require some TLS options to set up the connection properly. More specifically:
I believe those should be set by defaults, then passing a URL string will just work.
Also, maybe it's better to use secureConnect
event instead of connect
event for the TLS sockets for setting up a session -- so that it won't go into the session if some TLS setup failure happens.
I just tried to write some tests like this.
'use strict';
const common = require('../common');
const assert = require('assert');
const http2 = require('http2');
const path = require('path');
const tls = require('tls');
const net = require('net');
const fs = require('fs');
const body =
'<html><head></head><body><h1>this is some data</h2></body></html>';
const server = http2.createServer((req, res) => {
res.setHeader('foobar', 'baz');
res.setHeader('X-POWERED-BY', 'node-test');
res.end(body);
});
server.listen(0, common.mustCall(() => {
const client = http2.connect(`http://localhost:${server.address().port}`);
const headers = { ':path': '/' };
const req = client.request(headers);
req.setEncoding('utf8');
req.on('response', common.mustCall(function(headers) {
client.socket.destroy();
server.close();
assert.strictEqual(headers['foobar'], 'baz');
assert.strictEqual(headers['x-powered-by'], 'node-test');
}));
req.end();
}));
server.on('error', common.mustNotCall());
but I have got the following errors
assert.js:86
throw new assert.AssertionError({
^
AssertionError: Internal HTTP/2 Failure. Stream does not exist.
at Http2Session.onSessionStreamClose [as onstreamclose] (internal/http2/core.js:152:3)
But following code is passed
'use strict';
const common = require('../common');
const assert = require('assert');
const http2 = require('http2');
const path = require('path');
const tls = require('tls');
const net = require('net');
const fs = require('fs');
const body =
'<html><head></head><body><h1>this is some data</h2></body></html>';
const server = http2.createServer((req, res) => {
res.setHeader('foobar', 'baz');
res.setHeader('X-POWERED-BY', 'node-test');
res.end(body);
});
server.listen(0, common.mustCall(() => {
const client = http2.connect(`http://localhost:${server.address().port}`);
const headers = { ':path': '/' };
const req = client.request(headers);
req.setEncoding('utf8');
req.on('response', common.mustCall(function(headers) {
assert.strictEqual(headers['foobar'], 'baz');
assert.strictEqual(headers['x-powered-by'], 'node-test');
}));
let data = '';
req.on('data', (d) => data += d);
req.on('end', () => {
assert.strictEqual(body, data);
// close in here
client.socket.destroy();
server.close();
});
req.end();
}));
server.on('error', common.mustNotCall());
I tried to debug this, but I cannot find some hints.
// here is the assertion code, but my code run this method twice, same id.
function onSessionStreamClose(id, code) {
const owner = this[kOwner];
const state = owner[kState];
const streams = state.streams;
const stream = streams.get(id);
assert(stream, 'Internal HTTP/2 Failure. Stream does not exist.');
timers._unrefActive(this); // Unref the session timer
timers._unrefActive(stream); // Unref the stream timer
// Notify the stream that it has been closed.
stream.emit('streamClosed', code);
timers.unenroll(stream);
stream[kSession] = undefined;
streams.delete(id);
}
Would it be possible for me to get write access to this repo so that I can merge approved PRs?
There are several things needed here:
How about we set up a call in the next couple of weeks to discuss how this is moving forward? There have been a lot of progress.
The client seems to hang sometimes after sending its first WINDOW_UPDATE
frame, and this is most readily seen when it opens a single stream with a small initialWindowSize
. In C++, DrainCallbacks
isn't being called after the first window update frame is sent.
I think there is a race condition involved, given that opening multiple streams increases the likelihood that all streams will receive all of their data without hanging, probably because the interleaving gives each stream enough time to reset state or something.
Maybe this is related to #19?
Http2Session::destroy
doesn't call destroy on its socket, so in order to close a connection completely on the client side, socket.destroy()
must be called on the socket exposed by the Http2Session
object.
I noticed that socket.destroy
calls destroy
on its parent session (I would've expected the other way around). Is there a reason for doing this?
๐๏ธ
Hey guys, i see this is a WIP repo - way to go for that important feature!
My question:
Is it part of the plan to add support for HTTP/2 for requests going out of a node app (client mode)
e.g. something like
http.request(options[, callback])
Will use HTTP/2.
(asking since all the discussions that i've seen here are referring to adding HTTP/2 server capabilities)
Many thanks.
https://ci.nodejs.org/job/node-test-binary-arm/7999/RUN_SUBSET=4,label=pi2-raspbian-wheezy/console
not ok 93 parallel/test-http2-create-client-connect
---
duration_ms: 1.537
severity: fail
stack: |-
(node:11017) ExperimentalWarning: The http2 module is an experimental API.
internal/http2/core.js:375
handle.consume(socket._handle._externalStream);
^
TypeError: Cannot read property '_externalStream' of null
at internal/http2/core.js:375:34
at new Http2Session (internal/http2/core.js:435:7)
at createClientSession (internal/http2/core.js:1340:19)
at connect (internal/http2/core.js:1402:19)
at items.forEach (/home/iojs/build/workspace/node-test-binary-arm/test/parallel/test-http2-create-client-connect.js:39:20)
at Array.forEach (native)
at Http2Server.<anonymous> (/home/iojs/build/workspace/node-test-binary-arm/test/parallel/test-http2-create-client-connect.js:37:11)
at Http2Server.<anonymous> (/home/iojs/build/workspace/node-test-binary-arm/test/common.js:462:15)
at emitNone (events.js:105:13)
at Http2Server.emit (events.js:207:7)
...
not ok 94 parallel/test-http2-server-startup
---
duration_ms: 3.639
severity: fail
stack: |-
(node:11033) ExperimentalWarning: The http2 module is an experimental API.
assert.js:86
throw new assert.AssertionError({
^
AssertionError: server timeout failed
at Timeout.setTimeout [as _onTimeout] (/home/iojs/build/workspace/node-test-binary-arm/test/parallel/test-http2-server-startup.js:80:35)
at ontimeout (timers.js:407:14)
at tryOnTimeout (timers.js:271:5)
at Timer.listOnTimeout (timers.js:235:5)
...
In the current http/1 implementation, support for detecting an HTTP/2 upgrade request can be added. This would take two forms: 1. when setting up an HTTPS server, detect the ALPN h2
option, and 2. when setting up an HTTP (plaintext) server, detecting the upgrade request. If either of these are detected, then either the existing upgrade
event, or a new upgrade-http2
event on the server can be triggered, allowing handing off of the socket to the http2 implementation. It ought to be possible to simply attach the socket to a new Http2Session
object then go from there.
(description above added by @jasnell)
=== release test-async-wrap-check-providers ===
Path: parallel/test-async-wrap-check-providers
Not all keys have been used:
[ 'HTTP2SESSION', 'HTTP2STREAM' ]
assert.js:85
throw new assert.AssertionError({
^
AssertionError: 2 === 0
at process.<anonymous> (/Users/matteo/Repositories/http2/test/parallel/test-async-wrap-check-providers.js:122:12)
at emitOne (events.js:101:20)
at process.emit (events.js:188:7)
Command: out/Release/node /Users/matteo/Repositories/http2/test/parallel/test-async-wrap-check-providers.js
=== release test-process-versions ===
Path: parallel/test-process-versions
assert.js:85
throw new assert.AssertionError({
^
AssertionError: [ 'ares',
'cldr',
'http_parser',
'icu',
'modules',
'nghttp2',
'node',
'openssl',
'tz',
'unicode',
'uv',
'v deepStrictEqual [ 'ares',
'cldr',
'http_parser',
'icu',
'modules',
'node',
'openssl',
'tz',
'unicode',
'uv',
'v8',
'zlib'
at Object.<anonymous> (/Users/matteo/Repositories/http2/test/parallel/test-process-versions.js:22:8)
at Module._compile (module.js:573:32)
at Object.Module._extensions..js (module.js:582:10)
at Module.load (module.js:490:32)
at tryModuleLoad (module.js:449:12)
at Function.Module._load (module.js:441:3)
at Module.runMain (module.js:607:10)
at run (bootstrap_node.js:420:7)
at startup (bootstrap_node.js:139:9)
at bootstrap_node.js:535:3
Command: out/Release/node /Users/matteo/Repositories/http2/test/parallel/test-process-versions.js
[02:00|% 100|+ 1276|- 2]: Done
make: *** [test] Error 1
I think we should track down all the part of the APIs and tests that needs to be added.
Having a list of unit tests that we want to cover makes easier for others to contribute.
Hi everyone. I'm just curious why http2 is exposed via require('http').HTTP2
? Is this temporary, or the final API? It seems a bit clunky. I was hoping we'd see require('http2')
.
As an aside, this is really cool stuff. Really exciting to see this under development. Thanks for your efforts here. ๐ป
How will this work?
Should we even support it in the first version?
The http2 client will not emit end
, given no data
listener is registered, even if the server ends the response.
The following code calls req.on('end')
just in the case req.on('data')
is registered.
'use strict';
require('../common');
const assert = require('assert');
const http2 = require('http2');
const testResBody = 'other stuff!\n';
const server = http2.createServer((req, res) => {
res.writeHead(200, {
'Content-Type': 'text/plain'
});
res.end(testResBody);
});
server.listen(0, function() {
const client = http2.connect(`http://localhost:${this.address().port}`);
const headers = { ':path': '/' };
const req = client.request(headers)
req.setEncoding('utf8');
// XXX: remove this and ` req.on('end')` is never called
let data = '';
req.on('data', (d) => data += d);
req.on('response', (headers) => {
assert.ok('date' in headers,
'Response headers contain a date.');
});
req.on('end', () => {
server.close();
process.exit();
});
req.end();
});
CI is showing nghttp2 library failing to build on windows: https://ci.nodejs.org/job/node-compile-windows/8991/label=win-vcbt2015/console
formal parameter list illegal (compiling source file lib\nghttp2_session.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(2188): error C2081: 'nghttp2_select_padding_callback': name in formal parameter list illegal (compiling source file lib\nghttp2_stream.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(2041): error C2059: syntax error: ';' (compiling source file lib\nghttp2_submit.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\nghttp2_hd.h(426): error C2059: syntax error: ';' (compiling source file lib\nghttp2_outbound_item.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(2820): error C2059: syntax error: '<parameter-list>' (compiling source file lib\nghttp2_rcbuf.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(3728): error C2059: syntax error: 'type' (compiling source file lib\nghttp2_priority_spec.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(3797): error C2143: syntax error: missing '{' before '*' (compiling source file lib\nghttp2_queue.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(2199): error C2061: syntax error: identifier 'data_source_read_length_callback' (compiling source file lib\nghttp2_session.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(2188): error C2061: syntax error: identifier 'select_padding_callback' (compiling source file lib\nghttp2_stream.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(2041): error C2059: syntax error: ')' (compiling source file lib\nghttp2_submit.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\nghttp2_hd.h(426): error C2059: syntax error: '<parameter-list>' (compiling source file lib\nghttp2_outbound_item.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(2930): error C2061: syntax error: identifier 'nghttp2_session_mem_recv' (compiling source file lib\nghttp2_rcbuf.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(3728): error C2059: syntax error: ')' (compiling source file lib\nghttp2_priority_spec.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(3797): error C2059: syntax error: ')' (compiling source file lib\nghttp2_queue.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(2199): error C2059: syntax error: ';' (compiling source file lib\nghttp2_session.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\lib\includes\nghttp2/nghttp2.h(2188): error C2059: syntax error: ';' (compiling source file lib\nghttp2_stream.c) [c:\workspace\node-compile-windows\label\win-vcbt2015\deps\nghttp2\nghttp2.vcxproj]
We should start working on docs, as it would be easier to onboard new collabs.
Also, docs would show inconsistencies in the API, so it's a good idea overall.
I would like to write some tests about http2 session, but I don't understand how to get the session from http2 server.
according to implementation guide, we have the following example codes.
const session = getSessionSomehow();
const socket = getSocketSomehow();
session.on('send', (buffer) => socket.write(buffer));
if the API does not exist yet, I will send other PR.
We need to make sure there is proper async hooks support here. Specifically, we need appropriate hooks for the creation / destruction of an Http2Session
, hooks for the creation / destruction of a Stream, each of the write operations, and the session shutdown operation.
We should have a quick call to discuss how to progress this better.
How about the 20th Dec at 5pm GMT? Does it work for everyone?
Join: https://hangouts.google.com/call/t7zou5rcnnf5begg7dqqicjbcie
Watch: https://www.youtube.com/watch?v=uQtKyX0eB2A
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.