1// Copyright 2014 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 "extensions/renderer/runtime_custom_bindings.h" 6 7#include "base/bind.h" 8#include "base/memory/scoped_ptr.h" 9#include "base/values.h" 10#include "content/public/renderer/render_view.h" 11#include "content/public/renderer/v8_value_converter.h" 12#include "extensions/common/extension.h" 13#include "extensions/common/extension_messages.h" 14#include "extensions/common/features/feature.h" 15#include "extensions/common/features/feature_provider.h" 16#include "extensions/common/manifest.h" 17#include "extensions/renderer/api_activity_logger.h" 18#include "extensions/renderer/extension_helper.h" 19#include "extensions/renderer/script_context.h" 20#include "third_party/WebKit/public/web/WebDocument.h" 21#include "third_party/WebKit/public/web/WebFrame.h" 22#include "third_party/WebKit/public/web/WebView.h" 23 24using content::V8ValueConverter; 25 26namespace extensions { 27 28RuntimeCustomBindings::RuntimeCustomBindings(ScriptContext* context) 29 : ObjectBackedNativeHandler(context) { 30 RouteFunction( 31 "GetManifest", 32 base::Bind(&RuntimeCustomBindings::GetManifest, base::Unretained(this))); 33 RouteFunction("OpenChannelToExtension", 34 base::Bind(&RuntimeCustomBindings::OpenChannelToExtension, 35 base::Unretained(this))); 36 RouteFunction("OpenChannelToNativeApp", 37 base::Bind(&RuntimeCustomBindings::OpenChannelToNativeApp, 38 base::Unretained(this))); 39 RouteFunction("GetExtensionViews", 40 base::Bind(&RuntimeCustomBindings::GetExtensionViews, 41 base::Unretained(this))); 42} 43 44RuntimeCustomBindings::~RuntimeCustomBindings() { 45} 46 47void RuntimeCustomBindings::OpenChannelToExtension( 48 const v8::FunctionCallbackInfo<v8::Value>& args) { 49 // Get the current RenderView so that we can send a routed IPC message from 50 // the correct source. 51 content::RenderView* renderview = context()->GetRenderView(); 52 if (!renderview) 53 return; 54 55 // The Javascript code should validate/fill the arguments. 56 CHECK_EQ(args.Length(), 3); 57 CHECK(args[0]->IsString() && args[1]->IsString() && args[2]->IsBoolean()); 58 59 ExtensionMsg_ExternalConnectionInfo info; 60 61 // For messaging APIs, hosted apps should be considered a web page so hide 62 // its extension ID. 63 const Extension* extension = context()->extension(); 64 if (extension && !extension->is_hosted_app()) 65 info.source_id = extension->id(); 66 67 info.target_id = *v8::String::Utf8Value(args[0]->ToString()); 68 info.source_url = context()->GetURL(); 69 std::string channel_name = *v8::String::Utf8Value(args[1]->ToString()); 70 bool include_tls_channel_id = 71 args.Length() > 2 ? args[2]->BooleanValue() : false; 72 int port_id = -1; 73 renderview->Send( 74 new ExtensionHostMsg_OpenChannelToExtension(renderview->GetRoutingID(), 75 info, 76 channel_name, 77 include_tls_channel_id, 78 &port_id)); 79 args.GetReturnValue().Set(static_cast<int32_t>(port_id)); 80} 81 82void RuntimeCustomBindings::OpenChannelToNativeApp( 83 const v8::FunctionCallbackInfo<v8::Value>& args) { 84 // Verify that the extension has permission to use native messaging. 85 Feature::Availability availability = 86 FeatureProvider::GetPermissionFeatures() 87 ->GetFeature("nativeMessaging") 88 ->IsAvailableToContext(context()->extension(), 89 context()->context_type(), 90 context()->GetURL()); 91 if (!availability.is_available()) 92 return; 93 94 // Get the current RenderView so that we can send a routed IPC message from 95 // the correct source. 96 content::RenderView* renderview = context()->GetRenderView(); 97 if (!renderview) 98 return; 99 100 // The Javascript code should validate/fill the arguments. 101 CHECK(args.Length() >= 2 && args[0]->IsString() && args[1]->IsString()); 102 103 std::string extension_id = *v8::String::Utf8Value(args[0]->ToString()); 104 std::string native_app_name = *v8::String::Utf8Value(args[1]->ToString()); 105 106 int port_id = -1; 107 renderview->Send(new ExtensionHostMsg_OpenChannelToNativeApp( 108 renderview->GetRoutingID(), extension_id, native_app_name, &port_id)); 109 args.GetReturnValue().Set(static_cast<int32_t>(port_id)); 110} 111 112void RuntimeCustomBindings::GetManifest( 113 const v8::FunctionCallbackInfo<v8::Value>& args) { 114 CHECK(context()->extension()); 115 116 scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create()); 117 args.GetReturnValue().Set(converter->ToV8Value( 118 context()->extension()->manifest()->value(), context()->v8_context())); 119} 120 121void RuntimeCustomBindings::GetExtensionViews( 122 const v8::FunctionCallbackInfo<v8::Value>& args) { 123 if (args.Length() != 2) 124 return; 125 126 if (!args[0]->IsInt32() || !args[1]->IsString()) 127 return; 128 129 // |browser_window_id| == extension_misc::kUnknownWindowId means getting 130 // all views for the current extension. 131 int browser_window_id = args[0]->Int32Value(); 132 133 std::string view_type_string = *v8::String::Utf8Value(args[1]->ToString()); 134 StringToUpperASCII(&view_type_string); 135 // |view_type| == VIEW_TYPE_INVALID means getting any type of 136 // views. 137 ViewType view_type = VIEW_TYPE_INVALID; 138 if (view_type_string == kViewTypeBackgroundPage) { 139 view_type = VIEW_TYPE_EXTENSION_BACKGROUND_PAGE; 140 } else if (view_type_string == kViewTypeInfobar) { 141 view_type = VIEW_TYPE_EXTENSION_INFOBAR; 142 } else if (view_type_string == kViewTypeTabContents) { 143 view_type = VIEW_TYPE_TAB_CONTENTS; 144 } else if (view_type_string == kViewTypePopup) { 145 view_type = VIEW_TYPE_EXTENSION_POPUP; 146 } else if (view_type_string == kViewTypeExtensionDialog) { 147 view_type = VIEW_TYPE_EXTENSION_DIALOG; 148 } else if (view_type_string == kViewTypeAppWindow) { 149 view_type = VIEW_TYPE_APP_WINDOW; 150 } else if (view_type_string == kViewTypePanel) { 151 view_type = VIEW_TYPE_PANEL; 152 } else if (view_type_string != kViewTypeAll) { 153 return; 154 } 155 156 std::string extension_id = context()->GetExtensionID(); 157 if (extension_id.empty()) 158 return; 159 160 std::vector<content::RenderView*> views = ExtensionHelper::GetExtensionViews( 161 extension_id, browser_window_id, view_type); 162 v8::Local<v8::Array> v8_views = v8::Array::New(args.GetIsolate()); 163 int v8_index = 0; 164 for (size_t i = 0; i < views.size(); ++i) { 165 v8::Local<v8::Context> context = 166 views[i]->GetWebView()->mainFrame()->mainWorldScriptContext(); 167 if (!context.IsEmpty()) { 168 v8::Local<v8::Value> window = context->Global(); 169 DCHECK(!window.IsEmpty()); 170 v8_views->Set(v8::Integer::New(args.GetIsolate(), v8_index++), window); 171 } 172 } 173 174 args.GetReturnValue().Set(v8_views); 175} 176 177} // namespace extensions 178