From d2fa3acd8f82fc5badc47c20ad2f354a07cf639d Mon Sep 17 00:00:00 2001 From: Philip Deltour Date: Thu, 2 Oct 2025 09:26:38 +0000 Subject: [PATCH 1/3] Add callback handler to report internal HTTP parsing errors(431, 400, 505) --- docs/index.d.ts | 3 +++ examples/HttpParsingErrorHandling.js | 30 +++++++++++++++++++++ src/AppWrapper.h | 40 ++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 examples/HttpParsingErrorHandling.js diff --git a/docs/index.d.ts b/docs/index.d.ts index 5199f608..b222d21c 100644 --- a/docs/index.d.ts +++ b/docs/index.d.ts @@ -329,6 +329,9 @@ export interface TemplatedApp { missingServerName(cb: (hostname: string) => void) : TemplatedApp; /** Attaches a "filter" function to track socket connections / disconnections */ filter(cb: (res: HttpResponse, count: Number) => void | Promise) : TemplatedApp; + /** Registers an HTTP parsing error handler that is called when malformed HTTP requests are encountered. + * The handler receives the request object (or null if request is too malformed), HTTP status code, and complete response body. */ + onHttpParsingError(cb: (req: HttpRequest | null, statusCode: number, responseBody: ArrayBuffer) => void | Promise) : TemplatedApp; /** Closes all sockets including listen sockets. This will forcefully terminate all connections. */ close() : TemplatedApp; } diff --git a/examples/HttpParsingErrorHandling.js b/examples/HttpParsingErrorHandling.js new file mode 100644 index 00000000..3bd8375f --- /dev/null +++ b/examples/HttpParsingErrorHandling.js @@ -0,0 +1,30 @@ +const uWS = require('../src/uws.js'); + +const app = uWS.App({ + // Optional SSL configuration +}).onHttpParsingError((req, httpStatus, responseBody) => { + console.log('HTTP parsing error occurred with status:', httpStatus); + + if (req) { + console.log('Request URL:', req.getUrl()); + console.log('Request method:', req.getMethod()); + console.log('Request headers:', req.getHeader('host')); + } else { + console.log('Request information not available (parsing failed early)'); + } + + // Log the response body that will be sent to the client + console.log('Response body length:', responseBody.byteLength); + console.log('Response preview:', Buffer.from(responseBody).toString().substring(0, 100) + '...'); + + // High-level program can now handle the error gracefully + // The socket will be closed automatically after this handler runs +}).get('/*', (res, req) => { + res.end('Hello World!'); +}).listen(9001, (token) => { + if (token) { + console.log('Listening to port 9001 with HTTP parsing error handling'); + } else { + console.log('Failed to listen to port 9001'); + } +}); diff --git a/src/AppWrapper.h b/src/AppWrapper.h index 63bb97de..3044e4d0 100644 --- a/src/AppWrapper.h +++ b/src/AppWrapper.h @@ -570,6 +570,45 @@ void uWS_App_filter(const FunctionCallbackInfo &args) { args.GetReturnValue().Set(args.This()); } +template +void uWS_App_onHttpParsingError(const FunctionCallbackInfo &args) { + APP *app = (APP *) args.This()->GetAlignedPointerFromInternalField(0); + + /* Handler */ + Callback checkedCallback(args.GetIsolate(), args[0]); + if (checkedCallback.isInvalid(args)) { + return; + } + UniquePersistent cb = checkedCallback.getFunction(); + + /* This function requires perContextData */ + PerContextData *perContextData = (PerContextData *) Local::Cast(args.Data())->Value(); + + app->onHttpParsingError([cb = std::move(cb), perContextData](auto *req, int statusCode, std::string_view responseBody) { + Isolate *isolate = perContextData->isolate; + HandleScope hs(isolate); + + Local reqObject; + if (req) { + reqObject = perContextData->reqTemplate[getAppTypeIndex()].Get(isolate)->Clone(); + reqObject->SetAlignedPointerInInternalField(0, req); + } else { + reqObject = Local::Cast(Null(isolate)); + } + + Local responseBodyBuffer = ArrayBuffer_New(isolate, (void *) responseBody.data(), responseBody.length()); + + Local argv[] = {reqObject, Local::Cast(Integer::New(isolate, statusCode)), responseBodyBuffer}; + CallJS(isolate, cb.Get(isolate), 3, argv); + + /* Important: we clear the ArrayBuffer to make sure it is not invalidly used after return */ + responseBodyBuffer->Detach(); + }); + + args.GetReturnValue().Set(args.This()); +} + + template void uWS_App_domain(const FunctionCallbackInfo &args) { APP *app = (APP *) args.This()->GetAlignedPointerFromInternalField(0); @@ -996,6 +1035,7 @@ void uWS_App(const FunctionCallbackInfo &args) { appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "close", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_close, args.Data())); appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "listen_unix", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_listen_unix, args.Data())); appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "filter", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_filter, args.Data())); + appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onHttpParsingError", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_onHttpParsingError, args.Data())); /* load balancing */ appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "removeChildAppDescriptor", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_removeChildApp, args.Data())); From e598b0168f9a6a75b8b648a4875f2ce1f139d908 Mon Sep 17 00:00:00 2001 From: Philip Deltour Date: Tue, 7 Oct 2025 08:32:28 +0000 Subject: [PATCH 2/3] renamed callack to log --- docs/index.d.ts | 2 +- examples/HttpParsingErrorHandling.js | 2 +- src/AppWrapper.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/index.d.ts b/docs/index.d.ts index b222d21c..3c465244 100644 --- a/docs/index.d.ts +++ b/docs/index.d.ts @@ -331,7 +331,7 @@ export interface TemplatedApp { filter(cb: (res: HttpResponse, count: Number) => void | Promise) : TemplatedApp; /** Registers an HTTP parsing error handler that is called when malformed HTTP requests are encountered. * The handler receives the request object (or null if request is too malformed), HTTP status code, and complete response body. */ - onHttpParsingError(cb: (req: HttpRequest | null, statusCode: number, responseBody: ArrayBuffer) => void | Promise) : TemplatedApp; + log(cb: (req: HttpRequest | null, statusCode: number, responseBody: ArrayBuffer) => void | Promise) : TemplatedApp; /** Closes all sockets including listen sockets. This will forcefully terminate all connections. */ close() : TemplatedApp; } diff --git a/examples/HttpParsingErrorHandling.js b/examples/HttpParsingErrorHandling.js index 3bd8375f..e9d73e17 100644 --- a/examples/HttpParsingErrorHandling.js +++ b/examples/HttpParsingErrorHandling.js @@ -2,7 +2,7 @@ const uWS = require('../src/uws.js'); const app = uWS.App({ // Optional SSL configuration -}).onHttpParsingError((req, httpStatus, responseBody) => { +}).log((req, httpStatus, responseBody) => { console.log('HTTP parsing error occurred with status:', httpStatus); if (req) { diff --git a/src/AppWrapper.h b/src/AppWrapper.h index 3044e4d0..bc51640f 100644 --- a/src/AppWrapper.h +++ b/src/AppWrapper.h @@ -571,7 +571,7 @@ void uWS_App_filter(const FunctionCallbackInfo &args) { } template -void uWS_App_onHttpParsingError(const FunctionCallbackInfo &args) { +void uWS_App_log(const FunctionCallbackInfo &args) { APP *app = (APP *) args.This()->GetAlignedPointerFromInternalField(0); /* Handler */ @@ -584,7 +584,7 @@ void uWS_App_onHttpParsingError(const FunctionCallbackInfo &args) { /* This function requires perContextData */ PerContextData *perContextData = (PerContextData *) Local::Cast(args.Data())->Value(); - app->onHttpParsingError([cb = std::move(cb), perContextData](auto *req, int statusCode, std::string_view responseBody) { + app->log([cb = std::move(cb), perContextData](auto *req, int statusCode, std::string_view responseBody) { Isolate *isolate = perContextData->isolate; HandleScope hs(isolate); @@ -1035,7 +1035,7 @@ void uWS_App(const FunctionCallbackInfo &args) { appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "close", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_close, args.Data())); appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "listen_unix", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_listen_unix, args.Data())); appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "filter", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_filter, args.Data())); - appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onHttpParsingError", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_onHttpParsingError, args.Data())); + appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "log", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_log, args.Data())); /* load balancing */ appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "removeChildAppDescriptor", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_removeChildApp, args.Data())); From 96ad4bcf708d3aebaeb87cec687d801e2c98f273 Mon Sep 17 00:00:00 2001 From: Philip Deltour Date: Tue, 7 Oct 2025 08:35:33 +0000 Subject: [PATCH 3/3] renamed example --- .../{HttpParsingErrorHandling.js => HttpParsingLogHandling.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{HttpParsingErrorHandling.js => HttpParsingLogHandling.js} (100%) diff --git a/examples/HttpParsingErrorHandling.js b/examples/HttpParsingLogHandling.js similarity index 100% rename from examples/HttpParsingErrorHandling.js rename to examples/HttpParsingLogHandling.js