Skip to content

Commit 2b3e623

Browse files
divybotlittledivy
andauthored
fix(ext/node): restore llhttp parser.data after execute to handle re-entrant calls (#33832)
## Summary Enables `test-http-parser-multiple-execute` in node_compat suite. ## Test plan - [x] `cargo test --test node_compat -- test-http-parser-multiple-execute` --------- Co-authored-by: divybot <divybot@users.noreply.github.com> Co-authored-by: Divy Srivastava <me@littledivy.com>
1 parent 43b78ea commit 2b3e623

2 files changed

Lines changed: 14 additions & 3 deletions

File tree

ext/node/ops/llhttp/binding.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,8 @@ unsafe fn consume_read_callback(
814814
callbacks: callbacks_static,
815815
};
816816

817+
// Save+restore for re-entrant execute() calls — see HTTPParser::execute.
818+
let saved_data = inner.parser.data;
817819
inner.parser.data = &mut ctx as *mut ExecuteContext as *mut std::ffi::c_void;
818820

819821
let err = unsafe {
@@ -824,7 +826,7 @@ unsafe fn consume_read_callback(
824826
)
825827
};
826828

827-
inner.parser.data = std::ptr::null_mut();
829+
inner.parser.data = saved_data;
828830
inner.current_buffer_data = std::ptr::null();
829831
inner.current_buffer_len = 0;
830832

@@ -971,6 +973,12 @@ impl HTTPParser {
971973
callbacks: callbacks_static,
972974
};
973975

976+
// Save and restore parser.data to support re-entrant execute() calls.
977+
// If a JS callback (e.g. the 'information' event handler for 100 Continue)
978+
// triggers another execute() call, the inner execute must restore the outer
979+
// context pointer so subsequent callbacks from the outer llhttp_execute
980+
// still have a valid ExecuteContext.
981+
let saved_data = inner.parser.data;
974982
inner.parser.data =
975983
&mut ctx as *mut ExecuteContext as *mut std::ffi::c_void;
976984

@@ -982,7 +990,7 @@ impl HTTPParser {
982990
)
983991
};
984992

985-
inner.parser.data = std::ptr::null_mut();
993+
inner.parser.data = saved_data;
986994
inner.current_buffer_data = std::ptr::null();
987995
inner.current_buffer_len = 0;
988996

@@ -1046,12 +1054,14 @@ impl HTTPParser {
10461054
callbacks: callbacks_static,
10471055
};
10481056

1057+
// Save+restore for re-entrant execute() calls — see HTTPParser::execute.
1058+
let saved_data = inner.parser.data;
10491059
inner.parser.data =
10501060
&mut ctx as *mut ExecuteContext as *mut std::ffi::c_void;
10511061

10521062
let err = unsafe { sys::llhttp_finish(&mut inner.parser) };
10531063

1054-
inner.parser.data = std::ptr::null_mut();
1064+
inner.parser.data = saved_data;
10551065

10561066
if err != sys::HPE_OK { -1 } else { 0 }
10571067
}

tests/node_compat/config.jsonc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,6 +1661,7 @@
16611661
"parallel/test-http-parser-free.js": {},
16621662
"parallel/test-http-parser-freed-before-upgrade.js": {},
16631663
"parallel/test-http-parser-freed-during-execute.js": {},
1664+
"parallel/test-http-parser-multiple-execute.js": {},
16641665
"parallel/test-http-parser.js": {},
16651666
"parallel/test-http-pause-no-dump.js": {},
16661667
"parallel/test-http-pause-resume-one-end.js": {},

0 commit comments

Comments
 (0)