summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/extension_webrequest_api.cc46
-rw-r--r--chrome/browser/extensions/extension_webrequest_api.h1
-rw-r--r--chrome/test/data/extensions/api_test/webrequest/test_blocking.html114
3 files changed, 158 insertions, 3 deletions
diff --git a/chrome/browser/extensions/extension_webrequest_api.cc b/chrome/browser/extensions/extension_webrequest_api.cc
index 3c6bcca..b9bfd0f 100644
--- a/chrome/browser/extensions/extension_webrequest_api.cc
+++ b/chrome/browser/extensions/extension_webrequest_api.cc
@@ -114,6 +114,25 @@ bool IsWebRequestEvent(const std::string& event_name) {
event_name) != ARRAYEND(kWebRequestEvents);
}
+// Returns whether |request| has been triggered by an extension in
+// |extension_info_map|.
+bool IsRequestFromExtension(const net::URLRequest* request,
+ const ExtensionInfoMap* extension_info_map) {
+ // |extension_info_map| is NULL for system-level requests.
+ if (!extension_info_map)
+ return false;
+
+ const ResourceDispatcherHostRequestInfo* info =
+ ResourceDispatcherHost::InfoForRequest(request);
+
+ // If this request was not created by the ResourceDispatcher, |info| is NULL.
+ // All requests from extensions are created by the ResourceDispatcher.
+ if (!info)
+ return false;
+
+ return extension_info_map->process_map().Contains(info->child_id());
+}
+
// Returns true if the scheme is one we want to allow extensions to have access
// to. Extensions still need specific permissions for a given URL, which is
// covered by CanExtensionAccessURL.
@@ -1093,6 +1112,7 @@ void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
int tab_id,
int window_id,
ResourceType::Type resource_type,
+ bool is_request_from_extension,
int* extra_info_spec,
std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
matching_listeners) {
@@ -1127,9 +1147,24 @@ void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
!extension_info_map->CanCrossIncognito(extension)))
continue;
+ bool blocking_listener =
+ (it->extra_info_spec &
+ (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
+
+ // We do not want to notify extensions about XHR requests that are
+ // triggered by themselves. This is a workaround to prevent deadlocks
+ // in case of synchronous XHR requests that block the extension renderer
+ // and therefore prevent the extension from processing the request
+ // handler. This is only a problem for blocking listeners.
+ // http://crbug.com/105656
+ bool possibly_synchronous_xhr_from_extension =
+ is_request_from_extension && resource_type == ResourceType::XHR;
+
// Only send webRequest events for URLs the extension has access to.
- if (!CanExtensionAccessURL(extension, url))
+ if (!CanExtensionAccessURL(extension, url) ||
+ (blocking_listener && possibly_synchronous_xhr_from_extension)) {
continue;
+ }
}
matching_listeners->push_back(&(*it));
@@ -1163,15 +1198,20 @@ ExtensionWebRequestEventRouter::GetMatchingListeners(
std::vector<const ExtensionWebRequestEventRouter::EventListener*>
matching_listeners;
+ bool is_request_from_extension =
+ IsRequestFromExtension(request, extension_info_map);
+
GetMatchingListenersImpl(
profile, extension_info_map, false, event_name, url,
- tab_id, window_id, resource_type, extra_info_spec, &matching_listeners);
+ tab_id, window_id, resource_type, is_request_from_extension,
+ extra_info_spec, &matching_listeners);
CrossProfileMap::const_iterator cross_profile =
cross_profile_map_.find(profile);
if (cross_profile != cross_profile_map_.end()) {
GetMatchingListenersImpl(
cross_profile->second, extension_info_map, true, event_name, url,
- tab_id, window_id, resource_type, extra_info_spec, &matching_listeners);
+ tab_id, window_id, resource_type, is_request_from_extension,
+ extra_info_spec, &matching_listeners);
}
return matching_listeners;
diff --git a/chrome/browser/extensions/extension_webrequest_api.h b/chrome/browser/extensions/extension_webrequest_api.h
index ba15265..941d52d 100644
--- a/chrome/browser/extensions/extension_webrequest_api.h
+++ b/chrome/browser/extensions/extension_webrequest_api.h
@@ -289,6 +289,7 @@ class ExtensionWebRequestEventRouter {
int tab_id,
int window_id,
ResourceType::Type resource_type,
+ bool is_request_from_extension,
int* extra_info_spec,
std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
matching_listeners);
diff --git a/chrome/test/data/extensions/api_test/webrequest/test_blocking.html b/chrome/test/data/extensions/api_test/webrequest/test_blocking.html
index ee849b3..608b31a 100644
--- a/chrome/test/data/extensions/api_test/webrequest/test_blocking.html
+++ b/chrome/test/data/extensions/api_test/webrequest/test_blocking.html
@@ -19,6 +19,9 @@ function getURLNonUTF8SetCookie() {
function getURLHttpSimpleLoad() {
return getServerURL('files/extensions/api_test/webrequest/simpleLoad/a.html');
}
+function getURLHttpXHRData() {
+ return getServerURL('files/extensions/api_test/webrequest/xhr/data.json');
+}
function toCharCodes(str) {
var result = [];
@@ -516,5 +519,116 @@ runTests([
});
});
},
+
+ // Checks that XHR requests from ourself are invisible to blocking handlers.
+ function xhrsFromOurselfAreInvisible() {
+ expect(
+ [ // events
+ { label: "a-onBeforeRequest",
+ event: "onBeforeRequest",
+ details: {
+ url: getURL("simpleLoad/a.html"),
+ frameUrl: getURL("simpleLoad/a.html")
+ }
+ },
+ { label: "a-onResponseStarted",
+ event: "onResponseStarted",
+ details: {
+ url: getURL("simpleLoad/a.html"),
+ statusCode: 200,
+ fromCache: false,
+ statusLine: "HTTP/1.1 200 OK",
+ // Request to chrome-extension:// url has no IP.
+ }
+ },
+ { label: "a-onCompleted",
+ event: "onCompleted",
+ details: {
+ url: getURL("simpleLoad/a.html"),
+ statusCode: 200,
+ fromCache: false,
+ statusLine: "HTTP/1.1 200 OK",
+ // Request to chrome-extension:// url has no IP.
+ }
+ },
+ // We do not see onBeforeRequest for the XHR request here because it is
+ // handled by a blocking handler.
+ { label: "x-onSendHeaders",
+ event: "onSendHeaders",
+ details: {
+ url: getURLHttpXHRData(),
+ tabId: 1,
+ type: "xmlhttprequest",
+ }
+ },
+ { label: "x-onResponseStarted",
+ event: "onResponseStarted",
+ details: {
+ url: getURLHttpXHRData(),
+ statusCode: 200,
+ fromCache: false,
+ statusLine: "HTTP/1.0 200 OK",
+ tabId: 1,
+ type: "xmlhttprequest",
+ ip: "127.0.0.1",
+ // Request to chrome-extension:// url has no IP.
+ }
+ },
+ { label: "x-onCompleted",
+ event: "onCompleted",
+ details: {
+ url: getURLHttpXHRData(),
+ statusCode: 200,
+ fromCache: false,
+ statusLine: "HTTP/1.0 200 OK",
+ tabId: 1,
+ type: "xmlhttprequest",
+ ip: "127.0.0.1",
+ // Request to chrome-extension:// url has no IP.
+ }
+ },
+ { label: "b-onBeforeRequest",
+ event: "onBeforeRequest",
+ details: {
+ url: getURL("complexLoad/b.jpg"),
+ frameUrl: getURL("complexLoad/b.jpg")
+ }
+ },
+ { label: "b-onResponseStarted",
+ event: "onResponseStarted",
+ details: {
+ url: getURL("complexLoad/b.jpg"),
+ statusCode: 200,
+ fromCache: false,
+ statusLine: "HTTP/1.1 200 OK",
+ // Request to chrome-extension:// url has no IP.
+ }
+ },
+ { label: "b-onCompleted",
+ event: "onCompleted",
+ details: {
+ url: getURL("complexLoad/b.jpg"),
+ statusCode: 200,
+ fromCache: false,
+ statusLine: "HTTP/1.1 200 OK",
+ // Request to chrome-extension:// url has no IP.
+ }
+ },
+ ],
+ [ // event order
+ ["a-onBeforeRequest", "a-onResponseStarted", "a-onCompleted",
+ "x-onSendHeaders", "x-onResponseStarted", "x-onCompleted",
+ "b-onBeforeRequest", "b-onResponseStarted", "b-onCompleted"]
+ ],
+ {}, ["blocking"]);
+ // Check the page content for our modified User-Agent string.
+ navigateAndWait(getURL("simpleLoad/a.html"), function() {
+ var req = new XMLHttpRequest();
+ var asynchronous = false;
+ req.open("GET", getURLHttpXHRData(), asynchronous);
+ req.send(null);
+ navigateAndWait(getURL("complexLoad/b.jpg"));
+ });
+ },
]);
</script>