Skip to content
Closed
Show file tree
Hide file tree
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
3 changes: 0 additions & 3 deletions docs/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,6 @@ export interface HttpResponse {
/** Returns the global byte write offset for this response. Use with onWritable. */
getWriteOffset() : number;

/** Returns the max remaining body length of the currently read HTTP body. */
maxRemainingBodyLength() : bigint;

/** Registers a handler for writable events. Continue failed write attempts in here.
* You MUST return true for success, false for failure.
* Writing nothing is always success, so by default you must return true.
Expand Down
27 changes: 8 additions & 19 deletions src/HttpResponseWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,13 @@ struct HttpResponseWrapper {
std::unique_ptr<std::vector<char>> buffer;
bool overflow = false;

res->onData([res, p = std::move(p), buffer = std::move(buffer), overflow, maxSize, isolate](std::string_view data, bool last) mutable {
res->onDataV2([p = std::move(p), buffer = std::move(buffer), overflow, maxSize, isolate](std::string_view data, uint64_t maxRemainingBodyLength) mutable {
HandleScope hs(isolate);

if (!overflow) {
if (!buffer) {
/* Fast path: this is the very first (and possibly only) chunk */
if (last) {
if (maxRemainingBodyLength == 0) {
if (data.size() <= maxSize) {
/* Single-chunk zero-copy: wrap data directly, detach after call like onData */
Local<ArrayBuffer> ab = ArrayBuffer_New(isolate, (void *) data.data(), data.size());
Expand All @@ -164,9 +164,9 @@ struct HttpResponseWrapper {
/* Slow path begins: allocate buffer lazily for first non-terminal chunk */
if (data.size() <= maxSize) {
buffer = std::make_unique<std::vector<char>>();
/* Preallocate with hint */
if (res->maxRemainingBodyLength() <= maxSize) {
buffer->reserve(res->maxRemainingBodyLength()); // this includes the total size on first call (look over this)
/* Preallocate with hint: total = current chunk + remaining; subtraction is safe since data.size() <= maxSize (outer check); guards against chunked encoding (UINT64_MAX) */
if (maxRemainingBodyLength <= maxSize - data.size()) {
buffer->reserve(data.size() + maxRemainingBodyLength);
}
buffer->assign(data.begin(), data.end());
} else {
Expand All @@ -183,7 +183,7 @@ struct HttpResponseWrapper {
}
}

if (last) {
if (maxRemainingBodyLength == 0) {
if (!overflow) {
/* Zero-copy: hand V8 the vector's own memory via a custom deleter */
auto *rawBuffer = buffer.release();
Expand Down Expand Up @@ -233,13 +233,13 @@ struct HttpResponseWrapper {
CallJS(isolate, Local<Function>::New(isolate, *sharedP), 2, argv);
});

res->onData([res, sharedP, isolate](std::string_view data, bool last) {
res->onDataV2([sharedP, isolate](std::string_view data, uint64_t maxRemainingBodyLength) {
HandleScope hs(isolate);

Local<ArrayBuffer> dataArrayBuffer = ArrayBuffer_New(isolate, (void *) data.data(), data.length());

/* Pass maxRemainingBodyLength so user can preallocate; 0 signals the last chunk */
Local<Value> argv[] = {dataArrayBuffer, BigInt::NewFromUnsigned(isolate, res->maxRemainingBodyLength())};
Local<Value> argv[] = {dataArrayBuffer, BigInt::NewFromUnsigned(isolate, maxRemainingBodyLength)};
CallJS(isolate, Local<Function>::New(isolate, *sharedP), 2, argv);

dataArrayBuffer->Detach();
Expand Down Expand Up @@ -368,16 +368,6 @@ struct HttpResponseWrapper {
}
}

/* Returns the max remaining body length */
template <int SSL>
static void res_maxRemainingBodyLength(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
auto *res = getHttpResponse<SSL>(args);
if (res) {
args.GetReturnValue().Set(BigInt::NewFromUnsigned(isolate, res->maxRemainingBodyLength()));
}
}

/* Takes function of bool(int), returns this */
template <int SSL>
static void res_onWritable(const FunctionCallbackInfo<Value> &args) {
Expand Down Expand Up @@ -641,7 +631,6 @@ struct HttpResponseWrapper {
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onStream", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onStream<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onFullData", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onFullData<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getWriteOffset", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getWriteOffset<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "maxRemainingBodyLength", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_maxRemainingBodyLength<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getRemoteAddress", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getRemoteAddress<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "cork", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_cork<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "collect", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_cork<SSL>));
Expand Down
2 changes: 1 addition & 1 deletion uWebSockets