1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/renderer/web_ui_extension.h" 6 7 #include "base/memory/scoped_ptr.h" 8 #include "base/values.h" 9 #include "content/common/view_messages.h" 10 #include "content/public/common/bindings_policy.h" 11 #include "content/public/common/url_constants.h" 12 #include "content/public/renderer/render_thread.h" 13 #include "content/public/renderer/render_view.h" 14 #include "content/public/renderer/v8_value_converter.h" 15 #include "content/renderer/web_ui_extension_data.h" 16 #include "third_party/WebKit/public/web/WebDocument.h" 17 #include "third_party/WebKit/public/web/WebFrame.h" 18 #include "third_party/WebKit/public/web/WebView.h" 19 #include "url/gurl.h" 20 #include "v8/include/v8.h" 21 22 namespace content { 23 24 static const char* const kWebUIExtensionName = "v8/WebUI"; 25 26 // Javascript that gets executed when the extension loads into all frames. 27 // Exposes two methods: 28 // - chrome.send: Used to send messages to the browser. Requires the message 29 // name as the first argument and can have an optional second argument that 30 // should be an array. 31 // - chrome.getVariableValue: Returns value for the input variable name if such 32 // a value was set by the browser. Else will return an empty string. 33 static const char* const kWebUIExtensionJS = 34 "var chrome;" 35 "if (!chrome)" 36 " chrome = {};" 37 "chrome.send = function(name, data) {" 38 " native function Send();" 39 " Send(name, data);" 40 "};" 41 "chrome.getVariableValue = function(name) {" 42 " native function GetVariableValue();" 43 " return GetVariableValue(name);" 44 "};"; 45 46 class WebUIExtensionWrapper : public v8::Extension { 47 public: 48 WebUIExtensionWrapper(); 49 virtual ~WebUIExtensionWrapper(); 50 51 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( 52 v8::Isolate* isolate, 53 v8::Handle<v8::String> name) OVERRIDE; 54 static void Send(const v8::FunctionCallbackInfo<v8::Value>& args); 55 static void GetVariableValue(const v8::FunctionCallbackInfo<v8::Value>& args); 56 57 private: 58 static bool ShouldRespondToRequest(blink::WebFrame** frame_ptr, 59 RenderView** render_view_ptr); 60 61 DISALLOW_COPY_AND_ASSIGN(WebUIExtensionWrapper); 62 }; 63 64 WebUIExtensionWrapper::WebUIExtensionWrapper() 65 : v8::Extension(kWebUIExtensionName, kWebUIExtensionJS) {} 66 67 WebUIExtensionWrapper::~WebUIExtensionWrapper() {} 68 69 v8::Handle<v8::FunctionTemplate> 70 WebUIExtensionWrapper::GetNativeFunctionTemplate(v8::Isolate* isolate, 71 v8::Handle<v8::String> name) { 72 if (name->Equals(v8::String::NewFromUtf8(isolate, "Send"))) 73 return v8::FunctionTemplate::New(isolate, Send); 74 if (name->Equals(v8::String::NewFromUtf8(isolate, "GetVariableValue"))) 75 return v8::FunctionTemplate::New(isolate, GetVariableValue); 76 return v8::Handle<v8::FunctionTemplate>(); 77 } 78 79 // static 80 bool WebUIExtensionWrapper::ShouldRespondToRequest( 81 blink::WebFrame** frame_ptr, 82 RenderView** render_view_ptr) { 83 blink::WebFrame* frame = blink::WebFrame::frameForCurrentContext(); 84 if (!frame || !frame->view()) 85 return false; 86 87 RenderView* render_view = RenderView::FromWebView(frame->view()); 88 if (!render_view) 89 return false; 90 91 GURL frame_url = frame->document().url(); 92 93 bool webui_enabled = 94 (render_view->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI) && 95 (frame_url.SchemeIs(chrome::kChromeUIScheme) || 96 frame_url.SchemeIs(chrome::kDataScheme)); 97 98 if (!webui_enabled) 99 return false; 100 101 *frame_ptr = frame; 102 *render_view_ptr = render_view; 103 return true; 104 } 105 106 // static 107 void WebUIExtensionWrapper::Send( 108 const v8::FunctionCallbackInfo<v8::Value>& args) { 109 blink::WebFrame* frame; 110 RenderView* render_view; 111 if (!ShouldRespondToRequest(&frame, &render_view)) 112 return; 113 114 // We expect at least two parameters - a string message identifier, and 115 // an object parameter. The object param can be undefined. 116 if (args.Length() != 2 || !args[0]->IsString()) 117 return; 118 119 const std::string message = *v8::String::Utf8Value(args[0]->ToString()); 120 121 // If they've provided an optional message parameter, convert that into a 122 // Value to send to the browser process. 123 scoped_ptr<ListValue> content; 124 if (args[1]->IsUndefined()) { 125 content.reset(new ListValue()); 126 } else { 127 if (!args[1]->IsObject()) 128 return; 129 130 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); 131 132 base::Value* value = converter->FromV8Value( 133 args[1], frame->mainWorldScriptContext()); 134 base::ListValue* list = NULL; 135 value->GetAsList(&list); 136 DCHECK(list); 137 content.reset(list); 138 } 139 140 // Send the message up to the browser. 141 render_view->Send(new ViewHostMsg_WebUISend(render_view->GetRoutingID(), 142 frame->document().url(), 143 message, 144 *content)); 145 } 146 147 // static 148 void WebUIExtensionWrapper::GetVariableValue( 149 const v8::FunctionCallbackInfo<v8::Value>& args) { 150 blink::WebFrame* frame; 151 RenderView* render_view; 152 if (!ShouldRespondToRequest(&frame, &render_view)) 153 return; 154 155 if (!args.Length() || !args[0]->IsString()) 156 return; 157 158 std::string key = *v8::String::Utf8Value(args[0]->ToString()); 159 std::string value = WebUIExtensionData::Get(render_view)->GetValue(key); 160 args.GetReturnValue().Set(v8::String::NewFromUtf8(args.GetIsolate(), 161 value.c_str(), 162 v8::String::kNormalString, 163 value.length())); 164 } 165 166 // static 167 v8::Extension* WebUIExtension::Get() { 168 return new WebUIExtensionWrapper(); 169 } 170 171 } // namespace content 172