-
-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support http2 #36
base: master
Are you sure you want to change the base?
Support http2 #36
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is definitely something wrong here. For example a HEAD request, even in HTTP2, will never have a Body, so hasBody should return false. Same with almost all GET requests which would never have a body.
@dougwilson Thank you for feedback. you are right. I will change hasBody to return false if request is OPTIONS, TRACE, CONNECT, HEADor GET method. |
In HTTP1 a GET request may or may not have a body. I assume this is still the same in http/2 as I have used a body in a GET request to a http/2 server. Also that logic doesn't seem robust for custom methods or new future methods. There should be somewhere in the http/2 rfc that states exactly how to know if a request includes a body or not. That should be the implemented logic here. |
I dig in http/2 rfc next week and implement this. |
Skipping around through the rfc you linked,, from what I can gather is that a body = data frames from the client on a stream. So to know if there is a body in http/2 you would say "will this steam send data frames?" and it seems that answer would be yes for the following condition: you get a header or continuation frame with end headers flag but no end stream flag set. |
Definitely yes. And I had checked some nodejs code how get |
It's possible that new API needs to be added to Node.js to get that information. User land code should be able to get at all the data at the http/2 level from my understanding. If it's purposely hidden though the API then at the very least have an API to know if the http/2 request actually has a body or not. |
I dig in nodejs code and found parameter that indicate already get When Nodejs get I fixed this PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! Just the note about testing.
test/test.js
Outdated
'content-type': type || '' | ||
}, | ||
stream: { | ||
_readableState: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point if we are depending on Node.js internals for the state, we need to test against the actual Node.js implementation instead of a simple mock.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either that or there is specific documentation in Node.js documenting this exact behavior, though I didn't see that anywhere. Without one of these we won't know when Node.js changes it's behavior as our tests won't fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will fix tests tomorrow.
test/test.js
Outdated
assert.strictEqual(typeis(req, ['image/*']), false) | ||
assert.strictEqual(typeis(req, ['text/*', 'image/*']), false) | ||
}) | ||
if (!process.env.HTTP2_TEST) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this excludes from HTTP/2 tests? To me this seems like it should work in http/2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with you. I just cannot found how to unset content-type in superagent. I'm checking superagent code.
callback(req) | ||
}) | ||
|
||
server = server.listen(function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget to close the server, otherwise every test leaves a new server open, eventually going to starve the test memory over time.
callback(req) | ||
}) | ||
|
||
server = server.listen(function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't forget to close the server, otherwise every test leaves a new server open, eventually going to starve the test memory over time.
@dougwilson I addressed review comment. I think this is good for now. 👍 |
.travis.yml
Outdated
@@ -26,6 +26,7 @@ before_install: | |||
- "test $TRAVIS_NODE_VERSION != '0.6' || npm rm --save-dev istanbul" | |||
- "test $TRAVIS_NODE_VERSION != '0.8' || npm rm --save-dev istanbul" | |||
- "test $(echo $TRAVIS_NODE_VERSION | cut -d. -f1) -ge 4 || npm rm --save-dev $(grep -E '\"eslint\\S*\"' package.json | cut -d'\"' -f2)" | |||
- "test -z $(echo $HTTP2_TEST) || npm install --only=dev https://github.com/visionmedia/superagent.git" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please only install deps from npm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, superagent with http2 have not released. I will wait for release.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also what does the only flag do? According to https://docs.npmjs.com/cli/install it only does something if you do not provide a module name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is my mistake. --only=dev
flag does nothing here. I should delete this flag.
index.js
Outdated
* @param {Object} request | ||
* @return {Boolean} | ||
* @public | ||
*/ | ||
|
||
function hasbody (req) { | ||
return req.headers['transfer-encoding'] !== undefined || | ||
return (ishttp2(req) && !req.stream._readableState.ended) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some testing seems like this may have an issue. If you add a req.on('data'
listener and read the body, this then returns false
for http/2 but true
for http/1. The current interface it is expected to be true for both, as hasBody determines if the request has body, regardless of it you happened to have read it already or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked and happens an issue you said. I address this issue and add a test.
index.js
Outdated
* @param {Object} request | ||
* @return {Boolean} | ||
* @public | ||
*/ | ||
|
||
function hasbody (req) { | ||
return req.headers['transfer-encoding'] !== undefined || | ||
return (ishttp2(req) && (req.stream.readable || req.stream._readableState.endEmitted)) || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like this still has some kind of issue. I would expect the following test to pass:
it('should not indicate body', function (done) {
createBodylessRequest('', function (req) {
var data = ''
req.on('data', function (chunk) {
data += chunk
})
req.on('end', function (chunk) {
process.nextTick(function () {
assert.strictEqual(typeis.hasBody(req), false)
done()
})
})
})
})
It seems like just attaching a data
event will make this module claim the request has a body, even if the original request did not have a body.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I addressed issue. I found a parameter _readableState.sync
which is default true and became false after reading data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! What does that flag actually mean / is it documented so we can rely on some kind of behavior? The underscore prefix just has me worries about the long term.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It means 'readable'/'data' event is emitted immediately or not.
See also comment in source.
https://github.com/nodejs/node/blob/master/lib/_stream_readable.js#L104
// a flag to be able to tell if the event 'readable'/'data' is emitted
// immediately, or on a later tick. We set this to true at first, because
// any actions that shouldn't happen until "later" should generally also
// not happen before the first read call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think Node.js considers docs in source code as promised behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also unclear on how It means 'readable'/'data' event is emitted immediately or not.
has any indication on if the http/2 stream has data frames or not? It seems to be unrelated to the unlying state of the http/2 layer to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Searching the Node.js issue tracker for the underscore property pulls up nodejs/node#445 which sounds like it shouldn't be used inside Node.js code, let alone third-party things.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think Node.js considers docs in source code as promised behavior.
Yes. However, current Nodejs has no other parameter to indicate hasBody after event 'end'. Should we suggest new API for Nodejs?
I'm also unclear on how It means 'readable'/'data' event is emitted immediately or not. has any indication on if the http/2 stream has data frames or not? It seems to be unrelated to the unlying state of the http/2 layer to me.
sync
relates to readableStream rather than http/2 layer state. When http/2 layer get DataFrame, readableStream(ServerHttp2Request) emit 'data' event immediately or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. However, current Nodejs has no other parameter to indicate hasBody after event 'end'. Should we suggest new API for Nodejs?
Based on the discussion in nodejs/node#445 it sounds like the answer is it's a must, as the activity seems to indicate that this will break sooner rather than later, and they want to get everything public.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I will file a issue in nodejs repo and pending this PR.
Did you ever make this issue / can you provide a link I can look at? |
Yes, I already make the issue. |
Thanks! I left a comment there. Let's give 30 days from now on that issue if it's not resolved and then we'll go with the reaching into internals solution of this PR 👍 |
4ed52f8
to
88c2633
Compare
I fix PR to use request.stream.endAfterHeaders released on node 10.11. |
Support http2 to enable express tests with http2.
expressjs/express#3390.
body-parser
cannot parse http2 body stream, becausehasBody
withhttp2ServerRequest
always return false. Ahttp2ServerRequest
does not have any information about body had. I thinkhasBody
withhttp2ServerRequest
should return always true.