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> GetNativeFunction( 52 v8::Handle<v8::String> name) OVERRIDE; 53 static void Send(const v8::FunctionCallbackInfo<v8::Value>& args); 54 static void GetVariableValue(const v8::FunctionCallbackInfo<v8::Value>& args); 55 56 private: 57 static bool ShouldRespondToRequest(WebKit::WebFrame** frame_ptr, 58 RenderView** render_view_ptr); 59 60 DISALLOW_COPY_AND_ASSIGN(WebUIExtensionWrapper); 61 }; 62 63 WebUIExtensionWrapper::WebUIExtensionWrapper() 64 : v8::Extension(kWebUIExtensionName, kWebUIExtensionJS) {} 65 66 WebUIExtensionWrapper::~WebUIExtensionWrapper() {} 67 68 v8::Handle<v8::FunctionTemplate> WebUIExtensionWrapper::GetNativeFunction( 69 v8::Handle<v8::String> name) { 70 if (name->Equals(v8::String::New("Send"))) 71 return v8::FunctionTemplate::New(Send); 72 if (name->Equals(v8::String::New("GetVariableValue"))) 73 return v8::FunctionTemplate::New(GetVariableValue); 74 return v8::Handle<v8::FunctionTemplate>(); 75 } 76 77 // static 78 bool WebUIExtensionWrapper::ShouldRespondToRequest( 79 WebKit::WebFrame** frame_ptr, 80 RenderView** render_view_ptr) { 81 WebKit::WebFrame* frame = WebKit::WebFrame::frameForCurrentContext(); 82 if (!frame || !frame->view()) 83 return false; 84 85 RenderView* render_view = RenderView::FromWebView(frame->view()); 86 if (!render_view) 87 return false; 88 89 GURL frame_url = frame->document().url(); 90 91 bool webui_enabled = 92 (render_view->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI) && 93 (frame_url.SchemeIs(chrome::kChromeUIScheme) || 94 frame_url.SchemeIs(chrome::kDataScheme)); 95 96 if (!webui_enabled) 97 return false; 98 99 *frame_ptr = frame; 100 *render_view_ptr = render_view; 101 return true; 102 } 103 104 // static 105 void WebUIExtensionWrapper::Send( 106 const v8::FunctionCallbackInfo<v8::Value>& args) { 107 WebKit::WebFrame* frame; 108 RenderView* render_view; 109 if (!ShouldRespondToRequest(&frame, &render_view)) 110 return; 111 112 // We expect at least two parameters - a string message identifier, and 113 // an object parameter. The object param can be undefined. 114 if (args.Length() != 2 || !args[0]->IsString()) 115 return; 116 117 const std::string message = *v8::String::Utf8Value(args[0]->ToString()); 118 119 // If they've provided an optional message parameter, convert that into a 120 // Value to send to the browser process. 121 scoped_ptr<ListValue> content; 122 if (args[1]->IsUndefined()) { 123 content.reset(new ListValue()); 124 } else { 125 if (!args[1]->IsObject()) 126 return; 127 128 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); 129 130 base::Value* value = converter->FromV8Value( 131 args[1], frame->mainWorldScriptContext()); 132 base::ListValue* list = NULL; 133 value->GetAsList(&list); 134 DCHECK(list); 135 content.reset(list); 136 } 137 138 // Send the message up to the browser. 139 render_view->Send(new ViewHostMsg_WebUISend(render_view->GetRoutingID(), 140 frame->document().url(), 141 message, 142 *content)); 143 } 144 145 // static 146 void WebUIExtensionWrapper::GetVariableValue( 147 const v8::FunctionCallbackInfo<v8::Value>& args) { 148 WebKit::WebFrame* frame; 149 RenderView* render_view; 150 if (!ShouldRespondToRequest(&frame, &render_view)) 151 return; 152 153 if (!args.Length() || !args[0]->IsString()) 154 return; 155 156 std::string key = *v8::String::Utf8Value(args[0]->ToString()); 157 std::string value = WebUIExtensionData::Get(render_view)->GetValue(key); 158 args.GetReturnValue().Set(v8::String::New(value.c_str(), value.length())); 159 } 160 161 // static 162 v8::Extension* WebUIExtension::Get() { 163 return new WebUIExtensionWrapper(); 164 } 165 166 } // namespace content 167