From 4ae2facba745ab052354e21039987054b83bb288 Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Thu, 17 Jan 2019 08:22:43 +0100 Subject: [PATCH] Wrap req.getQuery, req.getMethod, res.close, res.onData & add Upload example --- examples/Upload.js | 36 ++++++++++++++++++++++++++++++++++++ src/HttpRequestWrapper.h | 15 +++++++++++++++ src/HttpResponseWrapper.h | 31 +++++++++++++++++++++++++++++-- src/WebSocketWrapper.h | 2 ++ uWebSockets | 2 +- 5 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 examples/Upload.js diff --git a/examples/Upload.js b/examples/Upload.js new file mode 100644 index 0000000..7c652c4 --- /dev/null +++ b/examples/Upload.js @@ -0,0 +1,36 @@ +/* Minimal POST example a SSL/non-SSL */ +/* todo: proper throttling, better example */ + +/* a good example would be using the router to get + * a file name and stream that file to disk */ + +const uWS = require('../dist/uws.js'); +const port = 9001; + +const app = uWS./*SSL*/App({ + key_file_name: '/home/alexhultman/key.pem', + cert_file_name: '/home/alexhultman/cert.pem', + passphrase: '1234' +}).post('/*', (res, req) => { + console.log('Posted to ' + req.getUrl()); + res.onData((chunk, isLast) => { + /* Buffer this anywhere you want to */ + console.log('Got chunk of data with length ' + chunk.byteLength + ', isLast: ' + isLast); + + /* We respond when we are done */ + if (isLast) { + res.end('Thanks for the data!'); + } + }); + + res.onAborted(() => { + /* Request was prematurely aborted, stop reading */ + console.log('Eh, okay. Thanks for nothing!'); + }); +}).listen(port, (token) => { + if (token) { + console.log('Listening to port ' + port); + } else { + console.log('Failed to listen to port ' + port); + } +}); diff --git a/src/HttpRequestWrapper.h b/src/HttpRequestWrapper.h index 1bce519..ab3121c 100644 --- a/src/HttpRequestWrapper.h +++ b/src/HttpRequestWrapper.h @@ -44,16 +44,31 @@ struct HttpRequestWrapper { args.GetReturnValue().Set(String::NewFromUtf8(isolate, header.data(), v8::String::kNormalString, header.length())); } + static void req_getMethod(const FunctionCallbackInfo &args) { + std::string_view method = getHttpRequest(args)->getMethod(); + + args.GetReturnValue().Set(String::NewFromUtf8(isolate, method.data(), v8::String::kNormalString, method.length())); + } + + static void req_getQuery(const FunctionCallbackInfo &args) { + std::string_view query = getHttpRequest(args)->getQuery(); + + args.GetReturnValue().Set(String::NewFromUtf8(isolate, query.data(), v8::String::kNormalString, query.length())); + } + static void initReqTemplate() { /* We do clone every request object, we could share them, they are illegal to use outside the function anyways */ Local reqTemplateLocal = FunctionTemplate::New(isolate); reqTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uWS.HttpRequest")); reqTemplateLocal->InstanceTemplate()->SetInternalFieldCount(1); + /* Register our functions */ reqTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getHeader"), FunctionTemplate::New(isolate, req_getHeader)); reqTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getParameter"), FunctionTemplate::New(isolate, req_getParameter)); reqTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getUrl"), FunctionTemplate::New(isolate, req_getUrl)); + reqTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getMethod"), FunctionTemplate::New(isolate, req_getMethod)); + reqTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getQuery"), FunctionTemplate::New(isolate, req_getQuery)); /* Create the template */ Local reqObjectLocal = reqTemplateLocal->GetFunction()->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); diff --git a/src/HttpResponseWrapper.h b/src/HttpResponseWrapper.h index 0ca5b6b..99b4383 100644 --- a/src/HttpResponseWrapper.h +++ b/src/HttpResponseWrapper.h @@ -11,7 +11,33 @@ struct HttpResponseWrapper { return (uWS::HttpResponse *) args.Holder()->GetAlignedPointerFromInternalField(0); } - // res.onData(JS function) + /* Takes nothing, kills the connection */ + template + static void res_close(const FunctionCallbackInfo &args) { + getHttpResponse(args)->close(); + + args.GetReturnValue().Set(args.Holder()); + } + + /* Takes function of data and isLast. Expects nothing from callback, returns this */ + template + static void res_onData(const FunctionCallbackInfo &args) { + /* This thing perfectly fits in with unique_function, and will Reset on destructor */ + UniquePersistent p(isolate, Local::Cast(args[0])); + + getHttpResponse(args)->onData([p = std::move(p)](std::string_view data, bool last) { + HandleScope hs(isolate); + + Local dataArrayBuffer = ArrayBuffer::New(isolate, (void *) data.data(), data.length()); + + Local argv[] = {dataArrayBuffer, Boolean::New(isolate, last)}; + Local::New(isolate, p)->Call(isolate->GetCurrentContext()->Global(), 2, argv); + + dataArrayBuffer->Neuter(); + }); + + args.GetReturnValue().Set(args.Holder()); + } /* Takes nothing, returns nothing. Cb wants nothing returned. */ template @@ -119,10 +145,11 @@ struct HttpResponseWrapper { resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "tryEnd"), FunctionTemplate::New(isolate, res_tryEnd)); resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "write"), FunctionTemplate::New(isolate, res_write)); resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "writeHeader"), FunctionTemplate::New(isolate, res_writeHeader)); - + resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "close"), FunctionTemplate::New(isolate, res_close)); resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getWriteOffset"), FunctionTemplate::New(isolate, res_getWriteOffset)); resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onWritable"), FunctionTemplate::New(isolate, res_onWritable)); resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onAborted"), FunctionTemplate::New(isolate, res_onAborted)); + resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onData"), FunctionTemplate::New(isolate, res_onData)); /* Create our template */ Local resObjectLocal = resTemplateLocal->GetFunction()->NewInstance(isolate->GetCurrentContext()).ToLocalChecked(); diff --git a/src/WebSocketWrapper.h b/src/WebSocketWrapper.h index 2d98158..837f0cc 100644 --- a/src/WebSocketWrapper.h +++ b/src/WebSocketWrapper.h @@ -3,6 +3,8 @@ #include "Utilities.h" using namespace v8; +// todo: probably isCorked, cork should be exposed? + struct WebSocketWrapper { static Persistent wsTemplate[2]; diff --git a/uWebSockets b/uWebSockets index 2a62218..04281ee 160000 --- a/uWebSockets +++ b/uWebSockets @@ -1 +1 @@ -Subproject commit 2a62218d2a4344255463eeb7b1cbda507f90e86f +Subproject commit 04281eeea649d2d9d527644eba5866de44b64502