Skip to content
Open
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: 3 additions & 0 deletions docs/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>) : 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. */
log(cb: (req: HttpRequest | null, statusCode: number, responseBody: ArrayBuffer) => void | Promise<void>) : TemplatedApp;
/** Closes all sockets including listen sockets. This will forcefully terminate all connections. */
close() : TemplatedApp;
}
Expand Down
30 changes: 30 additions & 0 deletions examples/HttpParsingLogHandling.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const uWS = require('../src/uws.js');

const app = uWS.App({
// Optional SSL configuration
}).log((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');
}
});
40 changes: 40 additions & 0 deletions src/AppWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,45 @@ void uWS_App_filter(const FunctionCallbackInfo<Value> &args) {
args.GetReturnValue().Set(args.This());
}

template <typename APP>
void uWS_App_log(const FunctionCallbackInfo<Value> &args) {
APP *app = (APP *) args.This()->GetAlignedPointerFromInternalField(0);

/* Handler */
Callback checkedCallback(args.GetIsolate(), args[0]);
if (checkedCallback.isInvalid(args)) {
return;
}
UniquePersistent<Function> cb = checkedCallback.getFunction();

/* This function requires perContextData */
PerContextData *perContextData = (PerContextData *) Local<External>::Cast(args.Data())->Value();

app->log([cb = std::move(cb), perContextData](auto *req, int statusCode, std::string_view responseBody) {
Isolate *isolate = perContextData->isolate;
HandleScope hs(isolate);

Local<Object> reqObject;
if (req) {
reqObject = perContextData->reqTemplate[getAppTypeIndex<APP>()].Get(isolate)->Clone();
reqObject->SetAlignedPointerInInternalField(0, req);
} else {
reqObject = Local<Object>::Cast(Null(isolate));
}

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

Local<Value> argv[] = {reqObject, Local<Value>::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 <typename APP>
void uWS_App_domain(const FunctionCallbackInfo<Value> &args) {
APP *app = (APP *) args.This()->GetAlignedPointerFromInternalField(0);
Expand Down Expand Up @@ -996,6 +1035,7 @@ void uWS_App(const FunctionCallbackInfo<Value> &args) {
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "close", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_close<APP>, args.Data()));
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "listen_unix", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_listen_unix<APP>, args.Data()));
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "filter", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_filter<APP>, args.Data()));
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "log", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_log<APP>, args.Data()));

/* load balancing */
appTemplate->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "removeChildAppDescriptor", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, uWS_App_removeChildApp<APP>, args.Data()));
Expand Down