// 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 "base/memory/scoped_ptr.h" #include "base/values.h" #include "content/common/view_messages.h" #include "content/public/common/bindings_policy.h" #include "content/public/common/url_constants.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/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebView.h" #include "url/gurl.h" #include "v8/include/v8.h" namespace content { namespace { bool ShouldRespondToRequest( blink::WebFrame** frame_ptr, RenderView** render_view_ptr) { blink::WebFrame* frame = blink::WebLocalFrame::frameForCurrentContext(); if (!frame || !frame->view()) return false; RenderView* render_view = RenderView::FromWebView(frame->view()); if (!render_view) return false; GURL frame_url = frame->document().url(); bool webui_enabled = (render_view->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI) && (frame_url.SchemeIs(kChromeUIScheme) || frame_url.SchemeIs(url::kDataScheme)); if (!webui_enabled) return false; *frame_ptr = frame; *render_view_ptr = render_view; 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::WebFrame* frame) { v8::Isolate* isolate = blink::mainThreadIsolate(); v8::HandleScope handle_scope(isolate); v8::Handle<v8::Context> context = frame->mainWorldScriptContext(); if (context.IsEmpty()) return; v8::Context::Scope context_scope(context); v8::Handle<v8::Object> global = context->Global(); v8::Handle<v8::Object> chrome = global->Get(gin::StringToV8(isolate, "chrome"))->ToObject(); if (chrome.IsEmpty()) { chrome = v8::Object::New(isolate); global->Set(gin::StringToSymbol(isolate, "chrome"), chrome); } chrome->Set(gin::StringToSymbol(isolate, "send"), gin::CreateFunctionTemplate( isolate, base::Bind(&WebUIExtension::Send))->GetFunction()); chrome->Set(gin::StringToSymbol(isolate, "getVariableValue"), gin::CreateFunctionTemplate( isolate, base::Bind(&WebUIExtension::GetVariableValue)) ->GetFunction()); } // static void WebUIExtension::Send(gin::Arguments* args) { blink::WebFrame* frame; RenderView* render_view; if (!ShouldRespondToRequest(&frame, &render_view)) 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. scoped_ptr<base::ListValue> content; if (args->PeekNext().IsEmpty() || args->PeekNext()->IsUndefined()) { content.reset(new base::ListValue()); } else { v8::Handle<v8::Object> obj; if (!args->GetNext(&obj)) { args->ThrowError(); return; } scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); base::Value* value = converter->FromV8Value(obj, frame->mainWorldScriptContext()); base::ListValue* list = NULL; value->GetAsList(&list); DCHECK(list); content.reset(list); } // Send the message up to the browser. render_view->Send(new ViewHostMsg_WebUISend(render_view->GetRoutingID(), frame->document().url(), message, *content)); } // static std::string WebUIExtension::GetVariableValue(const std::string& name) { blink::WebFrame* frame; RenderView* render_view; if (!ShouldRespondToRequest(&frame, &render_view)) return std::string(); return WebUIExtensionData::Get(render_view)->GetValue(name); } } // namespace content