uWebSockets.js/src/HttpResponseWrapper.h

280 lines
12 KiB
C
Raw Normal View History

2019-01-14 12:17:08 +00:00
#include "App.h"
2019-01-14 10:45:25 +00:00
#include "Utilities.h"
#include <v8.h>
2019-01-14 10:45:25 +00:00
using namespace v8;
2019-01-14 12:17:08 +00:00
struct HttpResponseWrapper {
template <bool SSL>
static inline uWS::HttpResponse<SSL> *getHttpResponse(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
auto *res = (uWS::HttpResponse<SSL> *) args.Holder()->GetAlignedPointerFromInternalField(0);
if (!res) {
2019-11-08 12:49:40 +00:00
args.GetReturnValue().Set(isolate->ThrowException(String::NewFromUtf8(isolate, "Invalid access of discarded (invalid, deleted) uWS.HttpResponse/SSLHttpResponse.", NewStringType::kNormal).ToLocalChecked()));
}
return res;
}
/* Marks this JS object invalid */
static inline void invalidateResObject(const FunctionCallbackInfo<Value> &args) {
args.Holder()->SetAlignedPointerInInternalField(0, nullptr);
2019-01-14 12:17:08 +00:00
}
/* Takes nothing, kills the connection */
template <bool SSL>
static void res_close(const FunctionCallbackInfo<Value> &args) {
auto *res = getHttpResponse<SSL>(args);
if (res) {
invalidateResObject(args);
res->close();
args.GetReturnValue().Set(args.Holder());
}
}
/* Takes function of data and isLast. Expects nothing from callback, returns this */
template <bool SSL>
static void res_onData(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
auto *res = getHttpResponse<SSL>(args);
if (res) {
/* This thing perfectly fits in with unique_function, and will Reset on destructor */
UniquePersistent<Function> p(isolate, Local<Function>::Cast(args[0]));
res->onData([p = std::move(p), isolate](std::string_view data, bool last) {
HandleScope hs(isolate);
Local<ArrayBuffer> dataArrayBuffer = ArrayBuffer::New(isolate, (void *) data.data(), data.length());
Local<Value> argv[] = {dataArrayBuffer, Boolean::New(isolate, last)};
Local<Function>::New(isolate, p)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 2, argv).IsEmpty();
dataArrayBuffer->Neuter();
});
args.GetReturnValue().Set(args.Holder());
}
}
2019-01-15 07:10:57 +00:00
2019-01-17 05:42:45 +00:00
/* Takes nothing, returns nothing. Cb wants nothing returned. */
2019-01-17 05:31:55 +00:00
template <bool SSL>
static void res_onAborted(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
auto *res = getHttpResponse<SSL>(args);
if (res) {
/* This thing perfectly fits in with unique_function, and will Reset on destructor */
UniquePersistent<Function> p(isolate, Local<Function>::Cast(args[0]));
2019-01-17 05:31:55 +00:00
/* This is how we capture res (C++ this in invocation of this function) */
UniquePersistent<Object> resObject(isolate, args.Holder());
2019-01-17 05:31:55 +00:00
res->onAborted([p = std::move(p), resObject = std::move(resObject), isolate]() {
HandleScope hs(isolate);
2019-01-17 05:31:55 +00:00
/* Mark this resObject invalid */
Local<Object>::New(isolate, resObject)->SetAlignedPointerInInternalField(0, nullptr);
Local<Function>::New(isolate, p)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 0, nullptr).IsEmpty();
});
args.GetReturnValue().Set(args.Holder());
}
2019-01-17 05:31:55 +00:00
}
/* Takes nothing, returns arraybuffer */
template <bool SSL>
static void res_getRemoteAddress(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
auto *res = getHttpResponse<SSL>(args);
if (res) {
std::string_view ip = res->getRemoteAddress();
/* Todo: we need to pass a copy here */
args.GetReturnValue().Set(ArrayBuffer::New(isolate, (void *) ip.data(), ip.length()/*, ArrayBufferCreationMode::kInternalized*/));
}
}
/* Returns the current write offset */
template <bool SSL>
static void res_getWriteOffset(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
auto *res = getHttpResponse<SSL>(args);
if (res) {
args.GetReturnValue().Set(Integer::New(isolate, getHttpResponse<SSL>(args)->getWriteOffset()));
}
}
2019-01-15 07:10:57 +00:00
/* Takes function of bool(int), returns this */
template <bool SSL>
static void res_onWritable(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
auto *res = getHttpResponse<SSL>(args);
if (res) {
/* This thing perfectly fits in with unique_function, and will Reset on destructor */
UniquePersistent<Function> p(isolate, Local<Function>::Cast(args[0]));
2019-01-15 07:10:57 +00:00
res->onWritable([p = std::move(p), isolate](int offset) -> bool {
HandleScope hs(isolate);
2019-01-15 07:10:57 +00:00
Local<Value> argv[] = {Integer::NewFromUnsigned(isolate, offset)};
/* We should check if this is really here! */
MaybeLocal<Value> maybeBoolean = Local<Function>::New(isolate, p)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 1, argv);
if (maybeBoolean.IsEmpty()) {
std::cerr << "ERROR! onWritable must return a boolean value according to documentation!" << std::endl;
exit(-1);
}
2019-11-08 12:49:40 +00:00
return BooleanValue(isolate, maybeBoolean.ToLocalChecked());
/* How important is this return? */
});
2019-01-15 07:10:57 +00:00
args.GetReturnValue().Set(args.Holder());
}
2019-01-15 07:10:57 +00:00
}
/* Takes string or arraybuffer, returns this */
template <bool SSL>
static void res_writeStatus(const FunctionCallbackInfo<Value> &args) {
auto *res = getHttpResponse<SSL>(args);
if (res) {
NativeString data(args.GetIsolate(), args[0]);
if (data.isInvalid(args)) {
return;
}
res->writeStatus(data.getString());
args.GetReturnValue().Set(args.Holder());
}
}
2019-01-14 12:17:08 +00:00
/* Takes string or arraybuffer, returns this */
template <bool SSL>
static void res_end(const FunctionCallbackInfo<Value> &args) {
auto *res = getHttpResponse<SSL>(args);
if (res) {
NativeString data(args.GetIsolate(), args[0]);
if (data.isInvalid(args)) {
return;
}
invalidateResObject(args);
res->end(data.getString());
args.GetReturnValue().Set(args.Holder());
}
2019-01-14 12:17:08 +00:00
}
/* Takes data and optionally totalLength, returns true for success, false for backpressure */
template <bool SSL>
static void res_tryEnd(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
auto *res = getHttpResponse<SSL>(args);
if (res) {
NativeString data(args.GetIsolate(), args[0]);
if (data.isInvalid(args)) {
return;
}
int totalSize = 0;
if (args.Length() > 1) {
2019-04-24 01:01:54 +00:00
totalSize = args[1]->Uint32Value(isolate->GetCurrentContext()).ToChecked();
}
2019-02-09 22:32:07 +00:00
auto [ok, hasResponded] = res->tryEnd(data.getString(), totalSize);
/* Invalidate this object if we responded completely */
2019-02-09 22:32:07 +00:00
if (hasResponded) {
invalidateResObject(args);
}
/* This is a quick fix, it will need updating in µWS later on */
Local<Array> array = Array::New(isolate, 2);
2019-11-08 12:49:40 +00:00
array->Set(isolate->GetCurrentContext(), 0, Boolean::New(isolate, ok)).ToChecked();
array->Set(isolate->GetCurrentContext(), 1, Boolean::New(isolate, hasResponded)).ToChecked();
args.GetReturnValue().Set(array);
}
}
/* Takes data, returns true for success, false for backpressure */
template <bool SSL>
static void res_write(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
auto *res = getHttpResponse<SSL>(args);
if (res) {
NativeString data(args.GetIsolate(), args[0]);
if (data.isInvalid(args)) {
return;
}
bool ok = res->write(data.getString());
args.GetReturnValue().Set(Boolean::New(isolate, ok));
}
}
2019-01-14 12:17:08 +00:00
/* Takes key, value. Returns this */
template <bool SSL>
static void res_writeHeader(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
auto *res = getHttpResponse<SSL>(args);
if (res) {
NativeString header(args.GetIsolate(), args[0]);
if (header.isInvalid(args)) {
return;
}
NativeString value(args.GetIsolate(), args[1]);
if (value.isInvalid(args)) {
return;
}
res->writeHeader(header.getString(),value.getString());
args.GetReturnValue().Set(args.Holder());
}
2019-01-14 12:17:08 +00:00
}
2019-04-16 15:00:27 +00:00
/* Takes function, returns this (EXPERIMENTAL) */
template <bool SSL>
static void res_cork(const FunctionCallbackInfo<Value> &args) {
Isolate *isolate = args.GetIsolate();
2019-04-16 15:00:27 +00:00
auto *res = getHttpResponse<SSL>(args);
if (res) {
res->cork([cb = Local<Function>::Cast(args[0]), isolate]() {
cb->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 0, nullptr).IsEmpty();
2019-04-16 15:00:27 +00:00
});
args.GetReturnValue().Set(args.Holder());
}
}
2019-01-14 12:17:08 +00:00
template <bool SSL>
static Local<Object> init(Isolate *isolate) {
2019-01-14 12:17:08 +00:00
Local<FunctionTemplate> resTemplateLocal = FunctionTemplate::New(isolate);
if (SSL) {
2019-11-08 12:49:40 +00:00
resTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uWS.SSLHttpResponse", NewStringType::kNormal).ToLocalChecked());
2019-01-14 12:17:08 +00:00
} else {
2019-11-08 12:49:40 +00:00
resTemplateLocal->SetClassName(String::NewFromUtf8(isolate, "uWS.HttpResponse", NewStringType::kNormal).ToLocalChecked());
2019-01-14 12:17:08 +00:00
}
resTemplateLocal->InstanceTemplate()->SetInternalFieldCount(1);
/* Register our functions */
2019-11-08 12:49:40 +00:00
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "writeStatus", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_writeStatus<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "end", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_end<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "tryEnd", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_tryEnd<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "write", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_write<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "writeHeader", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_writeHeader<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "close", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_close<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getWriteOffset", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getWriteOffset<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onWritable", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onWritable<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onAborted", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onAborted<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "onData", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_onData<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "getRemoteAddress", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_getRemoteAddress<SSL>));
resTemplateLocal->PrototypeTemplate()->Set(String::NewFromUtf8(isolate, "experimental_cork", NewStringType::kNormal).ToLocalChecked(), FunctionTemplate::New(isolate, res_cork<SSL>));
2019-01-15 07:10:57 +00:00
2019-01-14 12:17:08 +00:00
/* Create our template */
2019-04-24 01:01:54 +00:00
Local<Object> resObjectLocal = resTemplateLocal->GetFunction(isolate->GetCurrentContext()).ToLocalChecked()->NewInstance(isolate->GetCurrentContext()).ToLocalChecked();
return resObjectLocal;
2019-01-14 12:17:08 +00:00
}
};