Skip to content

Commit 1ac1424

Browse files
committed
http: align parser with StreamBase interface changes
The `StreamBase` interface changed, so that `OnStreamRead()` and `OnStreamAlloc()` are not guaranteed to be emitted in the same tick any more. This means that, while it isn’t causing any trouble right now, we should not assume that it’s safe to return a static buffer in the HTTP parser’s `OnStreamAlloc()` method. PR-URL: #18936 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent e136903 commit 1ac1424

File tree

4 files changed

+36
-0
lines changed

4 files changed

+36
-0
lines changed

src/env-inl.h

+8
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,14 @@ inline void Environment::set_http_parser_buffer(char* buffer) {
469469
http_parser_buffer_ = buffer;
470470
}
471471

472+
inline bool Environment::http_parser_buffer_in_use() const {
473+
return http_parser_buffer_in_use_;
474+
}
475+
476+
inline void Environment::set_http_parser_buffer_in_use(bool in_use) {
477+
http_parser_buffer_in_use_ = in_use;
478+
}
479+
472480
inline http2::http2_state* Environment::http2_state() const {
473481
return http2_state_.get();
474482
}

src/env.h

+3
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,8 @@ class Environment {
646646

647647
inline char* http_parser_buffer() const;
648648
inline void set_http_parser_buffer(char* buffer);
649+
inline bool http_parser_buffer_in_use() const;
650+
inline void set_http_parser_buffer_in_use(bool in_use);
649651

650652
inline http2::http2_state* http2_state() const;
651653
inline void set_http2_state(std::unique_ptr<http2::http2_state> state);
@@ -828,6 +830,7 @@ class Environment {
828830
double* heap_space_statistics_buffer_ = nullptr;
829831

830832
char* http_parser_buffer_;
833+
bool http_parser_buffer_in_use_ = false;
831834
std::unique_ptr<http2::http2_state> http2_state_;
832835

833836
// stat fields contains twice the number of entries because `fs.StatWatcher`

src/node_http_parser.cc

+17
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,14 @@ class Parser : public AsyncWrap, public StreamListener {
525525
static const size_t kAllocBufferSize = 64 * 1024;
526526

527527
uv_buf_t OnStreamAlloc(size_t suggested_size) override {
528+
// For most types of streams, OnStreamRead will be immediately after
529+
// OnStreamAlloc, and will consume all data, so using a static buffer for
530+
// reading is more efficient. For other streams, just use the default
531+
// allocator, which uses Malloc().
532+
if (env()->http_parser_buffer_in_use())
533+
return StreamListener::OnStreamAlloc(suggested_size);
534+
env()->set_http_parser_buffer_in_use(true);
535+
528536
if (env()->http_parser_buffer() == nullptr)
529537
env()->set_http_parser_buffer(new char[kAllocBufferSize]);
530538

@@ -534,6 +542,15 @@ class Parser : public AsyncWrap, public StreamListener {
534542

535543
void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override {
536544
HandleScope scope(env()->isolate());
545+
// Once we’re done here, either indicate that the HTTP parser buffer
546+
// is free for re-use, or free() the data if it didn’t come from there
547+
// in the first place.
548+
OnScopeLeave on_scope_leave([&]() {
549+
if (buf.base == env()->http_parser_buffer())
550+
env()->set_http_parser_buffer_in_use(false);
551+
else
552+
free(buf.base);
553+
});
537554

538555
if (nread < 0) {
539556
PassReadErrorToPreviousListener(nread);

src/util.h

+8
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,14 @@ class BufferValue : public MaybeStackBuffer<char> {
436436
template <typename T> inline void USE(T&&) {}
437437
} // namespace node
438438

439+
// Run a function when exiting the current scope.
440+
struct OnScopeLeave {
441+
std::function<void()> fn_;
442+
443+
explicit OnScopeLeave(std::function<void()> fn) : fn_(fn) {}
444+
~OnScopeLeave() { fn_(); }
445+
};
446+
439447
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
440448

441449
#endif // SRC_UTIL_H_

0 commit comments

Comments
 (0)