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> 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