Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 41 additions & 34 deletions src/node_http_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -124,70 +124,76 @@ class BindingData : public BaseObject {

// helper class for the Parser
struct StringPtr {
StringPtr() {
on_heap_ = false;
Reset();
}

// Memory impact: ~8KB per parser (66 StringPtr × 128 bytes).
Copy link

Copilot AI Jan 13, 2026

Choose a reason for hiding this comment

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

The memory calculation is slightly inaccurate. 66 × 128 = 8,448 bytes, which is approximately 8.25KB, not 8KB. Consider updating to '~8.4KB' or '~8.5KB' for better accuracy.

Suggested change
// Memory impact: ~8KB per parser (66 StringPtr × 128 bytes).
// Memory impact: ~8.4KB per parser (66 StringPtr × 128 bytes).

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

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

Thank you overly pedantic AI code review. The ~8KB is accurate enough here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I agree.

static constexpr size_t kSlabSize = 128;

~StringPtr() {
Reset();
}
StringPtr() = default;
~StringPtr() { Reset(); }

StringPtr(const StringPtr&) = delete;
StringPtr& operator=(const StringPtr&) = delete;

// If str_ does not point to a heap string yet, this function makes it do
// so. This is called at the end of each http_parser_execute() so as not
// to leak references. See issue #2438 and test-http-parser-bad-ref.js.
void Save() {
if (!on_heap_ && size_ > 0) {
char* s = new char[size_];
memcpy(s, str_, size_);
str_ = s;
on_heap_ = true;
if (!on_heap_ && !using_slab_ && size_ > 0) {
if (size_ <= kSlabSize) {
memcpy(slab_, str_, size_);
str_ = slab_;
using_slab_ = true;
} else {
char* s = new char[size_];
memcpy(s, str_, size_);
str_ = s;
on_heap_ = true;
}
}
}


void Reset() {
if (on_heap_) {
delete[] str_;
on_heap_ = false;
}

using_slab_ = false;
str_ = nullptr;
size_ = 0;
}


void Update(const char* str, size_t size) {
if (str_ == nullptr) {
str_ = str;
} else if (on_heap_ || str_ + size_ != str) {
// Non-consecutive input, make a copy on the heap.
// TODO(bnoordhuis) Use slab allocation, O(n) allocs is bad.
char* s = new char[size_ + size];
memcpy(s, str_, size_);
memcpy(s + size_, str, size);

if (on_heap_)
delete[] str_;
else
} else if (on_heap_ || using_slab_ || str_ + size_ != str) {
const size_t total = size_ + size;

if (!on_heap_ && total <= kSlabSize) {
if (!using_slab_) {
memcpy(slab_, str_, size_);
using_slab_ = true;
}
memcpy(slab_ + size_, str, size);
str_ = slab_;
} else {
char* s = new char[total];
memcpy(s, str_, size_);
memcpy(s + size_, str, size);
if (on_heap_) delete[] str_;
on_heap_ = true;

str_ = s;
using_slab_ = false;
str_ = s;
}
}
size_ += size;
}


Local<String> ToString(Environment* env) const {
if (size_ != 0)
return OneByteString(env->isolate(), str_, size_);
else
return String::Empty(env->isolate());
}


// Strip trailing OWS (SPC or HTAB) from string.
Local<String> ToTrimmedString(Environment* env) {
while (size_ > 0 && IsOWS(str_[size_ - 1])) {
Expand All @@ -196,10 +202,11 @@ struct StringPtr {
return ToString(env);
}


const char* str_;
bool on_heap_;
size_t size_;
const char* str_ = nullptr;
bool on_heap_ = false;
bool using_slab_ = false;
size_t size_ = 0;
char slab_[kSlabSize];
};

class Parser;
Expand Down
Loading