Home | History | Annotate | Download | only in renderer
      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