blob: 58f7b73bc26f81ebadad30eac963200dfbcd6414 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/extensions/app_hooks_delegate.h"
#include "extensions/renderer/api_activity_logger.h"
#include "extensions/renderer/bindings/api_request_handler.h"
#include "extensions/renderer/bindings/api_signature.h"
#include "extensions/renderer/script_context_set.h"
#include "gin/converter.h"
namespace extensions {
namespace {
void IsInstalledGetterCallback(
v8::Local<v8::String> property,
const v8::PropertyCallbackInfo<v8::Value>& info) {
v8::HandleScope handle_scope(info.GetIsolate());
v8::Local<v8::Context> context = info.Holder()->CreationContext();
ScriptContext* script_context =
ScriptContextSet::GetContextByV8Context(context);
// The ScriptContext may have been invalidated if e.g. the frame was removed.
// Return undefined in this case.
if (!script_context)
return;
auto* core =
static_cast<AppBindingsCore*>(info.Data().As<v8::External>()->Value());
// Since this is more-or-less an API, log it as an API call.
APIActivityLogger::LogAPICall(context, "app.getIsInstalled",
std::vector<v8::Local<v8::Value>>());
info.GetReturnValue().Set(core->GetIsInstalled(script_context));
}
} // namespace
AppHooksDelegate::AppHooksDelegate(Dispatcher* dispatcher,
APIRequestHandler* request_handler)
: app_core_(dispatcher), request_handler_(request_handler) {}
AppHooksDelegate::~AppHooksDelegate() {}
APIBindingHooks::RequestResult AppHooksDelegate::HandleRequest(
const std::string& method_name,
const APISignature* signature,
v8::Local<v8::Context> context,
std::vector<v8::Local<v8::Value>>* arguments,
const APITypeReferenceMap& refs) {
using RequestResult = APIBindingHooks::RequestResult;
v8::Isolate* isolate = context->GetIsolate();
std::vector<v8::Local<v8::Value>> arguments_out;
std::string error;
v8::TryCatch try_catch(isolate);
if (!signature->ParseArgumentsToV8(context, *arguments, refs, &arguments_out,
&error)) {
if (try_catch.HasCaught()) {
try_catch.ReThrow();
return RequestResult(RequestResult::THROWN);
}
return RequestResult(RequestResult::INVALID_INVOCATION);
}
ScriptContext* script_context =
ScriptContextSet::GetContextByV8Context(context);
DCHECK(script_context);
APIBindingHooks::RequestResult result(
APIBindingHooks::RequestResult::HANDLED);
if (method_name == "app.getIsInstalled") {
result.return_value =
v8::Boolean::New(isolate, app_core_.GetIsInstalled(script_context));
} else if (method_name == "app.getDetails") {
result.return_value = app_core_.GetDetails(script_context);
} else if (method_name == "app.runningState") {
result.return_value =
gin::StringToSymbol(isolate, app_core_.GetRunningState(script_context));
} else if (method_name == "app.installState") {
DCHECK_EQ(1u, arguments_out.size());
DCHECK(arguments_out[0]->IsFunction());
int request_id = request_handler_->AddPendingRequest(
context, arguments_out[0].As<v8::Function>());
app_core_.GetInstallState(
script_context, base::BindOnce(&AppHooksDelegate::OnGotInstallState,
base::Unretained(this), request_id));
} else {
NOTREACHED();
}
return result;
}
void AppHooksDelegate::InitializeTemplate(
v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> object_template,
const APITypeReferenceMap& type_refs) {
// We expose a boolean isInstalled on the chrome.app API object, as well as
// the getIsInstalled() method.
// TODO(devlin): :(. Hopefully we can just remove this whole API, but this is
// particularly silly.
// This object should outlive contexts, so the app_core_ v8::External is safe.
// TODO(devlin): This is getting pretty common. We should find a generalized
// solution, or make gin::ObjectTemplateBuilder work for these use cases.
object_template->SetAccessor(gin::StringToSymbol(isolate, "isInstalled"),
&IsInstalledGetterCallback, nullptr,
v8::External::New(isolate, &app_core_));
}
void AppHooksDelegate::OnGotInstallState(int request_id,
const std::string& install_state) {
// Note: it's kind of lame that we serialize the install state to a
// base::Value here when we're just going to later convert it to v8, but it's
// not worth the specialization on APIRequestHandler for this oddball API.
base::ListValue response;
response.AppendString(install_state);
request_handler_->CompleteRequest(request_id, response, std::string());
}
} // namespace extensions