1 // Copyright (c) 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 "chrome/renderer/external_extension.h" 6 7 #include "chrome/common/render_messages.h" 8 #include "chrome/common/search_provider.h" 9 #include "content/public/renderer/render_view.h" 10 #include "third_party/WebKit/public/web/WebDocument.h" 11 #include "third_party/WebKit/public/web/WebLocalFrame.h" 12 #include "third_party/WebKit/public/web/WebView.h" 13 #include "v8/include/v8.h" 14 15 using blink::WebLocalFrame; 16 using blink::WebView; 17 using content::RenderView; 18 19 namespace extensions_v8 { 20 21 namespace { 22 23 const char* const kSearchProviderApi = 24 "var external;" 25 "if (!external)" 26 " external = {};" 27 "external.AddSearchProvider = function(name) {" 28 " native function NativeAddSearchProvider();" 29 " NativeAddSearchProvider(name);" 30 "};" 31 "external.IsSearchProviderInstalled = function(name) {" 32 " native function NativeIsSearchProviderInstalled();" 33 " return NativeIsSearchProviderInstalled(name);" 34 "};"; 35 36 const char kExternalExtensionName[] = "v8/External"; 37 38 } // namespace 39 40 class ExternalExtensionWrapper : public v8::Extension { 41 public: 42 ExternalExtensionWrapper(); 43 44 // Allows v8's javascript code to call the native functions defined 45 // in this class for window.external. 46 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate( 47 v8::Isolate* isolate, 48 v8::Handle<v8::String> name) OVERRIDE; 49 50 // Helper function to find the RenderView. May return NULL. 51 static RenderView* GetRenderView(); 52 53 // Implementation of window.external.AddSearchProvider. 54 static void AddSearchProvider( 55 const v8::FunctionCallbackInfo<v8::Value>& args); 56 57 // Implementation of window.external.IsSearchProviderInstalled. 58 static void IsSearchProviderInstalled( 59 const v8::FunctionCallbackInfo<v8::Value>& args); 60 61 private: 62 DISALLOW_COPY_AND_ASSIGN(ExternalExtensionWrapper); 63 }; 64 65 ExternalExtensionWrapper::ExternalExtensionWrapper() 66 : v8::Extension(kExternalExtensionName, kSearchProviderApi) { 67 } 68 69 v8::Handle<v8::FunctionTemplate> 70 ExternalExtensionWrapper::GetNativeFunctionTemplate( 71 v8::Isolate* isolate, 72 v8::Handle<v8::String> name) { 73 if (name->Equals(v8::String::NewFromUtf8(isolate, "NativeAddSearchProvider"))) 74 return v8::FunctionTemplate::New(isolate, AddSearchProvider); 75 76 if (name->Equals(v8::String::NewFromUtf8( 77 isolate, "NativeIsSearchProviderInstalled"))) { 78 return v8::FunctionTemplate::New(isolate, IsSearchProviderInstalled); 79 } 80 81 return v8::Handle<v8::FunctionTemplate>(); 82 } 83 84 // static 85 RenderView* ExternalExtensionWrapper::GetRenderView() { 86 WebLocalFrame* webframe = WebLocalFrame::frameForCurrentContext(); 87 DCHECK(webframe) << "There should be an active frame since we just got " 88 "a native function called."; 89 if (!webframe) 90 return NULL; 91 92 WebView* webview = webframe->view(); 93 if (!webview) 94 return NULL; // can happen during closing 95 96 return RenderView::FromWebView(webview); 97 } 98 99 // static 100 void ExternalExtensionWrapper::AddSearchProvider( 101 const v8::FunctionCallbackInfo<v8::Value>& args) { 102 if (!args.Length() || !args[0]->IsString()) 103 return; 104 105 std::string osdd_string(*v8::String::Utf8Value(args[0])); 106 if (osdd_string.empty()) 107 return; 108 109 RenderView* render_view = GetRenderView(); 110 if (!render_view) 111 return; 112 113 WebLocalFrame* webframe = WebLocalFrame::frameForCurrentContext(); 114 if (!webframe) 115 return; 116 117 GURL osdd_url(osdd_string); 118 if (!osdd_url.is_empty() && osdd_url.is_valid()) { 119 render_view->Send(new ChromeViewHostMsg_PageHasOSDD( 120 render_view->GetRoutingID(), webframe->document().url(), osdd_url, 121 search_provider::EXPLICIT_PROVIDER)); 122 } 123 } 124 125 // static 126 void ExternalExtensionWrapper::IsSearchProviderInstalled( 127 const v8::FunctionCallbackInfo<v8::Value>& args) { 128 if (!args.Length() || !args[0]->IsString()) 129 return; 130 131 v8::String::Utf8Value utf8name(args[0]); 132 if (!utf8name.length()) 133 return; 134 135 std::string name(*utf8name); 136 RenderView* render_view = GetRenderView(); 137 if (!render_view) 138 return; 139 140 WebLocalFrame* webframe = WebLocalFrame::frameForCurrentContext(); 141 if (!webframe) 142 return; 143 144 search_provider::InstallState install = search_provider::DENIED; 145 GURL inquiry_url = GURL(name); 146 if (!inquiry_url.is_empty()) { 147 render_view->Send(new ChromeViewHostMsg_GetSearchProviderInstallState( 148 render_view->GetRoutingID(), 149 webframe->document().url(), 150 inquiry_url, 151 &install)); 152 } 153 154 if (install == search_provider::DENIED) { 155 // FIXME: throw access denied exception. 156 v8::Isolate* isolate = args.GetIsolate(); 157 isolate->ThrowException(v8::Exception::Error(v8::String::Empty(isolate))); 158 return; 159 } 160 args.GetReturnValue().Set(static_cast<int32_t>(install)); 161 } 162 163 v8::Extension* ExternalExtension::Get() { 164 return new ExternalExtensionWrapper(); 165 } 166 167 } // namespace extensions_v8 168