| // 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 "third_party/WebKit/public/web/WebDocument.h" |
| #include "third_party/WebKit/public/web/WebFrame.h" |
| #include "third_party/WebKit/public/web/WebView.h" |
| #include "url/gurl.h" |
| #include "v8/include/v8.h" |
| |
| namespace content { |
| |
| static const char* const kWebUIExtensionName = "v8/WebUI"; |
| |
| // Javascript that gets executed when the extension loads into all frames. |
| // 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. |
| static const char* const kWebUIExtensionJS = |
| "var chrome;" |
| "if (!chrome)" |
| " chrome = {};" |
| "chrome.send = function(name, data) {" |
| " native function Send();" |
| " Send(name, data);" |
| "};" |
| "chrome.getVariableValue = function(name) {" |
| " native function GetVariableValue();" |
| " return GetVariableValue(name);" |
| "};"; |
| |
| class WebUIExtensionWrapper : public v8::Extension { |
| public: |
| WebUIExtensionWrapper(); |
| virtual ~WebUIExtensionWrapper(); |
| |
| virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( |
| v8::Isolate* isolate, |
| v8::Handle<v8::String> name) OVERRIDE; |
| static void Send(const v8::FunctionCallbackInfo<v8::Value>& args); |
| static void GetVariableValue(const v8::FunctionCallbackInfo<v8::Value>& args); |
| |
| private: |
| static bool ShouldRespondToRequest(blink::WebFrame** frame_ptr, |
| RenderView** render_view_ptr); |
| |
| DISALLOW_COPY_AND_ASSIGN(WebUIExtensionWrapper); |
| }; |
| |
| WebUIExtensionWrapper::WebUIExtensionWrapper() |
| : v8::Extension(kWebUIExtensionName, kWebUIExtensionJS) {} |
| |
| WebUIExtensionWrapper::~WebUIExtensionWrapper() {} |
| |
| v8::Handle<v8::FunctionTemplate> |
| WebUIExtensionWrapper::GetNativeFunctionTemplate(v8::Isolate* isolate, |
| v8::Handle<v8::String> name) { |
| if (name->Equals(v8::String::NewFromUtf8(isolate, "Send"))) |
| return v8::FunctionTemplate::New(isolate, Send); |
| if (name->Equals(v8::String::NewFromUtf8(isolate, "GetVariableValue"))) |
| return v8::FunctionTemplate::New(isolate, GetVariableValue); |
| return v8::Handle<v8::FunctionTemplate>(); |
| } |
| |
| // static |
| bool WebUIExtensionWrapper::ShouldRespondToRequest( |
| blink::WebFrame** frame_ptr, |
| RenderView** render_view_ptr) { |
| blink::WebFrame* frame = blink::WebFrame::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(chrome::kChromeUIScheme) || |
| frame_url.SchemeIs(chrome::kDataScheme)); |
| |
| if (!webui_enabled) |
| return false; |
| |
| *frame_ptr = frame; |
| *render_view_ptr = render_view; |
| return true; |
| } |
| |
| // static |
| void WebUIExtensionWrapper::Send( |
| const v8::FunctionCallbackInfo<v8::Value>& args) { |
| blink::WebFrame* frame; |
| RenderView* render_view; |
| if (!ShouldRespondToRequest(&frame, &render_view)) |
| return; |
| |
| // We expect at least two parameters - a string message identifier, and |
| // an object parameter. The object param can be undefined. |
| if (args.Length() != 2 || !args[0]->IsString()) |
| return; |
| |
| const std::string message = *v8::String::Utf8Value(args[0]->ToString()); |
| |
| // If they've provided an optional message parameter, convert that into a |
| // Value to send to the browser process. |
| scoped_ptr<ListValue> content; |
| if (args[1]->IsUndefined()) { |
| content.reset(new ListValue()); |
| } else { |
| if (!args[1]->IsObject()) |
| return; |
| |
| scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); |
| |
| base::Value* value = converter->FromV8Value( |
| args[1], 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 |
| void WebUIExtensionWrapper::GetVariableValue( |
| const v8::FunctionCallbackInfo<v8::Value>& args) { |
| blink::WebFrame* frame; |
| RenderView* render_view; |
| if (!ShouldRespondToRequest(&frame, &render_view)) |
| return; |
| |
| if (!args.Length() || !args[0]->IsString()) |
| return; |
| |
| std::string key = *v8::String::Utf8Value(args[0]->ToString()); |
| std::string value = WebUIExtensionData::Get(render_view)->GetValue(key); |
| args.GetReturnValue().Set(v8::String::NewFromUtf8(args.GetIsolate(), |
| value.c_str(), |
| v8::String::kNormalString, |
| value.length())); |
| } |
| |
| // static |
| v8::Extension* WebUIExtension::Get() { |
| return new WebUIExtensionWrapper(); |
| } |
| |
| } // namespace content |