-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
WIP: http2: improve compatibility with http1, add tests #15633
WIP: http2: improve compatibility with http1, add tests #15633
Conversation
lib/internal/http2/compat.js
Outdated
@@ -234,6 +235,10 @@ class Http2ServerRequest extends Readable { | |||
return this[kHeaders][HTTP2_HEADER_METHOD]; | |||
} | |||
|
|||
set method(method) { | |||
this[kHeaders][HTTP2_HEADER_METHOD] = method; |
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.
should this include a basic type check to ensure that method
is a non-empty string?
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.
Good point. http1 obviously didn't have it since it's not a getter/setter but I don't see why we couldn't do that for http2.
get closed() { | ||
return this[kState].closed; | ||
|
||
get socket() { |
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 wondering if we shouldn't more proactively warn people away from accessing this... e.g. by using an explicit runtime deprecation warning right from the start.
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.
Similar to statusMessageWarn? We could definitely do that.
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.
yep, exactly like that.
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.
As long as there is a way to retrieve the remote IP address for the socket (and local port, etc.); ideally symmetrically with http/1.
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 think we will keep the socket available but just add a one-time warning re: its usage.
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.
Good point and a good reminder! I had that marked down quite some time ago as a todo for an API that would make fetching those details easier but hadn't gotten around to it. We can make that data available via the Http2Session
object so that the socket
property does not have to be accessed.
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 think we will keep the socket available but just add a one-time warning re: its usage.
So getting the remote IP will print a warning?
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.
just getting it via the request and response objects should print a warning. We should add apis that allow this information to be retrieved independently of that so that there's a path that (a) does not print the warning and (b) does not mean users are accessing the socket directly.
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.
Sounds good. Would that land prior to landing a warning on the socket
getter, then?
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.
We could probably do those at the same time actually.
Extensive rework of Http2ServerResponse behaviours based on the expressjs test suite in order to get as close as possible to mimicking http1. Adds tests for all added and changed behaviour.
258f895
to
680e507
Compare
Made the requested changes. Will work on adding the ability to access the address info next (within this PR) unless @jasnell would prefer to do it or prefers it separated out into a new PR. On that note, we can't add 'session' getter to request or response (conflicts with existing user-land modules), do we just make users get it via |
Go for it! I'm going to be tied up in meetings and flights for most of the day so definitely have at it and don't wait on me! :-) |
This is undergoing somewhat major changes atm so please no reviews for now as it'll need to be reviewed after the next commit. I'm working on a solution for the socket problem and we should be able to get http2 to work with on-finished as a result (which is the biggest blocker for full express compatibility). I will in all likelihood open a new PR once that work is done (and close this one, putting it in Ref for the commit) since a lot of the changes made here will look different + there'll be new ones. |
I have basically 100% compatibility with (I'm using a proxy object for the socket and applying things like 'on', 'emit', 'readable', etc. to the Http2Stream instead while anything unaccounted for hits the socket. As a result of some other changes, performance for compatibility mode actually improved despite the usage of a Proxy.) Closing this now. Will open a new PR when done. |
I think you inadvertently pushed the closed button, I'm reopening. |
Oh my bad, I didn't read the last sentence |
Extensive re-work of http1 compatibility layer based on tests in express, on-finished and finalhandler. Fix handling of HEAD method to match http1. Adjust write, end, etc. to call writeHead as in http1 and as expected by user-land modules. Add socket proxy that instead uses the Http2Stream for the vast majority of socket interactions. Add and change tests to closer represent http1 behaviour. Refs: nodejs#15633 Refs: https://github.com/expressjs/express/tree/master/test Refs: https://github.com/jshttp/on-finished/blob/master/test/test.js Refs: https://github.com/pillarjs/finalhandler/blob/master/test/test.js
Extensive re-work of http1 compatibility layer based on tests in express, on-finished and finalhandler. Fix handling of HEAD method to match http1. Adjust write, end, etc. to call writeHead as in http1 and as expected by user-land modules. Add socket proxy that instead uses the Http2Stream for the vast majority of socket interactions. Add and change tests to closer represent http1 behaviour. Refs: #15633 Refs: https://github.com/expressjs/express/tree/master/test Refs: https://github.com/jshttp/on-finished/blob/master/test/test.js Refs: https://github.com/pillarjs/finalhandler/blob/master/test/test.js PR-URL: #15702 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Extensive re-work of http1 compatibility layer based on tests in express, on-finished and finalhandler. Fix handling of HEAD method to match http1. Adjust write, end, etc. to call writeHead as in http1 and as expected by user-land modules. Add socket proxy that instead uses the Http2Stream for the vast majority of socket interactions. Add and change tests to closer represent http1 behaviour. Refs: #15633 Refs: https://github.com/expressjs/express/tree/master/test Refs: https://github.com/jshttp/on-finished/blob/master/test/test.js Refs: https://github.com/pillarjs/finalhandler/blob/master/test/test.js PR-URL: #15702 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Extensive re-work of http1 compatibility layer based on tests in express, on-finished and finalhandler. Fix handling of HEAD method to match http1. Adjust write, end, etc. to call writeHead as in http1 and as expected by user-land modules. Add socket proxy that instead uses the Http2Stream for the vast majority of socket interactions. Add and change tests to closer represent http1 behaviour. Refs: #15633 Refs: https://github.com/expressjs/express/tree/master/test Refs: https://github.com/jshttp/on-finished/blob/master/test/test.js Refs: https://github.com/pillarjs/finalhandler/blob/master/test/test.js PR-URL: #15702 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Extensive re-work of http1 compatibility layer based on tests in express, on-finished and finalhandler. Fix handling of HEAD method to match http1. Adjust write, end, etc. to call writeHead as in http1 and as expected by user-land modules. Add socket proxy that instead uses the Http2Stream for the vast majority of socket interactions. Add and change tests to closer represent http1 behaviour. Refs: nodejs/node#15633 Refs: https://github.com/expressjs/express/tree/master/test Refs: https://github.com/jshttp/on-finished/blob/master/test/test.js Refs: https://github.com/pillarjs/finalhandler/blob/master/test/test.js PR-URL: nodejs/node#15702 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This PR brings near full compatibility with
express
's use of http1 API. List of updates:complete
prop forHttp2ServerRequest
method
setter since some user-land modules use thissocket
andconnection
onHttp2ServerResponse
writeHead
,write
,end
,addHeader
andremoveHeader
. A lot of user-land modules, including express, rely on the fact that in http1 all write methods callwriteHead
if headers haven't been written yet.end
call and triggers callback, even ifwriteHead
already happened)Please let me know if I can provide more info for any of these changes. I know there's a lot here and some of the logic is a bit complicated in order to replicate http1 behaviour. It came a long way since my 1st pass at it.
(Re: express, after this PR only 5 tests are failing and they're a result of other modules relying on specific http1-only behaviour. This should bode well for compatibility with other popular libraries too.)
Thanks in advance for any and all reviews!
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
http2, test