Skip to content

Conversation

ShogunPanda
Copy link
Contributor

This PR fixes an edge case in which Parser::Execute is called within the callback of one of its events.

Fixes: #39671

@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/http
  • @nodejs/net

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. http_parser Issues and PRs related to the HTTP Parser dependency or the http_parser binding. needs-ci PRs that need a full CI run. labels Jun 10, 2022
@mcollina
Copy link
Member

Good work!

@bnoordhuis
Copy link
Member

The problematic parser->current_buffer_.IsEmpty() check is a speed hack; it's explicitly documented as such. Adding a hack to work around a hack is not a good idea.

My suggestion: remove current_buffer_. That simplifies the parser and makes it re-entrant again. Worry about performance afterwards.

I speculate the hit won't be so bad, and can probably be fixed by doing the bookkeeping in JS land.

@ShogunPanda
Copy link
Contributor Author

ShogunPanda commented Jun 13, 2022

@bnoordhuis Are you suggesting to remove that just in Execute, isn't it?

@bnoordhuis
Copy link
Member

current_buffer_ is used to thread through the buffer from a parser.execute(buffer) call from JS through C++ to the JS callback parser[kOnBody] = parserOnBody(buffer, start, len) { /* ... */ }.

That threading through isn't necessary. Just set parser.buffer = buffer before calling parser.execute(buffer) and the callback can access it as this.buffer.

Node can short-circuit and pass data directly from libuv to the callback without going through parser.execute(buffer) first but the callback can detect that by doing buffer = this.buffer ?? buffer.

OnStreamRead()should be modified to create a new buffer instead of reusing current_buffer_. In theory that's a performance hit but I expect it's a wash because the callback no longer needs to call buffer.slice().


If I had infinite free time, I'd rewrite the parser to get rid of C++ -> JS callbacks and just return parse info. It'd get rid of so much complexity and inefficiency.

@ShogunPanda
Copy link
Contributor Author

Actually I was able to remove the current_buffer_ at all and apparently nothing changes.
The only relevant change is in on_body where I always do:

Local<Object> current_buffer_ = scope.Escape(Buffer::Copy(
        env()->isolate(),
        current_buffer_data_,
        current_buffer_len_).ToLocalChecked());

Do you see any problem in this?

@ShogunPanda
Copy link
Contributor Author

@addaleax @bnoordhuis I've sent my latest version which removes current_buffer_ and thus also removes needs for all the suggestion Anna asked about. Can you please take a look again?

@ShogunPanda ShogunPanda force-pushed the http-defer-execute branch 2 times, most recently from 97fbe67 to 5c2884b Compare June 15, 2022 08:41
@ShogunPanda
Copy link
Contributor Author

@bnoordhuis I applied your changes (plus few additional required changes). How does it look now?

@bnoordhuis
Copy link
Member

Is there a reason you didn't update lib/_http_common.js? You don't need to slice anymore, or pass the start and len arguments.

@ShogunPanda
Copy link
Contributor Author

@bnoordhuis The answer is obvious: I forgot. X°°°D Done now!

Copy link
Member

@bnoordhuis bnoordhuis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, good work!

@addaleax I'll go ahead and dismiss your review. Looks like all actionable feedback's been addressed.

@ShogunPanda
Copy link
Contributor Author

ShogunPanda commented Jun 17, 2022

@bnoordhuis The last item would be to try to test it without using the parser directly. I'll give it a try today but this can go out without as well.

Done!

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

wow, when a PR fixes a bug and reduces code, it's doing something right.

@ShogunPanda
Copy link
Contributor Author

Thanks sir :)

@nodejs-github-bot
Copy link
Collaborator

@ShogunPanda
Copy link
Contributor Author

@nodejs/http Can anybody reapprove this so I can land it?

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@ShogunPanda
Copy link
Contributor Author

Landed in b970634

ShogunPanda added a commit that referenced this pull request Jun 22, 2022
PR-URL: #43369
Fixes: #39671
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
F3n67u pushed a commit to F3n67u/node that referenced this pull request Jun 24, 2022
PR-URL: nodejs#43369
Fixes: nodejs#39671
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
@j-catania
Copy link

j-catania commented Jun 27, 2022

Hello @ShogunPanda

Thanks for your work !
Can you please tell me in which version of NodeJS is it fixed please ?

@ShogunPanda
Copy link
Contributor Author

@j-catania It was merged in main, which means it will be available in the next 18 release, I think 18.5.0. Not sure it will be backported.

@ShogunPanda ShogunPanda deleted the http-defer-execute branch June 27, 2022 07:26
@MasterOdin
Copy link
Contributor

Is there a way to help see this backported to 16.x? This bug is really biting us as we are doing file uploads, and the 18 LTS release is still ~4 months off so upgrading isn't an option for us, and that we expect surrounding infra will take a few months to add 18 support after it releases.

@ShogunPanda
Copy link
Contributor Author

Is there a way to help see this backported to 16.x? This bug is really biting us as we are doing file uploads, and the 18 LTS release is still ~4 months off so upgrading isn't an option for us, and that we expect surrounding infra will take a few months to add 18 support after it releases.

@nodejs/tsc Can we do this? What is the policy about backporting?

@aduh95
Copy link
Contributor

aduh95 commented Jun 28, 2022

## What can be backported?
The "Current" release line is much more lenient than the LTS release lines in
what can be landed. Our LTS release lines (see the [Release Plan][])
require that commits mature in the Current release for at least 2 weeks before
they can be landed in an LTS staging branch. Only after "maturation" will those
commits be cherry-picked or backported.

@richardlau
Copy link
Member

Is there a way to help see this backported to 16.x? This bug is really biting us as we are doing file uploads, and the 18 LTS release is still ~4 months off so upgrading isn't an option for us, and that we expect surrounding infra will take a few months to add 18 support after it releases.

@nodejs/tsc Can we do this? What is the policy about backporting?

Standard policy is:

  • Semver patch commits can be backported to LTS although we prefer to have them go have been in a current release for at least two weeks first (https://github.com/nodejs/Release#lts-staging-branches).
  • Semver minor changes, in addition to the "two weeks in current" guideline, would wait for the next semver minor LTS release (generally one per quarter).

@ShogunPanda
Copy link
Contributor Author

ShogunPanda commented Jun 28, 2022

Thanks both.
In other words, in this particular case, I think the change is semver-patch. So I will be able to send a backport PR in about two weeks from the release of 18.5.0. Am I right?

@aduh95
Copy link
Contributor

aduh95 commented Jun 28, 2022

If the commit lands cleanly on v16.x-staging, there's no need for a backport PR:

## What needs to be backported?
If a cherry-pick from `main` does not land cleanly on a staging branch, the
releaser will mark the pull request with a particular label for that release
line (e.g. `backport-requested-vN.x`), specifying to our tooling that this
pull request should not be included. The releaser will then add a comment
requesting that a backport pull request be made.

If a backport PR is necessary, you don't need to wait two weeks for opening it, but the LTS team won't land it until it's been on a Current version for at least two weeks.

@ShogunPanda
Copy link
Contributor Author

I see.
Given that you added the label now, the tooling will try to perform the landing automatically, isn't it?

@aduh95
Copy link
Contributor

aduh95 commented Jun 28, 2022

No, someone from @nodejs/lts will (try to) do it when preparing the next release, or leave a comment here if there's a conflict.

targos pushed a commit that referenced this pull request Jul 12, 2022
PR-URL: #43369
Fixes: #39671
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
targos pushed a commit that referenced this pull request Jul 31, 2022
PR-URL: #43369
Fixes: #39671
Reviewed-By: Ben Noordhuis <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
guangwong pushed a commit to noslate-project/node that referenced this pull request Oct 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. http_parser Issues and PRs related to the HTTP Parser dependency or the http_parser binding.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Assertion `parser->current_buffer_.IsEmpty()' failed