blob: 5af8770399e214785e6038469e5b0d86c3f930e5 [file] [log] [blame]
// Copyright 2012 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 "content/renderer/web_ui_extension.h"
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/values.h"
#include "content/common/frame_messages.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/url_constants.h"
#include "content/public/renderer/chrome_object_extensions_utils.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/v8_value_converter.h"
#include "content/renderer/web_ui_extension_data.h"
#include "gin/arguments.h"
#include "gin/function_template.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_view.h"
#include "url/gurl.h"
#include "v8/include/v8.h"
namespace content {
namespace {
bool ShouldRespondToRequest(blink::WebLocalFrame** frame_ptr,
RenderFrame** render_frame_ptr) {
blink::WebLocalFrame* frame = blink::WebLocalFrame::FrameForCurrentContext();
if (!frame || !frame->View())
return false;
GURL frame_url = frame->GetDocument().Url();
RenderFrame* render_frame = RenderFrame::FromWebFrame(frame);
if (!render_frame)
return false;
bool webui_enabled =
(render_frame->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI) &&
(frame_url.SchemeIs(kChromeUIScheme) ||
frame_url.SchemeIs(url::kDataScheme));
if (!webui_enabled)
return false;
*frame_ptr = frame;
*render_frame_ptr = render_frame;
return true;
}
} // namespace
// Exposes two methods:
// - chrome.send: Used to send messages to the browser. Requires the message
// name as the first argument and can have an optional second argument that
// should be an array.
// - chrome.getVariableValue: Returns value for the input variable name if such
// a value was set by the browser. Else will return an empty string.
void WebUIExtension::Install(blink::WebLocalFrame* frame) {
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = frame->MainWorldScriptContext();
if (context.IsEmpty())
return;
v8::Context::Scope context_scope(context);
v8::Local<v8::Object> chrome = GetOrCreateChromeObject(isolate, context);
chrome
->Set(context, gin::StringToSymbol(isolate, "send"),
gin::CreateFunctionTemplate(isolate,
base::Bind(&WebUIExtension::Send))
->GetFunction(context)
.ToLocalChecked())
.Check();
chrome
->Set(context, gin::StringToSymbol(isolate, "getVariableValue"),
gin::CreateFunctionTemplate(
isolate, base::Bind(&WebUIExtension::GetVariableValue))
->GetFunction(context)
.ToLocalChecked())
.Check();
}
// static
void WebUIExtension::Send(gin::Arguments* args) {
blink::WebLocalFrame* frame;
RenderFrame* render_frame;
if (!ShouldRespondToRequest(&frame, &render_frame))
return;
std::string message;
if (!args->GetNext(&message)) {
args->ThrowError();
return;
}
// If they've provided an optional message parameter, convert that into a
// Value to send to the browser process.
std::unique_ptr<base::ListValue> content;
if (args->PeekNext().IsEmpty() || args->PeekNext()->IsUndefined()) {
content.reset(new base::ListValue());
} else {
v8::Local<v8::Object> obj;
if (!args->GetNext(&obj)) {
args->ThrowError();
return;
}
content = base::ListValue::From(V8ValueConverter::Create()->FromV8Value(
obj, frame->MainWorldScriptContext()));
DCHECK(content);
// The conversion of |obj| could have triggered arbitrary JavaScript code,
// so check that the frame is still valid to avoid dereferencing a stale
// pointer.
if (frame != blink::WebLocalFrame::FrameForCurrentContext()) {
NOTREACHED();
return;
}
}
// Send the message up to the browser.
render_frame->Send(new FrameHostMsg_WebUISend(render_frame->GetRoutingID(),
message, *content));
}
// static
std::string WebUIExtension::GetVariableValue(const std::string& name) {
blink::WebLocalFrame* frame;
RenderFrame* render_frame;
if (!ShouldRespondToRequest(&frame, &render_frame))
return std::string();
return WebUIExtensionData::Get(render_frame->GetRenderView())->GetValue(name);
}
} // namespace content