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 "gin/arguments.h"
     17 #include "gin/function_template.h"
     18 #include "third_party/WebKit/public/web/WebDocument.h"
     19 #include "third_party/WebKit/public/web/WebKit.h"
     20 #include "third_party/WebKit/public/web/WebLocalFrame.h"
     21 #include "third_party/WebKit/public/web/WebView.h"
     22 #include "url/gurl.h"
     23 #include "v8/include/v8.h"
     24 
     25 namespace content {
     26 
     27 namespace {
     28 
     29 bool ShouldRespondToRequest(
     30     blink::WebFrame** frame_ptr,
     31     RenderView** render_view_ptr) {
     32   blink::WebFrame* frame = blink::WebLocalFrame::frameForCurrentContext();
     33   if (!frame || !frame->view())
     34     return false;
     35 
     36   RenderView* render_view = RenderView::FromWebView(frame->view());
     37   if (!render_view)
     38     return false;
     39 
     40   GURL frame_url = frame->document().url();
     41 
     42   bool webui_enabled =
     43       (render_view->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI) &&
     44       (frame_url.SchemeIs(kChromeUIScheme) ||
     45        frame_url.SchemeIs(url::kDataScheme));
     46 
     47   if (!webui_enabled)
     48     return false;
     49 
     50   *frame_ptr = frame;
     51   *render_view_ptr = render_view;
     52   return true;
     53 }
     54 
     55 }  // namespace
     56 
     57 // Exposes two methods:
     58 //  - chrome.send: Used to send messages to the browser. Requires the message
     59 //      name as the first argument and can have an optional second argument that
     60 //      should be an array.
     61 //  - chrome.getVariableValue: Returns value for the input variable name if such
     62 //      a value was set by the browser. Else will return an empty string.
     63 void WebUIExtension::Install(blink::WebFrame* frame) {
     64   v8::Isolate* isolate = blink::mainThreadIsolate();
     65   v8::HandleScope handle_scope(isolate);
     66   v8::Handle<v8::Context> context = frame->mainWorldScriptContext();
     67   if (context.IsEmpty())
     68     return;
     69 
     70   v8::Context::Scope context_scope(context);
     71 
     72   v8::Handle<v8::Object> global = context->Global();
     73   v8::Handle<v8::Object> chrome =
     74       global->Get(gin::StringToV8(isolate, "chrome"))->ToObject();
     75   if (chrome.IsEmpty()) {
     76     chrome = v8::Object::New(isolate);
     77     global->Set(gin::StringToSymbol(isolate, "chrome"), chrome);
     78   }
     79   chrome->Set(gin::StringToSymbol(isolate, "send"),
     80               gin::CreateFunctionTemplate(
     81                   isolate, base::Bind(&WebUIExtension::Send))->GetFunction());
     82   chrome->Set(gin::StringToSymbol(isolate, "getVariableValue"),
     83               gin::CreateFunctionTemplate(
     84                   isolate, base::Bind(&WebUIExtension::GetVariableValue))
     85                   ->GetFunction());
     86 }
     87 
     88 // static
     89 void WebUIExtension::Send(gin::Arguments* args) {
     90   blink::WebFrame* frame;
     91   RenderView* render_view;
     92   if (!ShouldRespondToRequest(&frame, &render_view))
     93     return;
     94 
     95   std::string message;
     96   if (!args->GetNext(&message)) {
     97     args->ThrowError();
     98     return;
     99   }
    100 
    101   // If they've provided an optional message parameter, convert that into a
    102   // Value to send to the browser process.
    103   scoped_ptr<base::ListValue> content;
    104   if (args->PeekNext().IsEmpty() || args->PeekNext()->IsUndefined()) {
    105     content.reset(new base::ListValue());
    106   } else {
    107     v8::Handle<v8::Object> obj;
    108     if (!args->GetNext(&obj)) {
    109       args->ThrowError();
    110       return;
    111     }
    112 
    113     scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
    114 
    115     base::Value* value =
    116         converter->FromV8Value(obj, frame->mainWorldScriptContext());
    117     base::ListValue* list = NULL;
    118     value->GetAsList(&list);
    119     DCHECK(list);
    120     content.reset(list);
    121   }
    122 
    123   // Send the message up to the browser.
    124   render_view->Send(new ViewHostMsg_WebUISend(render_view->GetRoutingID(),
    125                                               frame->document().url(),
    126                                               message,
    127                                               *content));
    128 }
    129 
    130 // static
    131 std::string WebUIExtension::GetVariableValue(const std::string& name) {
    132   blink::WebFrame* frame;
    133   RenderView* render_view;
    134   if (!ShouldRespondToRequest(&frame, &render_view))
    135     return std::string();
    136 
    137   return WebUIExtensionData::Get(render_view)->GetValue(name);
    138 }
    139 
    140 }  // namespace content
    141