You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jul 6, 2018. It is now read-only.
Repository navigation
This repository was archived by the owner on Jul 6, 2018. It is now read-only.
Initial experiences with converting from legacy http2 module to core http2; Chunk repeat problem? #126
I have a large and complex application SPA that I am developing which up until now has been using the http2 module from molnarg/node-http2 repository. I thought I would give this new version a quick trial to get an idea for how much conversion effort I might need when this hits.
My immediate conclusion what was that theoretically I only needed to change one line of code, namely
However I have experienced other problems. Firstly there seems to be a problem around serve-static (or more probably the send module that it uses) in relation to completing requests. My application successfully loaded the first file (index.html), but immediately became stuck as it failed to complete loading of its first import. I couldn't get very far tracing down the problem as I can't get visual studio code debug to work with this latest version of node. It insists of providing --debug-brk flag which this version of node rejects.
So I have written my static file serving to to little more than fs.createReadSteam(filename).pipe(res)
Now it does load all the files but immediately fails as it tries to start running.
This application is a polymer based app (https://www.polymer-project.org/) and almost immediately the application crashes out with polymer-micro.html:310 Uncaught SyntaxError: Unexpected token
looking at this file as seen by the browser at that point (lines 298 to 321)
attributeChangedCallback: function (name, oldValue, newValue) {
this._attributeChangedImpl(name);
for (var i = 0, b; i < this.behaviors.length; i++) {
b = this.behaviors[i];
if (b.attributeChanged) {
b.attributeChanged.call(this, name, oldValue, newValue);
}
}
if (this.attributeChanged) {
this.attributeChanged(name, oldValue, newValue);
}
},
_attributeChangedImpl: function (namatus._makeReady();
});
},
_afterNextRenderQueue: [],
_waitingNextRender: false,
afterNextRender: function (element, fn, args) {
this._watchNextRender();
this._afterNextRenderQueue.push([
element,
fn,
args
]);
A quick comparison with the source file which was sent (with the fs.createReadStream().pipe(res)) shows that halfway along line 310, I suddenly get some code from further back up the file injected into the source, and the overall file has got more lines in it in the client than is in the file back on the server.
I am currently figuring out how I can get a better demonstration of the problem to you, but at least reckon I should report this to you as I find it.
Thanks for your feedback @akc42! That's highly needed, and what we are looking for. Are you able to reproduce the problem you are having in isolation? Would you mind attaching a full example that demonstrate it?
@mcollina Its a real problem showing the full application as
It is massive
Its not open source, I am developing it for a client.
I will have a look further at whether I can offer a cut down version, that still shows the issue as a repo on github
The README.md in this repository should show you how to set it up. You need to adjust dns for the certificate files, or (as is probably the case) you can replace them with your own.
@akc42 FWIW I've done a similar migration from node-http2 to node-spdy to this native implementation. Perhaps this repo can be helpful to you: https://gitlab.com/sebdeckers/http2server/merge_requests/20 (This is the latest branch, implements push promises, static file serving, mime types, compression, etc.)
Here is another datapoint in case it is useful to anyone. I did a character count of the original file and the corrupted file. They are identical (21094 in the case of property-assessors.html, the first corrupted file when I run the http2-corrupt setup referenced above). I had originally thought that the corrupted file was longer than the original because the line numbering was higher at the end, but it turns out not to be the case.
I'll try and see if I can find the length of the chunk that is different.
I found another interesting fact. The first corrupted file corruption started at character (using wc -c on linux) 8158 and the next corrupted file I checked it started at character 7531 but the data that was used to corrupt the file came from character 4088 onwards in all three of the first three cases that I checked.
Makes me wonder if there is some form of pause restart problem.
It's entirely possible. I'll start running some tests that pass a large amount of data through on both the client and server and make sure we get good check sums on both.
I am happy to report now that I have just upgraded to the lastest version in master, that the corruption problems I referred to above no longer seem to be happening.
As a result of that success, I have started to use it with my "big" application. Here I have run into another problem which I haven't got to the bottom of yet. I am using the router module from npm (https://www.npmjs.com/package/router) and whilst, so far its routing static files and an ajax GET request, something is happening with the ajax POST request. I see it received by the server, but it disappears inside the router module and never comes out. After a delay of a couple of minutes I get a error
pas:web request received for url /logon +12s
events.js:182
throw er; // Unhandled 'error' event
^
Error [ERR_HTTP2_STREAM_ERROR]: Stream closed with error code 7
at ServerHttp2Stream._destroy (internal/http2/core.js:1479:19)
at ServerHttp2Stream.destroy (internal/streams/destroy.js:32:8)
at streams.forEach (internal/http2/core.js:911:40)
at Map.forEach (native)
at ServerHttp2Session.destroy (internal/http2/core.js:911:13)
at TLSSocket.socketDestroy [as destroy] (internal/http2/core.js:1919:18)
at emitOne (events.js:115:13)
at ServerHttp2Session.emit (events.js:210:7)
at process.nextTick (internal/http2/core.js:611:31)
at _combinedTickCallback (internal/process/next_tick.js:134:7)
alan@kanga:~/dev/pasv5[newnode]$ ^C
I have attached breakpoints on all of these functions. It was only temporarily on onData (because everything times out whilst I am debugging) but it was called with the chunk of data that was the body), but I did a second run with breakpoints on the rest, and onEnd was never called, and after the long delay onAborted was called.
I have been playing with this further today. As far as I can see this is a failure somewhere down the line to emit 'end' on the request stream. I can see that Http2Stream extends from Duplex, and to make that emit 'end', somewhere along the line someone has to call this.push(null) on it. (or emit('end' ...) specifically, but I can't find any of those).
As far as I can see there are only two viable places for that to happen, Either onSessionClose or onStreamClose. If I understand correctly, for a single request, it is the latter of those two functions that I should be examining. This happens in _destroy() function, which is called by node when an external entity called destroy(). And thats as far as I've got. _destroy() doesn't get called in my scenario until the timeout in about two minutes. Certainly not when all the 'data' chunks have been consumed.
On Tue, Jul 11, 2017 at 11:01 AM Alan Chandler ***@***.***> wrote:
I have been playing with this further today. As far as I can see this is a
failure somewhere down the line to emit 'end' on the request stream. I can
see that Http2Stream extends from Duplex, and to make that emit 'end',
somewhere along the line someone has to call this.push(null) on it. (or emit('end'
...) specifically, but I can't find any of those).
As far as I can see there are only two viable places for that to happen,
Either onSessionClose or onStreamClose. If I understand correctly, for a
single request, it is the latter of those two functions that I should be
examining. This happens in _destroy() function, which is called by node
when an external entity called destroy(). And thats as far as I've got.
_destroy() doesn't get called in my scenario.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#126 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAa2eRXw5Lm4JnqftEeXtlyqLi_WwRGOks5sM7htgaJpZM4NcieG>
.
@jasnell I think your fix has worked, I now have a server that seems to be receiving and responding to GET and PUSH requests just fine.
I am now just puzzling how to use the http2 client (which is another subprocess of my application) to send a POST request to the server. I "think" I have it, slightly different from http, but its late this evening here and my eyes need some rest before typing the changes in.
It shows how I'm setting http methods, but I definitely have questions about performance and best practices which I've raised here: #131 The client passed all the unit tests in that repo based on nodejs/http2 from a couple weeks back. Haven't had a chance to test again with all the new PR's
Activity
mcollina commentedon May 16, 2017
Thanks for your feedback @akc42! That's highly needed, and what we are looking for. Are you able to reproduce the problem you are having in isolation? Would you mind attaching a full example that demonstrate it?
akc42 commentedon May 16, 2017
This is my serve static replacement
akc42 commentedon May 16, 2017
@mcollina Its a real problem showing the full application as
I will have a look further at whether I can offer a cut down version, that still shows the issue as a repo on github
mcollina commentedon May 16, 2017
To solve this, we need a way to reproduce. Can you assemble a trimmed down version that shows the same problem by just using core http2 module?
akc42 commentedon May 16, 2017
Try this. Its a simple server and the polymer 2.0 (just released) starter kit as the client. It shows the corruption for me.
https://github.com/akc42/http2-corrupt
The README.md in this repository should show you how to set it up. You need to adjust dns for the certificate files, or (as is probably the case) you can replace them with your own.
sebdeckers commentedon May 16, 2017
@akc42 FWIW I've done a similar migration from node-http2 to node-spdy to this native implementation. Perhaps this repo can be helpful to you: https://gitlab.com/sebdeckers/http2server/merge_requests/20 (This is the latest branch, implements push promises, static file serving, mime types, compression, etc.)
akc42 commentedon May 18, 2017
Here is another datapoint in case it is useful to anyone. I did a character count of the original file and the corrupted file. They are identical (21094 in the case of property-assessors.html, the first corrupted file when I run the http2-corrupt setup referenced above). I had originally thought that the corrupted file was longer than the original because the line numbering was higher at the end, but it turns out not to be the case.
I'll try and see if I can find the length of the chunk that is different.
akc42 commentedon May 18, 2017
I found another interesting fact. The first corrupted file corruption started at character (using
wc -con linux) 8158 and the next corrupted file I checked it started at character 7531 but the data that was used to corrupt the file came from character 4088 onwards in all three of the first three cases that I checked.Makes me wonder if there is some form of pause restart problem.
jasnell commentedon May 18, 2017
It's entirely possible. I'll start running some tests that pass a large amount of data through on both the client and server and make sure we get good check sums on both.
akc42 commentedon Jul 5, 2017
I am happy to report now that I have just upgraded to the lastest version in master, that the corruption problems I referred to above no longer seem to be happening.
As a result of that success, I have started to use it with my "big" application. Here I have run into another problem which I haven't got to the bottom of yet. I am using the
routermodule from npm (https://www.npmjs.com/package/router) and whilst, so far its routing static files and an ajax GET request, something is happening with the ajax POST request. I see it received by the server, but it disappears inside theroutermodule and never comes out. After a delay of a couple of minutes I get a errorakc42 commentedon Jul 6, 2017
I am closing in on the error. Its in body parser (json) https://www.npmjs.com/package/body-parser
It is expecting some events so it attaches to the request stream
I have attached breakpoints on all of these functions. It was only temporarily on
onData(because everything times out whilst I am debugging) but it was called with the chunk of data that was the body), but I did a second run with breakpoints on the rest, andonEndwas never called, and after the long delayonAbortedwas called.mcollina commentedon Jul 6, 2017
@akc42 can you link those in body-parser source code? I can't find them right now.
akc42 commentedon Jul 6, 2017
@mcollina Its in a module called
raw-bodythatbody-parserobviously brings inThe lines referenced above are on lines 228 on
index.jsthe functions are further down at 266 and beyondakc42 commentedon Jul 11, 2017
I have been playing with this further today. As far as I can see this is a failure somewhere down the line to emit 'end' on the request stream. I can see that
Http2Streamextends from Duplex, and to make that emit 'end', somewhere along the line someone has to callthis.push(null)on it. (oremit('end' ...)specifically, but I can't find any of those).As far as I can see there are only two viable places for that to happen, Either
onSessionCloseoronStreamClose. If I understand correctly, for a single request, it is the latter of those two functions that I should be examining. This happens in_destroy()function, which is called by node when an external entity calleddestroy(). And thats as far as I've got._destroy()doesn't get called in my scenario until the timeout in about two minutes. Certainly not when all the 'data' chunks have been consumed.jasnell commentedon Jul 11, 2017
akc42 commentedon Jul 14, 2017
@jasnell I think your fix has worked, I now have a server that seems to be receiving and responding to GET and PUSH requests just fine.
I am now just puzzling how to use the http2 client (which is another subprocess of my application) to send a POST request to the server. I "think" I have it, slightly different from
http, but its late this evening here and my eyes need some rest before typing the changes in.AndrewBarba commentedon Jul 14, 2017
I've been doing some work with the core http2 client, you can see a very basic implementation here:
https://github.com/AndrewBarba/apns2/blob/node/http2/lib/http2-client.js
It shows how I'm setting http methods, but I definitely have questions about performance and best practices which I've raised here: #131 The client passed all the unit tests in that repo based on
nodejs/http2from a couple weeks back. Haven't had a chance to test again with all the new PR'sBasic usage would look like: