OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/extensions/extension_process_bindings.h" | 5 #include "chrome/renderer/extensions/schema_generated_bindings.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <set> | 8 #include <set> |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/callback.h" | 12 #include "base/callback.h" |
13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
14 #include "base/json/json_reader.h" | 14 #include "base/json/json_reader.h" |
15 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
16 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
17 #include "base/string_number_conversions.h" | 17 #include "base/string_number_conversions.h" |
18 #include "base/string_util.h" | 18 #include "base/string_util.h" |
19 #include "base/utf_string_conversions.h" | 19 #include "base/utf_string_conversions.h" |
20 #include "chrome/common/extensions/extension.h" | 20 #include "chrome/common/extensions/extension.h" |
21 #include "chrome/common/extensions/extension_action.h" | 21 #include "chrome/common/extensions/extension_action.h" |
22 #include "chrome/common/extensions/extension_constants.h" | 22 #include "chrome/common/extensions/extension_constants.h" |
23 #include "chrome/common/extensions/extension_messages.h" | 23 #include "chrome/common/extensions/extension_messages.h" |
24 #include "chrome/common/extensions/extension_set.h" | 24 #include "chrome/common/extensions/extension_set.h" |
25 #include "chrome/common/extensions/url_pattern.h" | 25 #include "chrome/common/extensions/url_pattern.h" |
| 26 #include "chrome/common/extensions/api/extension_api.h" |
26 #include "chrome/common/render_messages.h" | 27 #include "chrome/common/render_messages.h" |
27 #include "chrome/common/url_constants.h" | 28 #include "chrome/common/url_constants.h" |
28 #include "chrome/common/chrome_view_types.h" | 29 #include "chrome/common/chrome_view_types.h" |
29 #include "content/public/renderer/render_view.h" | 30 #include "content/public/renderer/render_view.h" |
30 #include "content/public/renderer/render_view_visitor.h" | 31 #include "content/public/renderer/render_view_visitor.h" |
31 #include "chrome/renderer/chrome_render_process_observer.h" | 32 #include "chrome/renderer/chrome_render_process_observer.h" |
32 #include "chrome/renderer/extensions/chrome_v8_context.h" | 33 #include "chrome/renderer/extensions/chrome_v8_context.h" |
33 #include "chrome/renderer/extensions/chrome_v8_context_set.h" | 34 #include "chrome/renderer/extensions/chrome_v8_context_set.h" |
34 #include "chrome/renderer/extensions/chrome_v8_extension.h" | 35 #include "chrome/renderer/extensions/chrome_v8_extension.h" |
35 #include "chrome/renderer/extensions/event_bindings.h" | 36 #include "chrome/renderer/extensions/event_bindings.h" |
36 #include "chrome/renderer/extensions/extension_dispatcher.h" | 37 #include "chrome/renderer/extensions/extension_dispatcher.h" |
37 #include "chrome/renderer/extensions/extension_helper.h" | 38 #include "chrome/renderer/extensions/extension_helper.h" |
38 #include "chrome/renderer/extensions/renderer_extension_bindings.h" | 39 #include "chrome/renderer/extensions/miscellaneous_bindings.h" |
39 #include "chrome/renderer/extensions/user_script_slave.h" | 40 #include "chrome/renderer/extensions/user_script_slave.h" |
40 #include "chrome/renderer/static_v8_external_string_resource.h" | |
41 #include "content/public/renderer/render_view.h" | 41 #include "content/public/renderer/render_view.h" |
| 42 #include "content/public/renderer/v8_value_converter.h" |
42 #include "grit/common_resources.h" | 43 #include "grit/common_resources.h" |
43 #include "grit/renderer_resources.h" | 44 #include "grit/renderer_resources.h" |
44 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBlob.h" | 45 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBlob.h" |
45 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | 46 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" |
46 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | 47 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
47 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | 48 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
48 #include "third_party/skia/include/core/SkBitmap.h" | 49 #include "third_party/skia/include/core/SkBitmap.h" |
49 #include "third_party/skia/include/core/SkColor.h" | 50 #include "third_party/skia/include/core/SkColor.h" |
50 #include "ui/base/resource/resource_bundle.h" | 51 #include "ui/base/resource/resource_bundle.h" |
51 #include "v8/include/v8.h" | 52 #include "v8/include/v8.h" |
52 #include "webkit/glue/webkit_glue.h" | 53 #include "webkit/glue/webkit_glue.h" |
53 | 54 |
| 55 using content::V8ValueConverter; |
| 56 using extensions::ExtensionAPI; |
54 using WebKit::WebFrame; | 57 using WebKit::WebFrame; |
55 using WebKit::WebView; | 58 using WebKit::WebView; |
56 | 59 |
57 namespace { | 60 namespace { |
58 | 61 |
59 const char* kExtensionDeps[] = { | 62 const char* kExtensionDeps[] = { |
60 "extensions/event.js", | 63 "extensions/event.js", |
61 "extensions/json_schema.js", | 64 "extensions/json_schema.js", |
62 "extensions/renderer_extension_bindings.js", | 65 "extensions/miscellaneous_bindings.js", |
63 "extensions/apitest.js" | 66 "extensions/apitest.js" |
64 }; | 67 }; |
65 | 68 |
66 // Contains info relevant to a pending API request. | 69 // Contains info relevant to a pending API request. |
67 struct PendingRequest { | 70 struct PendingRequest { |
68 public : | 71 public : |
69 PendingRequest(v8::Persistent<v8::Context> context, const std::string& name, | 72 PendingRequest(v8::Persistent<v8::Context> context, const std::string& name, |
70 const std::string& extension_id) | 73 const std::string& extension_id) |
71 : context(context), name(name), extension_id(extension_id) { | 74 : context(context), name(name), extension_id(extension_id) { |
72 } | 75 } |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 std::string extension_id_; | 157 std::string extension_id_; |
155 int browser_window_id_; | 158 int browser_window_id_; |
156 content::ViewType view_type_; | 159 content::ViewType view_type_; |
157 v8::Local<v8::Array> views_; | 160 v8::Local<v8::Array> views_; |
158 int index_; | 161 int index_; |
159 }; | 162 }; |
160 | 163 |
161 class ExtensionImpl : public ChromeV8Extension { | 164 class ExtensionImpl : public ChromeV8Extension { |
162 public: | 165 public: |
163 explicit ExtensionImpl(ExtensionDispatcher* extension_dispatcher) | 166 explicit ExtensionImpl(ExtensionDispatcher* extension_dispatcher) |
164 : ChromeV8Extension("extensions/extension_process_bindings.js", | 167 : ChromeV8Extension("extensions/schema_generated_bindings.js", |
165 IDR_EXTENSION_PROCESS_BINDINGS_JS, | 168 IDR_SCHEMA_GENERATED_BINDINGS_JS, |
166 arraysize(kExtensionDeps), | 169 arraysize(kExtensionDeps), |
167 kExtensionDeps, | 170 kExtensionDeps, |
168 extension_dispatcher) { | 171 extension_dispatcher) { |
169 } | 172 } |
170 ~ExtensionImpl() {} | 173 |
| 174 ~ExtensionImpl() { |
| 175 // TODO(aa): It seems that v8 never deletes us, so this doesn't get called. |
| 176 // Leaving this in here in case v8's implementation ever changes. |
| 177 if (!extension_api_.IsEmpty()) |
| 178 extension_api_.Dispose(); |
| 179 } |
171 | 180 |
172 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( | 181 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( |
173 v8::Handle<v8::String> name) { | 182 v8::Handle<v8::String> name) OVERRIDE { |
174 if (name->Equals(v8::String::New("GetExtensionAPIDefinition"))) { | 183 if (name->Equals(v8::String::New("GetExtensionAPIDefinition"))) { |
175 return v8::FunctionTemplate::New(GetExtensionAPIDefinition); | 184 return v8::FunctionTemplate::New(GetExtensionAPIDefinition, |
| 185 v8::External::New(this)); |
176 } else if (name->Equals(v8::String::New("GetExtensionViews"))) { | 186 } else if (name->Equals(v8::String::New("GetExtensionViews"))) { |
177 return v8::FunctionTemplate::New(GetExtensionViews, | 187 return v8::FunctionTemplate::New(GetExtensionViews, |
178 v8::External::New(this)); | 188 v8::External::New(this)); |
179 } else if (name->Equals(v8::String::New("GetNextRequestId"))) { | 189 } else if (name->Equals(v8::String::New("GetNextRequestId"))) { |
180 return v8::FunctionTemplate::New(GetNextRequestId); | 190 return v8::FunctionTemplate::New(GetNextRequestId); |
181 } else if (name->Equals(v8::String::New("OpenChannelToTab"))) { | 191 } else if (name->Equals(v8::String::New("OpenChannelToTab"))) { |
182 return v8::FunctionTemplate::New(OpenChannelToTab); | 192 return v8::FunctionTemplate::New(OpenChannelToTab); |
183 } else if (name->Equals(v8::String::New("GetNextContextMenuId"))) { | 193 } else if (name->Equals(v8::String::New("GetNextContextMenuId"))) { |
184 return v8::FunctionTemplate::New(GetNextContextMenuId); | 194 return v8::FunctionTemplate::New(GetNextContextMenuId); |
185 } else if (name->Equals(v8::String::New("GetNextTtsEventId"))) { | 195 } else if (name->Equals(v8::String::New("GetNextTtsEventId"))) { |
(...skipping 18 matching lines...) Expand all Loading... |
204 } else if (name->Equals(v8::String::New("CreateBlob"))) { | 214 } else if (name->Equals(v8::String::New("CreateBlob"))) { |
205 return v8::FunctionTemplate::New(CreateBlob, v8::External::New(this)); | 215 return v8::FunctionTemplate::New(CreateBlob, v8::External::New(this)); |
206 } | 216 } |
207 | 217 |
208 return ChromeV8Extension::GetNativeFunction(name); | 218 return ChromeV8Extension::GetNativeFunction(name); |
209 } | 219 } |
210 | 220 |
211 private: | 221 private: |
212 static v8::Handle<v8::Value> GetExtensionAPIDefinition( | 222 static v8::Handle<v8::Value> GetExtensionAPIDefinition( |
213 const v8::Arguments& args) { | 223 const v8::Arguments& args) { |
214 return v8::String::NewExternal( | 224 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); |
215 new StaticV8ExternalAsciiStringResource( | 225 if (!self->extension_api_.IsEmpty()) |
216 ResourceBundle::GetSharedInstance().GetRawDataResource( | 226 return self->extension_api_; |
217 IDR_EXTENSION_API_JSON))); | 227 |
| 228 v8::Persistent<v8::Context> context(v8::Context::New()); |
| 229 v8::Context::Scope context_scope(context); |
| 230 |
| 231 scoped_ptr<V8ValueConverter> v8_value_converter(V8ValueConverter::create()); |
| 232 self->extension_api_ = v8::Persistent<v8::Array>::New( |
| 233 v8::Handle<v8::Array>::Cast( |
| 234 v8_value_converter->ToV8Value( |
| 235 ExtensionAPI::GetInstance()->value(), context))); |
| 236 CHECK(!self->extension_api_.IsEmpty()); |
| 237 |
| 238 // The persistent extension_api_ will keep the context alive. |
| 239 context.Dispose(); |
| 240 |
| 241 return self->extension_api_; |
218 } | 242 } |
219 | 243 |
220 static v8::Handle<v8::Value> GetExtensionViews(const v8::Arguments& args) { | 244 static v8::Handle<v8::Value> GetExtensionViews(const v8::Arguments& args) { |
221 if (args.Length() != 2) | 245 if (args.Length() != 2) |
222 return v8::Undefined(); | 246 return v8::Undefined(); |
223 | 247 |
224 if (!args[0]->IsInt32() || !args[1]->IsString()) | 248 if (!args[0]->IsInt32() || !args[1]->IsString()) |
225 return v8::Undefined(); | 249 return v8::Undefined(); |
226 | 250 |
227 // |browser_window_id| == extension_misc::kUnknownWindowId means getting | 251 // |browser_window_id| == extension_misc::kUnknownWindowId means getting |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 return v8::Undefined(); | 475 return v8::Undefined(); |
452 | 476 |
453 std::string name = *v8::String::AsciiValue(args[0]); | 477 std::string name = *v8::String::AsciiValue(args[0]); |
454 const std::set<std::string>& function_names = | 478 const std::set<std::string>& function_names = |
455 v8_extension->extension_dispatcher_->function_names(); | 479 v8_extension->extension_dispatcher_->function_names(); |
456 if (function_names.find(name) == function_names.end()) { | 480 if (function_names.find(name) == function_names.end()) { |
457 NOTREACHED() << "Unexpected function " << name; | 481 NOTREACHED() << "Unexpected function " << name; |
458 return v8::Undefined(); | 482 return v8::Undefined(); |
459 } | 483 } |
460 | 484 |
461 // TODO(aa): add this to ChromeV8Context. | 485 if (!v8_extension->CheckCurrentContextAccessToExtensionAPI(name)) |
462 if (!v8_extension->CheckPermissionForCurrentRenderView(name)) | |
463 return v8::Undefined(); | 486 return v8::Undefined(); |
464 | 487 |
465 GURL source_url; | 488 GURL source_url; |
466 WebFrame* webframe = current_context->web_frame(); | 489 WebFrame* webframe = current_context->web_frame(); |
467 if (webframe) | 490 if (webframe) |
468 source_url = webframe->document().url(); | 491 source_url = webframe->document().url(); |
469 | 492 |
470 int request_id = args[2]->Int32Value(); | 493 int request_id = args[2]->Int32Value(); |
471 bool has_callback = args[3]->BooleanValue(); | 494 bool has_callback = args[3]->BooleanValue(); |
472 bool for_io_thread = args[4]->BooleanValue(); | 495 bool for_io_thread = args[4]->BooleanValue(); |
473 | 496 |
474 v8::Persistent<v8::Context> v8_context = | 497 v8::Persistent<v8::Context> v8_context = |
475 v8::Persistent<v8::Context>::New(v8::Context::GetCurrent()); | 498 v8::Persistent<v8::Context>::New(v8::Context::GetCurrent()); |
476 DCHECK(!v8_context.IsEmpty()); | 499 DCHECK(!v8_context.IsEmpty()); |
477 g_pending_requests.Get()[request_id].reset(new PendingRequest( | 500 g_pending_requests.Get()[request_id].reset(new PendingRequest( |
478 v8_context, name, current_context->extension_id())); | 501 v8_context, name, current_context->extension_id())); |
479 | 502 |
480 ExtensionHostMsg_Request_Params params; | 503 ExtensionHostMsg_Request_Params params; |
481 params.name = name; | 504 params.name = name; |
482 params.arguments.Swap(value_args); | 505 params.arguments.Swap(value_args); |
| 506 params.extension_id = current_context->extension_id(); |
483 params.source_url = source_url; | 507 params.source_url = source_url; |
484 params.request_id = request_id; | 508 params.request_id = request_id; |
485 params.has_callback = has_callback; | 509 params.has_callback = has_callback; |
486 params.user_gesture = | 510 params.user_gesture = |
487 webframe ? webframe->isProcessingUserGesture() : false; | 511 webframe ? webframe->isProcessingUserGesture() : false; |
488 if (for_io_thread) { | 512 if (for_io_thread) { |
489 renderview->Send(new ExtensionHostMsg_RequestForIOThread( | 513 renderview->Send(new ExtensionHostMsg_RequestForIOThread( |
490 renderview->GetRoutingId(), params)); | 514 renderview->GetRoutingId(), params)); |
491 } else { | 515 } else { |
492 renderview->Send(new ExtensionHostMsg_Request( | 516 renderview->Send(new ExtensionHostMsg_Request( |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 | 606 |
583 return StartRequestCommon(args, &list_value); | 607 return StartRequestCommon(args, &list_value); |
584 } | 608 } |
585 | 609 |
586 static v8::Handle<v8::Value> GetRenderViewId(const v8::Arguments& args) { | 610 static v8::Handle<v8::Value> GetRenderViewId(const v8::Arguments& args) { |
587 content::RenderView* renderview = GetCurrentRenderView(); | 611 content::RenderView* renderview = GetCurrentRenderView(); |
588 if (!renderview) | 612 if (!renderview) |
589 return v8::Undefined(); | 613 return v8::Undefined(); |
590 return v8::Integer::New(renderview->GetRoutingId()); | 614 return v8::Integer::New(renderview->GetRoutingId()); |
591 } | 615 } |
| 616 |
| 617 // Cached JS Array representation of extension_api.json. We store this so that |
| 618 // we don't have to parse it over and over again for every context that uses |
| 619 // it. |
| 620 v8::Persistent<v8::Array> extension_api_; |
592 }; | 621 }; |
593 | 622 |
594 } // namespace | 623 } // namespace |
595 | 624 |
596 v8::Extension* ExtensionProcessBindings::Get( | 625 namespace extensions { |
| 626 |
| 627 v8::Extension* SchemaGeneratedBindings::Get( |
597 ExtensionDispatcher* extension_dispatcher) { | 628 ExtensionDispatcher* extension_dispatcher) { |
598 static v8::Extension* extension = new ExtensionImpl(extension_dispatcher); | 629 static v8::Extension* extension = new ExtensionImpl(extension_dispatcher); |
599 CHECK_EQ(extension_dispatcher, | 630 CHECK_EQ(extension_dispatcher, |
600 static_cast<ExtensionImpl*>(extension)->extension_dispatcher()); | 631 static_cast<ExtensionImpl*>(extension)->extension_dispatcher()); |
601 return extension; | 632 return extension; |
602 } | 633 } |
603 | 634 |
604 // static | 635 // static |
605 void ExtensionProcessBindings::HandleResponse( | 636 void SchemaGeneratedBindings::HandleResponse(const ChromeV8ContextSet& contexts, |
606 const ChromeV8ContextSet& contexts, | 637 int request_id, |
607 int request_id, | 638 bool success, |
608 bool success, | 639 const std::string& response, |
609 const std::string& response, | 640 const std::string& error, |
610 const std::string& error, | 641 std::string* extension_id) { |
611 std::string* extension_id) { | |
612 PendingRequestMap::iterator request = | 642 PendingRequestMap::iterator request = |
613 g_pending_requests.Get().find(request_id); | 643 g_pending_requests.Get().find(request_id); |
614 if (request == g_pending_requests.Get().end()) { | 644 if (request == g_pending_requests.Get().end()) { |
615 // This should not be able to happen since we only remove requests when they | 645 // This should not be able to happen since we only remove requests when they |
616 // are handled. | 646 // are handled. |
617 LOG(ERROR) << "Could not find specified request id: " << request_id; | 647 LOG(ERROR) << "Could not find specified request id: " << request_id; |
618 return; | 648 return; |
619 } | 649 } |
620 | 650 |
621 ChromeV8Context* v8_context = | 651 ChromeV8Context* v8_context = |
(...skipping 25 matching lines...) Expand all Loading... |
647 | 677 |
648 // Save the extension id before erasing the request. | 678 // Save the extension id before erasing the request. |
649 *extension_id = request->second->extension_id; | 679 *extension_id = request->second->extension_id; |
650 | 680 |
651 request->second->context.Dispose(); | 681 request->second->context.Dispose(); |
652 request->second->context.Clear(); | 682 request->second->context.Clear(); |
653 g_pending_requests.Get().erase(request); | 683 g_pending_requests.Get().erase(request); |
654 } | 684 } |
655 | 685 |
656 // static | 686 // static |
657 bool ExtensionProcessBindings::HasPendingRequests( | 687 bool SchemaGeneratedBindings::HasPendingRequests( |
658 const std::string& extension_id) { | 688 const std::string& extension_id) { |
659 for (PendingRequestMap::const_iterator it = g_pending_requests.Get().begin(); | 689 for (PendingRequestMap::const_iterator it = g_pending_requests.Get().begin(); |
660 it != g_pending_requests.Get().end(); ++it) { | 690 it != g_pending_requests.Get().end(); ++it) { |
661 if (it->second->extension_id == extension_id) | 691 if (it->second->extension_id == extension_id) |
662 return true; | 692 return true; |
663 } | 693 } |
664 return false; | 694 return false; |
665 } | 695 } |
| 696 |
| 697 } // namespace |
OLD | NEW |