| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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/dispatcher.h" | 5 #include "chrome/renderer/extensions/dispatcher.h" |
| 6 | 6 |
| 7 #include "base/callback.h" | 7 #include "base/callback.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/debug/alias.h" | 9 #include "base/debug/alias.h" |
| 10 #include "base/json/json_reader.h" | 10 #include "base/json/json_reader.h" |
| 11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
| 12 #include "base/strings/string_piece.h" | 12 #include "base/strings/string_piece.h" |
| 13 #include "base/strings/string_split.h" | 13 #include "base/strings/string_split.h" |
| 14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
| 15 #include "chrome/common/child_process_logging.h" | 15 #include "chrome/common/child_process_logging.h" |
| 16 #include "chrome/common/chrome_switches.h" | 16 #include "chrome/common/chrome_switches.h" |
| 17 #include "chrome/common/chrome_version_info.h" | 17 #include "chrome/common/chrome_version_info.h" |
| 18 #include "chrome/common/extensions/api/extension_api.h" | 18 #include "chrome/common/extensions/api/extension_api.h" |
| 19 #include "chrome/common/extensions/background_info.h" | 19 #include "chrome/common/extensions/background_info.h" |
| 20 #include "chrome/common/extensions/extension.h" | 20 #include "chrome/common/extensions/extension.h" |
| 21 #include "chrome/common/extensions/extension_manifest_constants.h" | 21 #include "chrome/common/extensions/extension_manifest_constants.h" |
| 22 #include "chrome/common/extensions/extension_messages.h" | 22 #include "chrome/common/extensions/extension_messages.h" |
| 23 #include "chrome/common/extensions/features/base_feature_provider.h" | 23 #include "chrome/common/extensions/features/base_feature_provider.h" |
| 24 #include "chrome/common/extensions/features/feature.h" | 24 #include "chrome/common/extensions/features/feature.h" |
| 25 #include "chrome/common/extensions/manifest.h" | 25 #include "chrome/common/extensions/manifest.h" |
| 26 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h" | 26 #include "chrome/common/extensions/manifest_handlers/externally_connectable.h" |
| 27 #include "chrome/common/extensions/manifest_handlers/sandboxed_page_info.h" |
| 27 #include "chrome/common/extensions/message_bundle.h" | 28 #include "chrome/common/extensions/message_bundle.h" |
| 28 #include "chrome/common/extensions/permissions/permission_set.h" | 29 #include "chrome/common/extensions/permissions/permission_set.h" |
| 29 #include "chrome/common/extensions/permissions/permissions_data.h" | 30 #include "chrome/common/extensions/permissions/permissions_data.h" |
| 30 #include "chrome/common/url_constants.h" | 31 #include "chrome/common/url_constants.h" |
| 31 #include "chrome/renderer/chrome_render_process_observer.h" | 32 #include "chrome/renderer/chrome_render_process_observer.h" |
| 32 #include "chrome/renderer/extensions/api_activity_logger.h" | 33 #include "chrome/renderer/extensions/api_activity_logger.h" |
| 33 #include "chrome/renderer/extensions/api_definitions_natives.h" | 34 #include "chrome/renderer/extensions/api_definitions_natives.h" |
| 34 #include "chrome/renderer/extensions/app_bindings.h" | 35 #include "chrome/renderer/extensions/app_bindings.h" |
| 35 #include "chrome/renderer/extensions/app_runtime_custom_bindings.h" | 36 #include "chrome/renderer/extensions/app_runtime_custom_bindings.h" |
| 36 #include "chrome/renderer/extensions/app_window_custom_bindings.h" | 37 #include "chrome/renderer/extensions/app_window_custom_bindings.h" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 66 #include "chrome/renderer/extensions/tab_finder.h" | 67 #include "chrome/renderer/extensions/tab_finder.h" |
| 67 #include "chrome/renderer/extensions/tabs_custom_bindings.h" | 68 #include "chrome/renderer/extensions/tabs_custom_bindings.h" |
| 68 #include "chrome/renderer/extensions/tts_custom_bindings.h" | 69 #include "chrome/renderer/extensions/tts_custom_bindings.h" |
| 69 #include "chrome/renderer/extensions/user_script_slave.h" | 70 #include "chrome/renderer/extensions/user_script_slave.h" |
| 70 #include "chrome/renderer/extensions/web_request_custom_bindings.h" | 71 #include "chrome/renderer/extensions/web_request_custom_bindings.h" |
| 71 #include "chrome/renderer/extensions/webstore_bindings.h" | 72 #include "chrome/renderer/extensions/webstore_bindings.h" |
| 72 #include "chrome/renderer/resource_bundle_source_map.h" | 73 #include "chrome/renderer/resource_bundle_source_map.h" |
| 73 #include "content/public/renderer/render_thread.h" | 74 #include "content/public/renderer/render_thread.h" |
| 74 #include "content/public/renderer/render_view.h" | 75 #include "content/public/renderer/render_view.h" |
| 75 #include "content/public/renderer/v8_value_converter.h" | 76 #include "content/public/renderer/v8_value_converter.h" |
| 77 #include "extensions/common/constants.h" |
| 76 #include "extensions/common/view_type.h" | 78 #include "extensions/common/view_type.h" |
| 77 #include "grit/common_resources.h" | 79 #include "grit/common_resources.h" |
| 78 #include "grit/renderer_resources.h" | 80 #include "grit/renderer_resources.h" |
| 79 #include "third_party/WebKit/public/platform/WebString.h" | 81 #include "third_party/WebKit/public/platform/WebString.h" |
| 80 #include "third_party/WebKit/public/platform/WebURLRequest.h" | 82 #include "third_party/WebKit/public/platform/WebURLRequest.h" |
| 81 #include "third_party/WebKit/public/web/WebDataSource.h" | 83 #include "third_party/WebKit/public/web/WebDataSource.h" |
| 82 #include "third_party/WebKit/public/web/WebDocument.h" | 84 #include "third_party/WebKit/public/web/WebDocument.h" |
| 83 #include "third_party/WebKit/public/web/WebFrame.h" | 85 #include "third_party/WebKit/public/web/WebFrame.h" |
| 84 #include "third_party/WebKit/public/web/WebScopedUserGesture.h" | 86 #include "third_party/WebKit/public/web/WebScopedUserGesture.h" |
| 85 #include "third_party/WebKit/public/web/WebSecurityPolicy.h" | 87 #include "third_party/WebKit/public/web/WebSecurityPolicy.h" |
| (...skipping 922 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1008 // CSP blocks extension page loading by switching the extension ID to | 1010 // CSP blocks extension page loading by switching the extension ID to |
| 1009 // "invalid". This isn't interesting. | 1011 // "invalid". This isn't interesting. |
| 1010 if (extension_id != "invalid") { | 1012 if (extension_id != "invalid") { |
| 1011 LOG(ERROR) << "Extension \"" << extension_id << "\" not found"; | 1013 LOG(ERROR) << "Extension \"" << extension_id << "\" not found"; |
| 1012 RenderThread::Get()->RecordUserMetrics("ExtensionNotFound_ED"); | 1014 RenderThread::Get()->RecordUserMetrics("ExtensionNotFound_ED"); |
| 1013 } | 1015 } |
| 1014 | 1016 |
| 1015 extension_id = ""; | 1017 extension_id = ""; |
| 1016 } | 1018 } |
| 1017 | 1019 |
| 1018 ExtensionURLInfo url_info(frame->document().securityOrigin(), | 1020 Feature::Context context_type = ClassifyJavaScriptContext( |
| 1019 UserScriptSlave::GetDataSourceURLForFrame(frame)); | 1021 extension_id, extension_group, |
| 1020 | 1022 UserScriptSlave::GetDataSourceURLForFrame(frame), |
| 1021 Feature::Context context_type = | 1023 frame->document().securityOrigin()); |
| 1022 ClassifyJavaScriptContext(extension_id, extension_group, url_info); | |
| 1023 | 1024 |
| 1024 ChromeV8Context* context = | 1025 ChromeV8Context* context = |
| 1025 new ChromeV8Context(v8_context, frame, extension, context_type); | 1026 new ChromeV8Context(v8_context, frame, extension, context_type); |
| 1026 v8_context_set_.Add(context); | 1027 v8_context_set_.Add(context); |
| 1027 | 1028 |
| 1028 { | 1029 { |
| 1029 scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context, | 1030 scoped_ptr<ModuleSystem> module_system(new ModuleSystem(context, |
| 1030 &source_map_)); | 1031 &source_map_)); |
| 1031 context->set_module_system(module_system.Pass()); | 1032 context->set_module_system(module_system.Pass()); |
| 1032 } | 1033 } |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1120 | 1121 |
| 1121 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size(); | 1122 VLOG(1) << "Num tracked contexts: " << v8_context_set_.size(); |
| 1122 } | 1123 } |
| 1123 | 1124 |
| 1124 std::string Dispatcher::GetExtensionID(const WebFrame* frame, int world_id) { | 1125 std::string Dispatcher::GetExtensionID(const WebFrame* frame, int world_id) { |
| 1125 if (world_id != 0) { | 1126 if (world_id != 0) { |
| 1126 // Isolated worlds (content script). | 1127 // Isolated worlds (content script). |
| 1127 return user_script_slave_->GetExtensionIdForIsolatedWorld(world_id); | 1128 return user_script_slave_->GetExtensionIdForIsolatedWorld(world_id); |
| 1128 } | 1129 } |
| 1129 | 1130 |
| 1131 // TODO(kalman): Delete this check. |
| 1132 if (frame->document().securityOrigin().isUnique()) |
| 1133 return std::string(); |
| 1134 |
| 1130 // Extension pages (chrome-extension:// URLs). | 1135 // Extension pages (chrome-extension:// URLs). |
| 1131 GURL frame_url = UserScriptSlave::GetDataSourceURLForFrame(frame); | 1136 GURL frame_url = UserScriptSlave::GetDataSourceURLForFrame(frame); |
| 1132 return extensions_.GetExtensionOrAppIDByURL( | 1137 return extensions_.GetExtensionOrAppIDByURL(frame_url); |
| 1133 ExtensionURLInfo(frame->document().securityOrigin(), frame_url)); | |
| 1134 } | 1138 } |
| 1135 | 1139 |
| 1136 bool Dispatcher::IsWithinPlatformApp(const WebFrame* frame) { | 1140 bool Dispatcher::IsWithinPlatformApp(const WebFrame* frame) { |
| 1137 // We intentionally don't use the origin parameter for ExtensionURLInfo since | 1141 GURL url(UserScriptSlave::GetDataSourceURLForFrame(frame->top())); |
| 1138 // it would be empty (i.e. unique) for sandboxed resources and thus not match. | 1142 const Extension* extension = extensions_.GetExtensionOrAppByURL(url); |
| 1139 ExtensionURLInfo url_info( | |
| 1140 UserScriptSlave::GetDataSourceURLForFrame(frame->top())); | |
| 1141 const Extension* extension = extensions_.GetExtensionOrAppByURL(url_info); | |
| 1142 | 1143 |
| 1143 return extension && extension->is_platform_app(); | 1144 return extension && extension->is_platform_app(); |
| 1144 } | 1145 } |
| 1145 | 1146 |
| 1146 void Dispatcher::WillReleaseScriptContext( | 1147 void Dispatcher::WillReleaseScriptContext( |
| 1147 WebFrame* frame, v8::Handle<v8::Context> v8_context, int world_id) { | 1148 WebFrame* frame, v8::Handle<v8::Context> v8_context, int world_id) { |
| 1148 ChromeV8Context* context = v8_context_set_.GetByV8Context(v8_context); | 1149 ChromeV8Context* context = v8_context_set_.GetByV8Context(v8_context); |
| 1149 if (!context) | 1150 if (!context) |
| 1150 return; | 1151 return; |
| 1151 | 1152 |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1368 // that it still considers the extension idle despite any activity the suspend | 1369 // that it still considers the extension idle despite any activity the suspend |
| 1369 // event creates. | 1370 // event creates. |
| 1370 DispatchEvent(extension_id, kOnSuspendEvent); | 1371 DispatchEvent(extension_id, kOnSuspendEvent); |
| 1371 RenderThread::Get()->Send(new ExtensionHostMsg_SuspendAck(extension_id)); | 1372 RenderThread::Get()->Send(new ExtensionHostMsg_SuspendAck(extension_id)); |
| 1372 } | 1373 } |
| 1373 | 1374 |
| 1374 void Dispatcher::OnCancelSuspend(const std::string& extension_id) { | 1375 void Dispatcher::OnCancelSuspend(const std::string& extension_id) { |
| 1375 DispatchEvent(extension_id, kOnSuspendCanceledEvent); | 1376 DispatchEvent(extension_id, kOnSuspendCanceledEvent); |
| 1376 } | 1377 } |
| 1377 | 1378 |
| 1379 // TODO(kalman): This is checking for the wrong thing, it should be checking if |
| 1380 // the frame's security origin is unique. The extension sandbox directive is |
| 1381 // checked for in chrome/common/extensions/csp_handler.cc. |
| 1382 bool Dispatcher::IsSandboxedPage(const GURL& url) const { |
| 1383 if (url.SchemeIs(extensions::kExtensionScheme)) { |
| 1384 const Extension* extension = extensions_.GetByID(url.host()); |
| 1385 if (extension) { |
| 1386 return extensions::SandboxedPageInfo::IsSandboxedPage(extension, |
| 1387 url.path()); |
| 1388 } |
| 1389 } |
| 1390 return false; |
| 1391 } |
| 1392 |
| 1378 Feature::Context Dispatcher::ClassifyJavaScriptContext( | 1393 Feature::Context Dispatcher::ClassifyJavaScriptContext( |
| 1379 const std::string& extension_id, | 1394 const std::string& extension_id, |
| 1380 int extension_group, | 1395 int extension_group, |
| 1381 const ExtensionURLInfo& url_info) { | 1396 const GURL& url, |
| 1397 const WebKit::WebSecurityOrigin& origin) { |
| 1382 DCHECK_GE(extension_group, 0); | 1398 DCHECK_GE(extension_group, 0); |
| 1383 if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS) { | 1399 if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS) { |
| 1384 return extensions_.Contains(extension_id) ? | 1400 return extensions_.Contains(extension_id) ? |
| 1385 Feature::CONTENT_SCRIPT_CONTEXT : Feature::UNSPECIFIED_CONTEXT; | 1401 Feature::CONTENT_SCRIPT_CONTEXT : Feature::UNSPECIFIED_CONTEXT; |
| 1386 } | 1402 } |
| 1387 | 1403 |
| 1388 // We have an explicit check for sandboxed pages before checking whether the | 1404 // We have an explicit check for sandboxed pages before checking whether the |
| 1389 // extension is active in this process because: | 1405 // extension is active in this process because: |
| 1390 // 1. Sandboxed pages run in the same process as regular extension pages, so | 1406 // 1. Sandboxed pages run in the same process as regular extension pages, so |
| 1391 // the extension is considered active. | 1407 // the extension is considered active. |
| 1392 // 2. ScriptContext creation (which triggers bindings injection) happens | 1408 // 2. ScriptContext creation (which triggers bindings injection) happens |
| 1393 // before the SecurityContext is updated with the sandbox flags (after | 1409 // before the SecurityContext is updated with the sandbox flags (after |
| 1394 // reading the CSP header), so url_info.url().securityOrigin() is not | 1410 // reading the CSP header), so the caller can't check if the context's |
| 1395 // unique yet. | 1411 // security origin is unique yet. |
| 1396 if (extensions_.IsSandboxedPage(url_info)) | 1412 if (IsSandboxedPage(url)) |
| 1397 return Feature::WEB_PAGE_CONTEXT; | 1413 return Feature::WEB_PAGE_CONTEXT; |
| 1398 | 1414 |
| 1399 if (IsExtensionActive(extension_id)) | 1415 if (IsExtensionActive(extension_id)) |
| 1400 return Feature::BLESSED_EXTENSION_CONTEXT; | 1416 return Feature::BLESSED_EXTENSION_CONTEXT; |
| 1401 | 1417 |
| 1402 if (extensions_.ExtensionBindingsAllowed(url_info)) { | 1418 // TODO(kalman): This isUnique() check is wrong, it should be performed as |
| 1419 // part of IsSandboxedPage(). |
| 1420 if (!origin.isUnique() && extensions_.ExtensionBindingsAllowed(url)) { |
| 1403 return extensions_.Contains(extension_id) ? | 1421 return extensions_.Contains(extension_id) ? |
| 1404 Feature::UNBLESSED_EXTENSION_CONTEXT : Feature::UNSPECIFIED_CONTEXT; | 1422 Feature::UNBLESSED_EXTENSION_CONTEXT : Feature::UNSPECIFIED_CONTEXT; |
| 1405 } | 1423 } |
| 1406 | 1424 |
| 1407 if (url_info.url().is_valid()) | 1425 if (url.is_valid()) |
| 1408 return Feature::WEB_PAGE_CONTEXT; | 1426 return Feature::WEB_PAGE_CONTEXT; |
| 1409 | 1427 |
| 1410 return Feature::UNSPECIFIED_CONTEXT; | 1428 return Feature::UNSPECIFIED_CONTEXT; |
| 1411 } | 1429 } |
| 1412 | 1430 |
| 1413 void Dispatcher::OnExtensionResponse(int request_id, | 1431 void Dispatcher::OnExtensionResponse(int request_id, |
| 1414 bool success, | 1432 bool success, |
| 1415 const base::ListValue& response, | 1433 const base::ListValue& response, |
| 1416 const std::string& error) { | 1434 const std::string& error) { |
| 1417 request_sender_->HandleResponse(request_id, success, response, error); | 1435 request_sender_->HandleResponse(request_id, success, response, error); |
| 1418 } | 1436 } |
| 1419 | 1437 |
| 1420 bool Dispatcher::CheckContextAccessToExtensionAPI( | 1438 bool Dispatcher::CheckContextAccessToExtensionAPI( |
| 1421 const std::string& function_name, ChromeV8Context* context) const { | 1439 const std::string& function_name, ChromeV8Context* context) const { |
| 1422 if (!context) { | 1440 if (!context) { |
| 1423 DLOG(ERROR) << "Not in a v8::Context"; | 1441 DLOG(ERROR) << "Not in a v8::Context"; |
| 1424 return false; | 1442 return false; |
| 1425 } | 1443 } |
| 1426 | 1444 |
| 1427 if (!context->extension()) { | 1445 if (!context->extension()) { |
| 1428 v8::ThrowException( | 1446 v8::ThrowException( |
| 1429 v8::Exception::Error(v8::String::New("Not in an extension."))); | 1447 v8::Exception::Error(v8::String::New("Not in an extension."))); |
| 1430 return false; | 1448 return false; |
| 1431 } | 1449 } |
| 1432 | 1450 |
| 1433 // Theoretically we could end up with bindings being injected into sandboxed | 1451 // Theoretically we could end up with bindings being injected into sandboxed |
| 1434 // frames, for example content scripts. Don't let them execute API functions. | 1452 // frames, for example content scripts. Don't let them execute API functions. |
| 1435 WebKit::WebFrame* frame = context->web_frame(); | 1453 WebKit::WebFrame* frame = context->web_frame(); |
| 1436 ExtensionURLInfo url_info(frame->document().securityOrigin(), | 1454 if (IsSandboxedPage(UserScriptSlave::GetDataSourceURLForFrame(frame))) { |
| 1437 UserScriptSlave::GetDataSourceURLForFrame(frame)); | |
| 1438 if (extensions_.IsSandboxedPage(url_info)) { | |
| 1439 static const char kMessage[] = | 1455 static const char kMessage[] = |
| 1440 "%s cannot be used within a sandboxed frame."; | 1456 "%s cannot be used within a sandboxed frame."; |
| 1441 std::string error_msg = base::StringPrintf(kMessage, function_name.c_str()); | 1457 std::string error_msg = base::StringPrintf(kMessage, function_name.c_str()); |
| 1442 v8::ThrowException( | 1458 v8::ThrowException( |
| 1443 v8::Exception::Error(v8::String::New(error_msg.c_str()))); | 1459 v8::Exception::Error(v8::String::New(error_msg.c_str()))); |
| 1444 return false; | 1460 return false; |
| 1445 } | 1461 } |
| 1446 | 1462 |
| 1447 Feature::Availability availability = context->GetAvailability(function_name); | 1463 Feature::Availability availability = context->GetAvailability(function_name); |
| 1448 if (!availability.is_available()) { | 1464 if (!availability.is_available()) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1502 RenderView* background_view = | 1518 RenderView* background_view = |
| 1503 ExtensionHelper::GetBackgroundPage(extension_id); | 1519 ExtensionHelper::GetBackgroundPage(extension_id); |
| 1504 if (background_view) { | 1520 if (background_view) { |
| 1505 background_view->Send(new ExtensionHostMsg_EventAck( | 1521 background_view->Send(new ExtensionHostMsg_EventAck( |
| 1506 background_view->GetRoutingID())); | 1522 background_view->GetRoutingID())); |
| 1507 } | 1523 } |
| 1508 } | 1524 } |
| 1509 } | 1525 } |
| 1510 | 1526 |
| 1511 } // namespace extensions | 1527 } // namespace extensions |
| OLD | NEW |