diff options
Diffstat (limited to 'libdeno/binding.cc')
-rw-r--r-- | libdeno/binding.cc | 93 |
1 files changed, 76 insertions, 17 deletions
diff --git a/libdeno/binding.cc b/libdeno/binding.cc index b3c59c3ec..a790573a7 100644 --- a/libdeno/binding.cc +++ b/libdeno/binding.cc @@ -25,6 +25,36 @@ Deno* FromIsolate(v8::Isolate* isolate) { return static_cast<Deno*>(isolate->GetData(0)); } +void LazilyCreateDataMap(Deno* d) { + if (d->async_data_map.IsEmpty()) { + v8::HandleScope handle_scope(d->isolate); + // It's important for security reasons that async_data_map is not exposed to + // the VM. + auto async_data_map = v8::Map::New(d->isolate); + d->async_data_map.Reset(d->isolate, async_data_map); + } + DCHECK(!d->async_data_map.IsEmpty()); +} + +void AddDataRef(Deno* d, int32_t req_id, v8::Local<v8::Value> data_v) { + LazilyCreateDataMap(d); + auto async_data_map = d->async_data_map.Get(d->isolate); + auto context = d->context.Get(d->isolate); + auto req_id_v = v8::Integer::New(d->isolate, req_id); + auto r = async_data_map->Set(context, req_id_v, data_v); + CHECK(!r.IsEmpty()); +} + +void DeleteDataRef(Deno* d, int32_t req_id) { + LazilyCreateDataMap(d); + auto context = d->context.Get(d->isolate); + // Delete persistent reference to data ArrayBuffer. + auto async_data_map = d->async_data_map.Get(d->isolate); + auto req_id_v = v8::Integer::New(d->isolate, req_id); + auto maybe_deleted = async_data_map->Delete(context, req_id_v); + DCHECK(maybe_deleted.IsJust()); +} + // Extracts a C string from a v8::V8 Utf8Value. const char* ToCString(const v8::String::Utf8Value& value) { return *value ? *value : "<string conversion failed>"; @@ -214,17 +244,40 @@ void Send(const v8::FunctionCallbackInfo<v8::Value>& args) { v8::Locker locker(d->isolate); v8::EscapableHandleScope handle_scope(isolate); - CHECK_EQ(args.Length(), 1); - v8::Local<v8::Value> ab_v = args[0]; - CHECK(ab_v->IsArrayBufferView()); - auto buf = GetContents(isolate, v8::Local<v8::ArrayBufferView>::Cast(ab_v)); + CHECK_EQ(d->currentArgs, nullptr); // libdeno.send re-entry forbidden. + int32_t req_id = d->next_req_id++; + + v8::Local<v8::Value> control_v = args[0]; + CHECK(control_v->IsArrayBufferView()); + deno_buf control = + GetContents(isolate, v8::Local<v8::ArrayBufferView>::Cast(control_v)); + deno_buf data = {nullptr, 0u, nullptr, 0u}; + v8::Local<v8::Value> data_v; + if (args.Length() == 2) { + if (args[1]->IsArrayBufferView()) { + data_v = args[1]; + data = GetContents(isolate, v8::Local<v8::ArrayBufferView>::Cast(data_v)); + } + } else { + CHECK_EQ(args.Length(), 1); + } DCHECK_EQ(d->currentArgs, nullptr); d->currentArgs = &args; - d->cb(d, buf); + d->cb(d, req_id, control, data); - d->currentArgs = nullptr; + if (d->currentArgs == nullptr) { + // This indicates that deno_repond() was called already. + } else { + // Asynchronous. + d->currentArgs = nullptr; + // If the data ArrayBuffer was given, we must maintain a strong reference + // to it until deno_respond is called. + if (!data_v.IsEmpty()) { + AddDataRef(d, req_id, data_v); + } + } } // Sets the global error handler. @@ -358,6 +411,7 @@ void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context, } void AddIsolate(Deno* d, v8::Isolate* isolate) { + d->next_req_id = 0; d->isolate = isolate; // Leaving this code here because it will probably be useful later on, but // disabling it now as I haven't got tests for the desired behavior. @@ -400,7 +454,17 @@ int deno_execute(Deno* d, const char* js_filename, const char* js_source) { return deno::Execute(context, js_filename, js_source) ? 1 : 0; } -int deno_send(Deno* d, deno_buf buf) { +int deno_respond(Deno* d, int32_t req_id, deno_buf buf) { + if (d->currentArgs != nullptr) { + // Synchronous response. + auto ab = deno::ImportBuf(d->isolate, buf); + d->currentArgs->GetReturnValue().Set(ab); + d->currentArgs = nullptr; + return 0; + } + + // Asynchronous response. + v8::Locker locker(d->isolate); v8::Isolate::Scope isolate_scope(d->isolate); v8::HandleScope handle_scope(d->isolate); @@ -410,10 +474,12 @@ int deno_send(Deno* d, deno_buf buf) { v8::TryCatch try_catch(d->isolate); + deno::DeleteDataRef(d, req_id); + auto recv = d->recv.Get(d->isolate); if (recv.IsEmpty()) { d->last_exception = "libdeno.recv has not been called."; - return 0; + return 1; } v8::Local<v8::Value> args[1]; @@ -422,17 +488,10 @@ int deno_send(Deno* d, deno_buf buf) { if (try_catch.HasCaught()) { deno::HandleException(context, try_catch.Exception()); - return 0; + return 1; } - return 1; -} - -void deno_set_response(Deno* d, deno_buf buf) { - // printf("deno_set_response: "); - // hexdump(buf.data_ptr, buf.data_len); - auto ab = deno::ImportBuf(d->isolate, buf); - d->currentArgs->GetReturnValue().Set(ab); + return 0; } void deno_delete(Deno* d) { |