| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/browser/extensions/extension_protocols.h" | 5 #include "chrome/browser/extensions/extension_protocols.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 virtual ~URLRequestResourceBundleJob() { } | 60 virtual ~URLRequestResourceBundleJob() { } |
| 61 | 61 |
| 62 // We need the filename of the resource to determine the mime type. | 62 // We need the filename of the resource to determine the mime type. |
| 63 FilePath filename_; | 63 FilePath filename_; |
| 64 | 64 |
| 65 // The resource bundle id to load. | 65 // The resource bundle id to load. |
| 66 int resource_id_; | 66 int resource_id_; |
| 67 }; | 67 }; |
| 68 | 68 |
| 69 // Returns true if an chrome-extension:// resource should be allowed to load. | 69 // Returns true if an chrome-extension:// resource should be allowed to load. |
| 70 // TODO(aa): This should be moved into ExtensionResourceRequestPolicy, but we |
| 71 // first need to find a way to get CanLoadInIncognito state into the renderers. |
| 70 bool AllowExtensionResourceLoad(net::URLRequest* request, | 72 bool AllowExtensionResourceLoad(net::URLRequest* request, |
| 71 ChromeURLRequestContext* context, | 73 ChromeURLRequestContext* context, |
| 72 const std::string& scheme) { | 74 const std::string& scheme) { |
| 73 const ResourceDispatcherHostRequestInfo* info = | 75 const ResourceDispatcherHostRequestInfo* info = |
| 74 ResourceDispatcherHost::InfoForRequest(request); | 76 ResourceDispatcherHost::InfoForRequest(request); |
| 75 | 77 |
| 76 // We have seen crashes where info is NULL: crbug.com/52374. | 78 // We have seen crashes where info is NULL: crbug.com/52374. |
| 77 if (!info) { | 79 if (!info) { |
| 78 LOG(ERROR) << "Allowing load of " << request->url().spec() | 80 LOG(ERROR) << "Allowing load of " << request->url().spec() |
| 79 << "from unknown origin. Could not find user data for " | 81 << "from unknown origin. Could not find user data for " |
| 80 << "request."; | 82 << "request."; |
| 81 return true; | 83 return true; |
| 82 } | 84 } |
| 83 | 85 |
| 84 GURL origin_url(info->frame_origin()); | |
| 85 | |
| 86 // chrome:// URLs are always allowed to load chrome-extension:// resources. | |
| 87 // The app launcher in the NTP uses this feature, as does dev tools. | |
| 88 if (origin_url.SchemeIs(chrome::kChromeDevToolsScheme) || | |
| 89 origin_url.SchemeIs(chrome::kChromeUIScheme)) | |
| 90 return true; | |
| 91 | |
| 92 // Disallow loading of packaged resources for hosted apps. We don't allow | |
| 93 // hybrid hosted/packaged apps. The one exception is access to icons, since | |
| 94 // some extensions want to be able to do things like create their own | |
| 95 // launchers. | |
| 96 if (context->extension_info_map()-> | |
| 97 ExtensionHasWebExtent(request->url().host())) { | |
| 98 if (!context->extension_info_map()->URLIsForExtensionIcon(request->url())) { | |
| 99 LOG(ERROR) << "Denying load of " << request->url().spec() << " from " | |
| 100 << "hosted app."; | |
| 101 return false; | |
| 102 } | |
| 103 } | |
| 104 | |
| 105 // Don't allow toplevel navigations to extension resources in incognito mode. | 86 // Don't allow toplevel navigations to extension resources in incognito mode. |
| 106 // This is because an extension must run in a single process, and an | 87 // This is because an extension must run in a single process, and an |
| 107 // incognito tab prevents that. | 88 // incognito tab prevents that. |
| 108 if (context->is_off_the_record() && | 89 if (context->is_off_the_record() && |
| 109 info->resource_type() == ResourceType::MAIN_FRAME && | 90 info->resource_type() == ResourceType::MAIN_FRAME && |
| 110 !context->extension_info_map()-> | 91 !context->extension_info_map()-> |
| 111 ExtensionCanLoadInIncognito(request->url().host())) { | 92 ExtensionCanLoadInIncognito(request->url().host())) { |
| 112 LOG(ERROR) << "Denying load of " << request->url().spec() << " from " | 93 LOG(ERROR) << "Denying load of " << request->url().spec() << " from " |
| 113 << "incognito tab."; | 94 << "incognito tab."; |
| 114 return false; | 95 return false; |
| 115 } | 96 } |
| 116 | 97 |
| 117 // Otherwise, pages are allowed to load resources from extensions if the | 98 return true; |
| 118 // extension has host permissions to (and therefore could be running script | |
| 119 // in, which might need access to the extension resources). | |
| 120 // | |
| 121 // Exceptions are: | |
| 122 // - empty origin (needed for some edge cases when we have empty origins) | |
| 123 // - chrome-extension:// (for legacy reasons -- some extensions interop) | |
| 124 // - data: (basic HTML notifications use data URLs internally) | |
| 125 if (origin_url.is_empty() || | |
| 126 origin_url.SchemeIs(chrome::kExtensionScheme) | | |
| 127 origin_url.SchemeIs(chrome::kDataScheme)) { | |
| 128 return true; | |
| 129 } else { | |
| 130 ExtensionExtent host_permissions = context->extension_info_map()-> | |
| 131 GetEffectiveHostPermissionsForExtension(request->url().host()); | |
| 132 if (host_permissions.ContainsURL(origin_url)) { | |
| 133 return true; | |
| 134 } else { | |
| 135 LOG(ERROR) << "Denying load of " << request->url().spec() << " from " | |
| 136 << origin_url.spec() << " because the extension does not have " | |
| 137 << "access to the requesting page."; | |
| 138 return false; | |
| 139 } | |
| 140 } | |
| 141 } | 99 } |
| 142 | 100 |
| 143 } // namespace | 101 } // namespace |
| 144 | 102 |
| 145 // Factory registered with net::URLRequest to create URLRequestJobs for | 103 // Factory registered with net::URLRequest to create URLRequestJobs for |
| 146 // extension:// URLs. | 104 // extension:// URLs. |
| 147 static net::URLRequestJob* CreateExtensionURLRequestJob( | 105 static net::URLRequestJob* CreateExtensionURLRequestJob( |
| 148 net::URLRequest* request, | 106 net::URLRequest* request, |
| 149 const std::string& scheme) { | 107 const std::string& scheme) { |
| 150 ChromeURLRequestContext* context = | 108 ChromeURLRequestContext* context = |
| 151 static_cast<ChromeURLRequestContext*>(request->context()); | 109 static_cast<ChromeURLRequestContext*>(request->context()); |
| 152 | 110 |
| 153 // TODO(mpcomplete): better error code. | 111 // TODO(mpcomplete): better error code. |
| 154 if (!AllowExtensionResourceLoad(request, context, scheme)) | 112 if (!AllowExtensionResourceLoad(request, context, scheme)) { |
| 113 LOG(ERROR) << "disallowed in extension protocols"; |
| 155 return new net::URLRequestErrorJob(request, net::ERR_ADDRESS_UNREACHABLE); | 114 return new net::URLRequestErrorJob(request, net::ERR_ADDRESS_UNREACHABLE); |
| 115 } |
| 156 | 116 |
| 157 // chrome-extension://extension-id/resource/path.js | 117 // chrome-extension://extension-id/resource/path.js |
| 158 const std::string& extension_id = request->url().host(); | 118 const std::string& extension_id = request->url().host(); |
| 159 FilePath directory_path = context->extension_info_map()-> | 119 FilePath directory_path = context->extension_info_map()-> |
| 160 GetPathForExtension(extension_id); | 120 GetPathForExtension(extension_id); |
| 161 if (directory_path.value().empty()) { | 121 if (directory_path.value().empty()) { |
| 162 LOG(WARNING) << "Failed to GetPathForExtension: " << extension_id; | 122 LOG(WARNING) << "Failed to GetPathForExtension: " << extension_id; |
| 163 return NULL; | 123 return NULL; |
| 164 } | 124 } |
| 165 | 125 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 | 178 |
| 219 return new net::URLRequestFileJob(request, resource.GetFilePath()); | 179 return new net::URLRequestFileJob(request, resource.GetFilePath()); |
| 220 } | 180 } |
| 221 | 181 |
| 222 void RegisterExtensionProtocols() { | 182 void RegisterExtensionProtocols() { |
| 223 net::URLRequest::RegisterProtocolFactory(chrome::kExtensionScheme, | 183 net::URLRequest::RegisterProtocolFactory(chrome::kExtensionScheme, |
| 224 &CreateExtensionURLRequestJob); | 184 &CreateExtensionURLRequestJob); |
| 225 net::URLRequest::RegisterProtocolFactory(chrome::kUserScriptScheme, | 185 net::URLRequest::RegisterProtocolFactory(chrome::kUserScriptScheme, |
| 226 &CreateUserScriptURLRequestJob); | 186 &CreateUserScriptURLRequestJob); |
| 227 } | 187 } |
| OLD | NEW |