Guard against callback being called twice

This commit is contained in:
Cheng Zhao 2015-08-12 13:43:27 +08:00
parent 96d53d279e
commit ee51e37db7
3 changed files with 26 additions and 19 deletions

View file

@ -21,14 +21,21 @@ struct CallbackHolder {
// Cached JavaScript version of |HandlerCallback|.
v8::Persistent<v8::FunctionTemplate> g_handler_callback_;
// Cached C++ version of |Function.prototype.bind|.
base::Callback<v8::Local<v8::Value>(
v8::Local<v8::Value>, v8::Local<v8::Value>, v8::Local<v8::Value>)> g_bind;
// The callback which is passed to |handler|.
void HandlerCallback(v8::Local<v8::External> external, mate::Arguments* args) {
void HandlerCallback(v8::Isolate* isolate,
v8::Local<v8::External> external,
v8::Local<v8::Object> state,
mate::Arguments* args) {
// Check if the callback has already been called.
v8::Local<v8::String> called_symbol = mate::StringToSymbol(isolate, "called");
if (state->Has(called_symbol))
return; // no nothing
else
state->Set(called_symbol, v8::Boolean::New(isolate, true));
// If there is no argument passed then we failed.
scoped_ptr<CallbackHolder> holder(
static_cast<CallbackHolder*>(external->Value()));
static_cast<CallbackHolder*>(external->Value()));
CHECK(holder);
v8::Local<v8::Value> value;
if (!args->GetNext(&value)) {
@ -36,13 +43,14 @@ void HandlerCallback(v8::Local<v8::External> external, mate::Arguments* args) {
return;
}
// Pass whatever user passed to the actaul request job.
V8ValueConverter converter;
v8::Local<v8::Context> context = args->isolate()->GetCurrentContext();
scoped_ptr<base::Value> options(converter.FromV8Value(value, context));
holder->callback.Run(true, options.Pass());
}
// func.bind(...).
// func.bind(func, ...).
template<typename... ArgTypes>
v8::Local<v8::Value> BindFunctionWith(v8::Isolate* isolate,
v8::Local<v8::Context> context,
@ -75,7 +83,8 @@ v8::MaybeLocal<v8::Value> GenerateCallback(v8::Isolate* isolate,
holder->callback = callback;
return BindFunctionWith(isolate, context,
handler_callback->GetFunction(),
v8::External::New(isolate, holder));
v8::External::New(isolate, holder),
v8::Object::New(isolate));
}
} // namespace

View file

@ -64,7 +64,7 @@ class JsAsker : public RequestJob {
// Called when the JS handler has sent the response, we need to decide whether
// to start, or fail the job.
void OnResponse(bool success, scoped_ptr<base::Value> options) {
if (success) {
if (success && options) {
StartAsync(options.Pass());
} else {
RequestJob::NotifyStartError(

View file

@ -19,16 +19,14 @@ URLRequestStringJob::URLRequestStringJob(net::URLRequest* request,
}
void URLRequestStringJob::StartAsync(scoped_ptr<base::Value> options) {
if (options) {
if (options->IsType(base::Value::TYPE_DICTIONARY)) {
base::DictionaryValue* dict =
static_cast<base::DictionaryValue*>(options.get());
dict->GetString("mimeType", &mime_type_);
dict->GetString("charset", &charset_);
dict->GetString("data", &data_);
} else if (options->IsType(base::Value::TYPE_STRING)) {
options->GetAsString(&data_);
}
if (options->IsType(base::Value::TYPE_DICTIONARY)) {
base::DictionaryValue* dict =
static_cast<base::DictionaryValue*>(options.get());
dict->GetString("mimeType", &mime_type_);
dict->GetString("charset", &charset_);
dict->GetString("data", &data_);
} else if (options->IsType(base::Value::TYPE_STRING)) {
options->GetAsString(&data_);
}
net::URLRequestSimpleJob::Start();
}