Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(367)

Side by Side Diff: chrome/browser/extensions/api/webrequest/webrequest_api.cc

Issue 9701039: Refactor folders in chrome/browser/extensions/api (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Small change to includes in extension_event_router.cc Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/browser/extensions/api/webrequest/webrequest_api.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/json/json_writer.h"
11 #include "base/metrics/histogram.h"
12 #include "base/string_number_conversions.h"
13 #include "base/string_util.h"
14 #include "base/time.h"
15 #include "base/utf_string_conversions.h"
16 #include "base/values.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_content_browser_client.h"
19 #include "chrome/browser/extensions/api/webrequest/webrequest_api_constants.h"
20 #include "chrome/browser/extensions/api/webrequest/webrequest_api_helpers.h"
21 #include "chrome/browser/extensions/api/webrequest/webrequest_time_tracker.h"
22 #include "chrome/browser/extensions/extension_event_router.h"
23 #include "chrome/browser/extensions/extension_info_map.h"
24 #include "chrome/browser/extensions/extension_prefs.h"
25 #include "chrome/browser/extensions/extension_service.h"
26 #include "chrome/browser/extensions/extension_tab_id_map.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/profiles/profile_manager.h"
29 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
30 #include "chrome/browser/renderer_host/web_cache_manager.h"
31 #include "chrome/common/extensions/extension.h"
32 #include "chrome/common/extensions/extension_constants.h"
33 #include "chrome/common/extensions/extension_error_utils.h"
34 #include "chrome/common/extensions/extension_messages.h"
35 #include "chrome/common/extensions/url_pattern.h"
36 #include "chrome/common/url_constants.h"
37 #include "content/public/browser/browser_message_filter.h"
38 #include "content/public/browser/browser_thread.h"
39 #include "content/public/browser/render_process_host.h"
40 #include "content/public/browser/resource_request_info.h"
41 #include "googleurl/src/gurl.h"
42 #include "grit/generated_resources.h"
43 #include "net/base/auth.h"
44 #include "net/base/net_errors.h"
45 #include "net/base/net_log.h"
46 #include "net/http/http_response_headers.h"
47 #include "net/url_request/url_request.h"
48 #include "ui/base/l10n/l10n_util.h"
49
50 using content::BrowserMessageFilter;
51 using content::BrowserThread;
52 using content::ResourceRequestInfo;
53
54 namespace helpers = extension_webrequest_api_helpers;
55 namespace keys = extension_webrequest_api_constants;
56
57 namespace {
58
59 // List of all the webRequest events.
60 static const char* const kWebRequestEvents[] = {
61 keys::kOnBeforeRedirect,
62 keys::kOnBeforeRequest,
63 keys::kOnBeforeSendHeaders,
64 keys::kOnCompleted,
65 keys::kOnErrorOccurred,
66 keys::kOnSendHeaders,
67 keys::kOnAuthRequired,
68 keys::kOnResponseStarted,
69 keys::kOnHeadersReceived,
70 };
71
72 static const char* kResourceTypeStrings[] = {
73 "main_frame",
74 "sub_frame",
75 "stylesheet",
76 "script",
77 "image",
78 "object",
79 "xmlhttprequest",
80 "other",
81 "other",
82 };
83
84 static ResourceType::Type kResourceTypeValues[] = {
85 ResourceType::MAIN_FRAME,
86 ResourceType::SUB_FRAME,
87 ResourceType::STYLESHEET,
88 ResourceType::SCRIPT,
89 ResourceType::IMAGE,
90 ResourceType::OBJECT,
91 ResourceType::XHR,
92 ResourceType::LAST_TYPE, // represents "other"
93 // TODO(jochen): We duplicate the last entry, so the array's size is not a
94 // power of two. If it is, this triggers a bug in gcc 4.4 in Release builds
95 // (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949). Once we use a version
96 // of gcc with this bug fixed, or the array is changed so this duplicate
97 // entry is no longer required, this should be removed.
98 ResourceType::LAST_TYPE,
99 };
100
101 COMPILE_ASSERT(
102 arraysize(kResourceTypeStrings) == arraysize(kResourceTypeValues),
103 keep_resource_types_in_sync);
104
105 #define ARRAYEND(array) (array + arraysize(array))
106
107 // Returns the frame ID as it will be passed to the extension:
108 // 0 if the navigation happens in the main frame, or the frame ID
109 // modulo 32 bits otherwise.
110 // Keep this in sync with the GetFrameId() function in
111 // extension_webnavigation_api.cc.
112 int GetFrameId(bool is_main_frame, int64 frame_id) {
113 return is_main_frame ? 0 : static_cast<int>(frame_id);
114 }
115
116 bool IsWebRequestEvent(const std::string& event_name) {
117 return std::find(kWebRequestEvents, ARRAYEND(kWebRequestEvents),
118 event_name) != ARRAYEND(kWebRequestEvents);
119 }
120
121 // Returns whether |request| has been triggered by an extension in
122 // |extension_info_map|.
123 bool IsRequestFromExtension(const net::URLRequest* request,
124 const ExtensionInfoMap* extension_info_map) {
125 // |extension_info_map| is NULL for system-level requests.
126 if (!extension_info_map)
127 return false;
128
129 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
130
131 // If this request was not created by the ResourceDispatcher, |info| is NULL.
132 // All requests from extensions are created by the ResourceDispatcher.
133 if (!info)
134 return false;
135
136 return extension_info_map->process_map().Contains(info->GetChildID());
137 }
138
139 // Returns true if the URL is sensitive and requests to this URL must not be
140 // modified/canceled by extensions, e.g. because it is targeted to the webstore
141 // to check for updates, extension blacklisting, etc.
142 bool IsSensitiveURL(const GURL& url) {
143 bool is_webstore_gallery_url =
144 StartsWithASCII(url.spec(), extension_urls::kGalleryBrowsePrefix, true);
145 bool is_google_com_chrome_url =
146 EndsWith(url.host(), "google.com", true) &&
147 StartsWithASCII(url.path(), "/chrome", true);
148 GURL::Replacements replacements;
149 replacements.ClearQuery();
150 replacements.ClearRef();
151 GURL url_without_query = url.ReplaceComponents(replacements);
152 return is_webstore_gallery_url || is_google_com_chrome_url ||
153 extension_urls::IsWebstoreUpdateUrl(url_without_query) ||
154 extension_urls::IsBlacklistUpdateUrl(url);
155 }
156
157 // Returns true if the scheme is one we want to allow extensions to have access
158 // to. Extensions still need specific permissions for a given URL, which is
159 // covered by CanExtensionAccessURL.
160 bool HasWebRequestScheme(const GURL& url) {
161 return (url.SchemeIs(chrome::kAboutScheme) ||
162 url.SchemeIs(chrome::kFileScheme) ||
163 url.SchemeIs(chrome::kFtpScheme) ||
164 url.SchemeIs(chrome::kHttpScheme) ||
165 url.SchemeIs(chrome::kHttpsScheme) ||
166 url.SchemeIs(chrome::kExtensionScheme));
167 }
168
169 // Returns true if requests for |url| shall not be reported to extensions.
170 bool HideRequestForURL(const GURL& url) {
171 return IsSensitiveURL(url) || !HasWebRequestScheme(url);
172 }
173
174 bool CanExtensionAccessURL(const Extension* extension, const GURL& url) {
175 // about: URLs are not covered in host permissions, but are allowed anyway.
176 return (url.SchemeIs(chrome::kAboutScheme) ||
177 extension->HasHostPermission(url) ||
178 url.GetOrigin() == extension->url());
179 }
180
181 const char* ResourceTypeToString(ResourceType::Type type) {
182 ResourceType::Type* iter =
183 std::find(kResourceTypeValues, ARRAYEND(kResourceTypeValues), type);
184 if (iter == ARRAYEND(kResourceTypeValues))
185 return "other";
186
187 return kResourceTypeStrings[iter - kResourceTypeValues];
188 }
189
190 bool ParseResourceType(const std::string& type_str,
191 ResourceType::Type* type) {
192 const char** iter =
193 std::find(kResourceTypeStrings, ARRAYEND(kResourceTypeStrings), type_str);
194 if (iter == ARRAYEND(kResourceTypeStrings))
195 return false;
196 *type = kResourceTypeValues[iter - kResourceTypeStrings];
197 return true;
198 }
199
200 void ExtractRequestInfoDetails(net::URLRequest* request,
201 bool* is_main_frame,
202 int64* frame_id,
203 bool* parent_is_main_frame,
204 int64* parent_frame_id,
205 int* tab_id,
206 int* window_id,
207 ResourceType::Type* resource_type) {
208 if (!request->GetUserData(NULL))
209 return;
210
211 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
212 ExtensionTabIdMap::GetInstance()->GetTabAndWindowId(
213 info->GetChildID(), info->GetRouteID(), tab_id, window_id);
214 *frame_id = info->GetFrameID();
215 *is_main_frame = info->IsMainFrame();
216 *parent_frame_id = info->GetParentFrameID();
217 *parent_is_main_frame = info->ParentIsMainFrame();
218
219 // Restrict the resource type to the values we care about.
220 ResourceType::Type* iter =
221 std::find(kResourceTypeValues, ARRAYEND(kResourceTypeValues),
222 info->GetResourceType());
223 *resource_type = (iter != ARRAYEND(kResourceTypeValues)) ?
224 *iter : ResourceType::LAST_TYPE;
225 }
226
227 // Extracts from |request| information for the keys requestId, url, method,
228 // frameId, tabId, type, and timeStamp and writes these into |out| to be passed
229 // on to extensions.
230 void ExtractRequestInfo(net::URLRequest* request, DictionaryValue* out) {
231 bool is_main_frame = false;
232 int64 frame_id = -1;
233 bool parent_is_main_frame = false;
234 int64 parent_frame_id = -1;
235 int frame_id_for_extension = -1;
236 int parent_frame_id_for_extension = -1;
237 int tab_id = -1;
238 int window_id = -1;
239 ResourceType::Type resource_type = ResourceType::LAST_TYPE;
240 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
241 &parent_is_main_frame, &parent_frame_id, &tab_id,
242 &window_id, &resource_type);
243 frame_id_for_extension = GetFrameId(is_main_frame, frame_id);
244 parent_frame_id_for_extension = GetFrameId(parent_is_main_frame,
245 parent_frame_id);
246
247 out->SetString(keys::kRequestIdKey,
248 base::Uint64ToString(request->identifier()));
249 out->SetString(keys::kUrlKey, request->url().spec());
250 out->SetString(keys::kMethodKey, request->method());
251 out->SetInteger(keys::kFrameIdKey, frame_id_for_extension);
252 out->SetInteger(keys::kParentFrameIdKey, parent_frame_id_for_extension);
253 out->SetInteger(keys::kTabIdKey, tab_id);
254 out->SetString(keys::kTypeKey, ResourceTypeToString(resource_type));
255 out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
256 }
257
258 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
259 // true if successful.
260 bool FromHeaderDictionary(const DictionaryValue* header_value,
261 std::string* name,
262 std::string* value) {
263 if (!header_value->GetString(keys::kHeaderNameKey, name))
264 return false;
265
266 // We require either a "value" or a "binaryValue" entry.
267 if (!(header_value->HasKey(keys::kHeaderValueKey) ^
268 header_value->HasKey(keys::kHeaderBinaryValueKey)))
269 return false;
270
271 if (header_value->HasKey(keys::kHeaderValueKey)) {
272 if (!header_value->GetString(keys::kHeaderValueKey, value)) {
273 return false;
274 }
275 } else if (header_value->HasKey(keys::kHeaderBinaryValueKey)) {
276 ListValue* list = NULL;
277 if (!header_value->GetList(keys::kHeaderBinaryValueKey, &list) ||
278 !helpers::CharListToString(list, value)) {
279 return false;
280 }
281 }
282 return true;
283 }
284
285 // Converts the |name|, |value| pair of a http header to a HttpHeaders
286 // dictionary. Ownership is passed to the caller.
287 DictionaryValue* ToHeaderDictionary(const std::string& name,
288 const std::string& value) {
289 DictionaryValue* header = new DictionaryValue();
290 header->SetString(keys::kHeaderNameKey, name);
291 if (IsStringUTF8(value)) {
292 header->SetString(keys::kHeaderValueKey, value);
293 } else {
294 header->Set(keys::kHeaderBinaryValueKey,
295 helpers::StringToCharList(value));
296 }
297 return header;
298 }
299
300 // Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
301 // NULL, the list is empty. Ownership is passed to the caller.
302 ListValue* GetResponseHeadersList(const net::HttpResponseHeaders* headers) {
303 ListValue* headers_value = new ListValue();
304 if (headers) {
305 void* iter = NULL;
306 std::string name;
307 std::string value;
308 while (headers->EnumerateHeaderLines(&iter, &name, &value))
309 headers_value->Append(ToHeaderDictionary(name, value));
310 }
311 return headers_value;
312 }
313
314 ListValue* GetRequestHeadersList(const net::HttpRequestHeaders& headers) {
315 ListValue* headers_value = new ListValue();
316 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext(); )
317 headers_value->Append(ToHeaderDictionary(it.name(), it.value()));
318 return headers_value;
319 }
320
321 // Creates a StringValue with the status line of |headers|. If |headers| is
322 // NULL, an empty string is returned. Ownership is passed to the caller.
323 StringValue* GetStatusLine(net::HttpResponseHeaders* headers) {
324 return new StringValue(headers ? headers->GetStatusLine() : "");
325 }
326
327 void NotifyWebRequestAPIUsed(void* profile_id, const Extension* extension) {
328 Profile* profile = reinterpret_cast<Profile*>(profile_id);
329 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
330 return;
331
332 if (profile->GetExtensionService()->HasUsedWebRequest(extension))
333 return;
334 profile->GetExtensionService()->SetHasUsedWebRequest(extension, true);
335
336 content::BrowserContext* browser_context = profile;
337 for (content::RenderProcessHost::iterator it =
338 content::RenderProcessHost::AllHostsIterator();
339 !it.IsAtEnd(); it.Advance()) {
340 content::RenderProcessHost* host = it.GetCurrentValue();
341 if (host->GetBrowserContext() == browser_context)
342 SendExtensionWebRequestStatusToHost(host);
343 }
344 }
345
346 void ClearCacheOnNavigationOnUI() {
347 WebCacheManager::GetInstance()->ClearCacheOnNavigation();
348 }
349
350 } // namespace
351
352 // Represents a single unique listener to an event, along with whatever filter
353 // parameters and extra_info_spec were specified at the time the listener was
354 // added.
355 struct ExtensionWebRequestEventRouter::EventListener {
356 std::string extension_id;
357 std::string extension_name;
358 std::string sub_event_name;
359 RequestFilter filter;
360 int extra_info_spec;
361 base::WeakPtr<IPC::Message::Sender> ipc_sender;
362 mutable std::set<uint64> blocked_requests;
363
364 // Comparator to work with std::set.
365 bool operator<(const EventListener& that) const {
366 if (extension_id < that.extension_id)
367 return true;
368 if (extension_id == that.extension_id &&
369 sub_event_name < that.sub_event_name)
370 return true;
371 return false;
372 }
373
374 EventListener() : extra_info_spec(0) {}
375 };
376
377 // Contains info about requests that are blocked waiting for a response from
378 // an extension.
379 struct ExtensionWebRequestEventRouter::BlockedRequest {
380 // The request that is being blocked.
381 net::URLRequest* request;
382
383 // The event that we're currently blocked on.
384 EventTypes event;
385
386 // The number of event handlers that we are awaiting a response from.
387 int num_handlers_blocking;
388
389 // Pointer to NetLog to report significant changes to the request for
390 // debugging.
391 const net::BoundNetLog* net_log;
392
393 // The callback to call when we get a response from all event handlers.
394 net::CompletionCallback callback;
395
396 // If non-empty, this contains the new URL that the request will redirect to.
397 // Only valid for OnBeforeRequest.
398 GURL* new_url;
399
400 // The request headers that will be issued along with this request. Only valid
401 // for OnBeforeSendHeaders.
402 net::HttpRequestHeaders* request_headers;
403
404 // The response headers that were received from the server. Only valid for
405 // OnHeadersReceived.
406 scoped_refptr<net::HttpResponseHeaders> original_response_headers;
407
408 // Location where to override response headers. Only valid for
409 // OnHeadersReceived.
410 scoped_refptr<net::HttpResponseHeaders>* override_response_headers;
411
412 // If non-empty, this contains the auth credentials that may be filled in.
413 // Only valid for OnAuthRequired.
414 net::AuthCredentials* auth_credentials;
415
416 // The callback to invoke for auth. If |auth_callback.is_null()| is false,
417 // |callback| must be NULL.
418 // Only valid for OnAuthRequired.
419 net::NetworkDelegate::AuthCallback auth_callback;
420
421 // Time the request was paused. Used for logging purposes.
422 base::Time blocking_time;
423
424 // Changes requested by extensions.
425 helpers::EventResponseDeltas response_deltas;
426
427 BlockedRequest()
428 : request(NULL),
429 event(kInvalidEvent),
430 num_handlers_blocking(0),
431 net_log(NULL),
432 new_url(NULL),
433 request_headers(NULL),
434 override_response_headers(NULL),
435 auth_credentials(NULL) {}
436 };
437
438 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
439 const DictionaryValue& value, std::string* error) {
440 if (!value.HasKey("urls"))
441 return false;
442
443 for (DictionaryValue::key_iterator key = value.begin_keys();
444 key != value.end_keys(); ++key) {
445 if (*key == "urls") {
446 ListValue* urls_value = NULL;
447 if (!value.GetList("urls", &urls_value))
448 return false;
449 for (size_t i = 0; i < urls_value->GetSize(); ++i) {
450 std::string url;
451 URLPattern pattern(
452 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
453 URLPattern::SCHEME_FTP | URLPattern::SCHEME_FILE |
454 URLPattern::SCHEME_EXTENSION);
455 if (!urls_value->GetString(i, &url) ||
456 pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
457 *error = ExtensionErrorUtils::FormatErrorMessage(
458 keys::kInvalidRequestFilterUrl, url);
459 return false;
460 }
461 urls.AddPattern(pattern);
462 }
463 } else if (*key == "types") {
464 ListValue* types_value = NULL;
465 if (!value.GetList("types", &types_value))
466 return false;
467 for (size_t i = 0; i < types_value->GetSize(); ++i) {
468 std::string type_str;
469 ResourceType::Type type;
470 if (!types_value->GetString(i, &type_str) ||
471 !ParseResourceType(type_str, &type))
472 return false;
473 types.push_back(type);
474 }
475 } else if (*key == "tabId") {
476 if (!value.GetInteger("tabId", &tab_id))
477 return false;
478 } else if (*key == "windowId") {
479 if (!value.GetInteger("windowId", &window_id))
480 return false;
481 } else {
482 return false;
483 }
484 }
485 return true;
486 }
487
488 // static
489 bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
490 const ListValue& value, int* extra_info_spec) {
491 *extra_info_spec = 0;
492 for (size_t i = 0; i < value.GetSize(); ++i) {
493 std::string str;
494 if (!value.GetString(i, &str))
495 return false;
496
497 if (str == "requestHeaders")
498 *extra_info_spec |= REQUEST_HEADERS;
499 else if (str == "responseHeaders")
500 *extra_info_spec |= RESPONSE_HEADERS;
501 else if (str == "blocking")
502 *extra_info_spec |= BLOCKING;
503 else if (str == "asyncBlocking")
504 *extra_info_spec |= ASYNC_BLOCKING;
505 else
506 return false;
507
508 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
509 if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
510 return false;
511 }
512 return true;
513 }
514
515
516 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
517 const std::string& extension_id, const base::Time& extension_install_time)
518 : extension_id(extension_id),
519 extension_install_time(extension_install_time),
520 cancel(false) {
521 }
522
523 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
524 }
525
526
527 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
528 : tab_id(-1), window_id(-1) {
529 }
530
531 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
532 }
533
534 //
535 // ExtensionWebRequestEventRouter
536 //
537
538 // static
539 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
540 return Singleton<ExtensionWebRequestEventRouter>::get();
541 }
542
543 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
544 : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
545 }
546
547 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
548 }
549
550 int ExtensionWebRequestEventRouter::OnBeforeRequest(
551 void* profile,
552 ExtensionInfoMap* extension_info_map,
553 net::URLRequest* request,
554 const net::CompletionCallback& callback,
555 GURL* new_url) {
556 // We hide events from the system context as well as sensitive requests.
557 if (!profile || HideRequestForURL(request->url()))
558 return net::OK;
559
560 if (IsPageLoad(request))
561 NotifyPageLoad();
562
563 request_time_tracker_->LogRequestStartTime(request->identifier(),
564 base::Time::Now(),
565 request->url(),
566 profile);
567
568 int extra_info_spec = 0;
569 std::vector<const EventListener*> listeners =
570 GetMatchingListeners(profile, extension_info_map, keys::kOnBeforeRequest,
571 request, &extra_info_spec);
572 if (listeners.empty())
573 return net::OK;
574
575 if (GetAndSetSignaled(request->identifier(), kOnBeforeRequest))
576 return net::OK;
577
578 ListValue args;
579 DictionaryValue* dict = new DictionaryValue();
580 ExtractRequestInfo(request, dict);
581 args.Append(dict);
582
583 if (DispatchEvent(profile, request, listeners, args)) {
584 blocked_requests_[request->identifier()].event = kOnBeforeRequest;
585 blocked_requests_[request->identifier()].callback = callback;
586 blocked_requests_[request->identifier()].new_url = new_url;
587 blocked_requests_[request->identifier()].net_log = &request->net_log();
588 return net::ERR_IO_PENDING;
589 }
590 return net::OK;
591 }
592
593 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
594 void* profile,
595 ExtensionInfoMap* extension_info_map,
596 net::URLRequest* request,
597 const net::CompletionCallback& callback,
598 net::HttpRequestHeaders* headers) {
599 // We hide events from the system context as well as sensitive requests.
600 if (!profile || HideRequestForURL(request->url()))
601 return net::OK;
602
603 if (GetAndSetSignaled(request->identifier(), kOnBeforeSendHeaders))
604 return net::OK;
605
606 int extra_info_spec = 0;
607 std::vector<const EventListener*> listeners =
608 GetMatchingListeners(profile, extension_info_map,
609 keys::kOnBeforeSendHeaders, request,
610 &extra_info_spec);
611 if (listeners.empty())
612 return net::OK;
613
614 ListValue args;
615 DictionaryValue* dict = new DictionaryValue();
616 ExtractRequestInfo(request, dict);
617 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
618 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(*headers));
619 args.Append(dict);
620
621 if (DispatchEvent(profile, request, listeners, args)) {
622 blocked_requests_[request->identifier()].event = kOnBeforeSendHeaders;
623 blocked_requests_[request->identifier()].callback = callback;
624 blocked_requests_[request->identifier()].request_headers = headers;
625 blocked_requests_[request->identifier()].net_log = &request->net_log();
626 return net::ERR_IO_PENDING;
627 }
628 return net::OK;
629 }
630
631 void ExtensionWebRequestEventRouter::OnSendHeaders(
632 void* profile,
633 ExtensionInfoMap* extension_info_map,
634 net::URLRequest* request,
635 const net::HttpRequestHeaders& headers) {
636 // We hide events from the system context as well as sensitive requests.
637 if (!profile || HideRequestForURL(request->url()))
638 return;
639
640 if (GetAndSetSignaled(request->identifier(), kOnSendHeaders))
641 return;
642
643 ClearSignaled(request->identifier(), kOnBeforeRedirect);
644
645 int extra_info_spec = 0;
646 std::vector<const EventListener*> listeners =
647 GetMatchingListeners(profile, extension_info_map,
648 keys::kOnSendHeaders, request, &extra_info_spec);
649 if (listeners.empty())
650 return;
651
652 ListValue args;
653 DictionaryValue* dict = new DictionaryValue();
654 ExtractRequestInfo(request, dict);
655 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
656 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
657 args.Append(dict);
658
659 DispatchEvent(profile, request, listeners, args);
660 }
661
662 int ExtensionWebRequestEventRouter::OnHeadersReceived(
663 void* profile,
664 ExtensionInfoMap* extension_info_map,
665 net::URLRequest* request,
666 const net::CompletionCallback& callback,
667 net::HttpResponseHeaders* original_response_headers,
668 scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
669 // We hide events from the system context as well as sensitive requests.
670 if (!profile || HideRequestForURL(request->url()))
671 return net::OK;
672
673 int extra_info_spec = 0;
674 std::vector<const EventListener*> listeners =
675 GetMatchingListeners(profile, extension_info_map,
676 keys::kOnHeadersReceived, request,
677 &extra_info_spec);
678
679 if (listeners.empty())
680 return net::OK;
681
682 if (GetAndSetSignaled(request->identifier(), kOnHeadersReceived))
683 return net::OK;
684
685 ListValue args;
686 DictionaryValue* dict = new DictionaryValue();
687 ExtractRequestInfo(request, dict);
688 dict->SetString(keys::kStatusLineKey,
689 original_response_headers->GetStatusLine());
690 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
691 dict->Set(keys::kResponseHeadersKey,
692 GetResponseHeadersList(original_response_headers));
693 }
694 args.Append(dict);
695
696 if (DispatchEvent(profile, request, listeners, args)) {
697 blocked_requests_[request->identifier()].event = kOnHeadersReceived;
698 blocked_requests_[request->identifier()].callback = callback;
699 blocked_requests_[request->identifier()].net_log = &request->net_log();
700 blocked_requests_[request->identifier()].override_response_headers =
701 override_response_headers;
702 blocked_requests_[request->identifier()].original_response_headers =
703 original_response_headers;
704 return net::ERR_IO_PENDING;
705 }
706 return net::OK;
707 }
708
709 net::NetworkDelegate::AuthRequiredResponse
710 ExtensionWebRequestEventRouter::OnAuthRequired(
711 void* profile,
712 ExtensionInfoMap* extension_info_map,
713 net::URLRequest* request,
714 const net::AuthChallengeInfo& auth_info,
715 const net::NetworkDelegate::AuthCallback& callback,
716 net::AuthCredentials* credentials) {
717 // No profile means that this is for authentication challenges in the
718 // system context. Skip in that case. Also skip sensitive requests.
719 if (!profile || HideRequestForURL(request->url()))
720 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
721
722 int extra_info_spec = 0;
723 std::vector<const EventListener*> listeners =
724 GetMatchingListeners(profile, extension_info_map,
725 keys::kOnAuthRequired, request, &extra_info_spec);
726 if (listeners.empty())
727 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
728
729 ListValue args;
730 DictionaryValue* dict = new DictionaryValue();
731 ExtractRequestInfo(request, dict);
732 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
733 if (!auth_info.scheme.empty())
734 dict->SetString(keys::kSchemeKey, auth_info.scheme);
735 if (!auth_info.realm.empty())
736 dict->SetString(keys::kRealmKey, auth_info.realm);
737 DictionaryValue* challenger = new DictionaryValue();
738 challenger->SetString(keys::kHostKey, auth_info.challenger.host());
739 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
740 dict->Set(keys::kChallengerKey, challenger);
741 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
742 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
743 dict->Set(keys::kResponseHeadersKey,
744 GetResponseHeadersList(request->response_headers()));
745 }
746 args.Append(dict);
747
748 if (DispatchEvent(profile, request, listeners, args)) {
749 blocked_requests_[request->identifier()].event = kOnAuthRequired;
750 blocked_requests_[request->identifier()].auth_callback = callback;
751 blocked_requests_[request->identifier()].auth_credentials = credentials;
752 blocked_requests_[request->identifier()].net_log = &request->net_log();
753 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING;
754 }
755 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
756 }
757
758 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
759 void* profile,
760 ExtensionInfoMap* extension_info_map,
761 net::URLRequest* request,
762 const GURL& new_location) {
763 // We hide events from the system context as well as sensitive requests.
764 if (!profile || HideRequestForURL(request->url()))
765 return;
766
767 if (GetAndSetSignaled(request->identifier(), kOnBeforeRedirect))
768 return;
769
770 ClearSignaled(request->identifier(), kOnBeforeRequest);
771 ClearSignaled(request->identifier(), kOnBeforeSendHeaders);
772 ClearSignaled(request->identifier(), kOnSendHeaders);
773 ClearSignaled(request->identifier(), kOnHeadersReceived);
774
775 int extra_info_spec = 0;
776 std::vector<const EventListener*> listeners =
777 GetMatchingListeners(profile, extension_info_map,
778 keys::kOnBeforeRedirect, request, &extra_info_spec);
779 if (listeners.empty())
780 return;
781
782 int http_status_code = request->GetResponseCode();
783
784 std::string response_ip = request->GetSocketAddress().host();
785
786 ListValue args;
787 DictionaryValue* dict = new DictionaryValue();
788 ExtractRequestInfo(request, dict);
789 dict->SetString(keys::kRedirectUrlKey, new_location.spec());
790 dict->SetInteger(keys::kStatusCodeKey, http_status_code);
791 if (!response_ip.empty())
792 dict->SetString(keys::kIpKey, response_ip);
793 dict->SetBoolean(keys::kFromCache, request->was_cached());
794 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
795 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
796 dict->Set(keys::kResponseHeadersKey,
797 GetResponseHeadersList(request->response_headers()));
798 }
799 args.Append(dict);
800
801 DispatchEvent(profile, request, listeners, args);
802 }
803
804 void ExtensionWebRequestEventRouter::OnResponseStarted(
805 void* profile,
806 ExtensionInfoMap* extension_info_map,
807 net::URLRequest* request) {
808 // We hide events from the system context as well as sensitive requests.
809 if (!profile || HideRequestForURL(request->url()))
810 return;
811
812 // OnResponseStarted is even triggered, when the request was cancelled.
813 if (request->status().status() != net::URLRequestStatus::SUCCESS)
814 return;
815
816 int extra_info_spec = 0;
817 std::vector<const EventListener*> listeners =
818 GetMatchingListeners(profile, extension_info_map,
819 keys::kOnResponseStarted, request, &extra_info_spec);
820 if (listeners.empty())
821 return;
822
823 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
824 int response_code = 200;
825 if (request->response_headers())
826 response_code = request->response_headers()->response_code();
827
828 std::string response_ip = request->GetSocketAddress().host();
829
830 ListValue args;
831 DictionaryValue* dict = new DictionaryValue();
832 ExtractRequestInfo(request, dict);
833 if (!response_ip.empty())
834 dict->SetString(keys::kIpKey, response_ip);
835 dict->SetBoolean(keys::kFromCache, request->was_cached());
836 dict->SetInteger(keys::kStatusCodeKey, response_code);
837 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
838 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
839 dict->Set(keys::kResponseHeadersKey,
840 GetResponseHeadersList(request->response_headers()));
841 }
842 args.Append(dict);
843
844 DispatchEvent(profile, request, listeners, args);
845 }
846
847 void ExtensionWebRequestEventRouter::OnCompleted(
848 void* profile,
849 ExtensionInfoMap* extension_info_map,
850 net::URLRequest* request) {
851 // We hide events from the system context as well as sensitive requests.
852 if (!profile || HideRequestForURL(request->url()))
853 return;
854
855 request_time_tracker_->LogRequestEndTime(request->identifier(),
856 base::Time::Now());
857
858 DCHECK(request->status().status() == net::URLRequestStatus::SUCCESS);
859
860 DCHECK(!GetAndSetSignaled(request->identifier(), kOnCompleted));
861
862 ClearPendingCallbacks(request);
863
864 int extra_info_spec = 0;
865 std::vector<const EventListener*> listeners =
866 GetMatchingListeners(profile, extension_info_map,
867 keys::kOnCompleted, request, &extra_info_spec);
868 if (listeners.empty())
869 return;
870
871 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
872 int response_code = 200;
873 if (request->response_headers())
874 response_code = request->response_headers()->response_code();
875
876 std::string response_ip = request->GetSocketAddress().host();
877
878 ListValue args;
879 DictionaryValue* dict = new DictionaryValue();
880 ExtractRequestInfo(request, dict);
881 dict->SetInteger(keys::kStatusCodeKey, response_code);
882 if (!response_ip.empty())
883 dict->SetString(keys::kIpKey, response_ip);
884 dict->SetBoolean(keys::kFromCache, request->was_cached());
885 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
886 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
887 dict->Set(keys::kResponseHeadersKey,
888 GetResponseHeadersList(request->response_headers()));
889 }
890 args.Append(dict);
891
892 DispatchEvent(profile, request, listeners, args);
893 }
894
895 void ExtensionWebRequestEventRouter::OnErrorOccurred(
896 void* profile,
897 ExtensionInfoMap* extension_info_map,
898 net::URLRequest* request,
899 bool started) {
900 // We hide events from the system context as well as sensitive requests.
901 if (!profile || HideRequestForURL(request->url()))
902 return;
903
904 request_time_tracker_->LogRequestEndTime(request->identifier(),
905 base::Time::Now());
906
907 DCHECK(request->status().status() == net::URLRequestStatus::FAILED ||
908 request->status().status() == net::URLRequestStatus::CANCELED);
909
910 DCHECK(!GetAndSetSignaled(request->identifier(), kOnErrorOccurred));
911
912 ClearPendingCallbacks(request);
913
914 int extra_info_spec = 0;
915 std::vector<const EventListener*> listeners =
916 GetMatchingListeners(profile, extension_info_map,
917 keys::kOnErrorOccurred, request, &extra_info_spec);
918 if (listeners.empty())
919 return;
920
921 ListValue args;
922 DictionaryValue* dict = new DictionaryValue();
923 ExtractRequestInfo(request, dict);
924 if (started) {
925 std::string response_ip = request->GetSocketAddress().host();
926 if (!response_ip.empty())
927 dict->SetString(keys::kIpKey, response_ip);
928 }
929 dict->SetBoolean(keys::kFromCache, request->was_cached());
930 dict->SetString(keys::kErrorKey,
931 net::ErrorToString(request->status().error()));
932 args.Append(dict);
933
934 DispatchEvent(profile, request, listeners, args);
935 }
936
937 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
938 void* profile, net::URLRequest* request) {
939 ClearPendingCallbacks(request);
940
941 signaled_requests_.erase(request->identifier());
942
943 request_time_tracker_->LogRequestEndTime(request->identifier(),
944 base::Time::Now());
945 }
946
947 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
948 net::URLRequest* request) {
949 blocked_requests_.erase(request->identifier());
950 }
951
952 bool ExtensionWebRequestEventRouter::DispatchEvent(
953 void* profile,
954 net::URLRequest* request,
955 const std::vector<const EventListener*>& listeners,
956 const ListValue& args) {
957 std::string json_args;
958
959 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
960 // pairs into a single message sent to a list of sub_event_names.
961 int num_handlers_blocking = 0;
962 for (std::vector<const EventListener*>::const_iterator it = listeners.begin();
963 it != listeners.end(); ++it) {
964 // Filter out the optional keys that this listener didn't request.
965 scoped_ptr<ListValue> args_filtered(args.DeepCopy());
966 DictionaryValue* dict = NULL;
967 CHECK(args_filtered->GetDictionary(0, &dict) && dict);
968 if (!((*it)->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS))
969 dict->Remove(keys::kRequestHeadersKey, NULL);
970 if (!((*it)->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS))
971 dict->Remove(keys::kResponseHeadersKey, NULL);
972
973 base::JSONWriter::Write(args_filtered.get(), &json_args);
974
975 ExtensionEventRouter::DispatchEvent(
976 (*it)->ipc_sender.get(), (*it)->extension_id, (*it)->sub_event_name,
977 json_args, GURL(), ExtensionEventRouter::USER_GESTURE_UNKNOWN);
978 if ((*it)->extra_info_spec &
979 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
980 (*it)->blocked_requests.insert(request->identifier());
981 ++num_handlers_blocking;
982
983 request->SetLoadStateParam(
984 l10n_util::GetStringFUTF16(IDS_LOAD_STATE_PARAMETER_EXTENSION,
985 UTF8ToUTF16((*it)->extension_name)));
986 }
987 }
988
989 if (num_handlers_blocking > 0) {
990 CHECK(blocked_requests_.find(request->identifier()) ==
991 blocked_requests_.end());
992 blocked_requests_[request->identifier()].request = request;
993 blocked_requests_[request->identifier()].num_handlers_blocking =
994 num_handlers_blocking;
995 blocked_requests_[request->identifier()].blocking_time = base::Time::Now();
996
997 return true;
998 }
999
1000 return false;
1001 }
1002
1003 void ExtensionWebRequestEventRouter::OnEventHandled(
1004 void* profile,
1005 const std::string& extension_id,
1006 const std::string& event_name,
1007 const std::string& sub_event_name,
1008 uint64 request_id,
1009 EventResponse* response) {
1010 EventListener listener;
1011 listener.extension_id = extension_id;
1012 listener.sub_event_name = sub_event_name;
1013
1014 // The listener may have been removed (e.g. due to the process going away)
1015 // before we got here.
1016 std::set<EventListener>::iterator found =
1017 listeners_[profile][event_name].find(listener);
1018 if (found != listeners_[profile][event_name].end())
1019 found->blocked_requests.erase(request_id);
1020
1021 DecrementBlockCount(profile, extension_id, event_name, request_id, response);
1022 }
1023
1024 void ExtensionWebRequestEventRouter::AddEventListener(
1025 void* profile,
1026 const std::string& extension_id,
1027 const std::string& extension_name,
1028 const std::string& event_name,
1029 const std::string& sub_event_name,
1030 const RequestFilter& filter,
1031 int extra_info_spec,
1032 base::WeakPtr<IPC::Message::Sender> ipc_sender) {
1033 if (!IsWebRequestEvent(event_name))
1034 return;
1035
1036 EventListener listener;
1037 listener.extension_id = extension_id;
1038 listener.extension_name = extension_name;
1039 listener.sub_event_name = sub_event_name;
1040 listener.filter = filter;
1041 listener.extra_info_spec = extra_info_spec;
1042 listener.ipc_sender = ipc_sender;
1043
1044 CHECK_EQ(listeners_[profile][event_name].count(listener), 0u) <<
1045 "extension=" << extension_id << " event=" << event_name;
1046 listeners_[profile][event_name].insert(listener);
1047 }
1048
1049 void ExtensionWebRequestEventRouter::RemoveEventListener(
1050 void* profile,
1051 const std::string& extension_id,
1052 const std::string& sub_event_name) {
1053 size_t slash_sep = sub_event_name.find('/');
1054 std::string event_name = sub_event_name.substr(0, slash_sep);
1055
1056 if (!IsWebRequestEvent(event_name))
1057 return;
1058
1059 EventListener listener;
1060 listener.extension_id = extension_id;
1061 listener.sub_event_name = sub_event_name;
1062
1063 // It's possible for AddEventListener to fail asynchronously. In that case,
1064 // the renderer believes the listener exists, while the browser does not.
1065 // Ignore a RemoveEventListener in that case.
1066 std::set<EventListener>::iterator found =
1067 listeners_[profile][event_name].find(listener);
1068 if (found == listeners_[profile][event_name].end())
1069 return;
1070
1071 CHECK_EQ(listeners_[profile][event_name].count(listener), 1u) <<
1072 "extension=" << extension_id << " event=" << event_name;
1073
1074 // Unblock any request that this event listener may have been blocking.
1075 for (std::set<uint64>::iterator it = found->blocked_requests.begin();
1076 it != found->blocked_requests.end(); ++it) {
1077 DecrementBlockCount(profile, extension_id, event_name, *it, NULL);
1078 }
1079
1080 listeners_[profile][event_name].erase(listener);
1081
1082 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1083 base::Bind(&ClearCacheOnNavigationOnUI));
1084 }
1085
1086 void ExtensionWebRequestEventRouter::OnOTRProfileCreated(
1087 void* original_profile, void* otr_profile) {
1088 cross_profile_map_[original_profile] = otr_profile;
1089 cross_profile_map_[otr_profile] = original_profile;
1090 }
1091
1092 void ExtensionWebRequestEventRouter::OnOTRProfileDestroyed(
1093 void* original_profile, void* otr_profile) {
1094 cross_profile_map_.erase(otr_profile);
1095 cross_profile_map_.erase(original_profile);
1096 }
1097
1098 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1099 const base::Closure& callback) {
1100 callbacks_for_page_load_.push_back(callback);
1101 }
1102
1103 bool ExtensionWebRequestEventRouter::IsPageLoad(
1104 net::URLRequest* request) const {
1105 bool is_main_frame = false;
1106 int64 frame_id = -1;
1107 bool parent_is_main_frame = false;
1108 int64 parent_frame_id = -1;
1109 int tab_id = -1;
1110 int window_id = -1;
1111 ResourceType::Type resource_type = ResourceType::LAST_TYPE;
1112
1113 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1114 &parent_is_main_frame, &parent_frame_id,
1115 &tab_id, &window_id, &resource_type);
1116
1117 return resource_type == ResourceType::MAIN_FRAME;
1118 }
1119
1120 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1121 for (CallbacksForPageLoad::const_iterator i =
1122 callbacks_for_page_load_.begin();
1123 i != callbacks_for_page_load_.end(); ++i) {
1124 i->Run();
1125 }
1126 callbacks_for_page_load_.clear();
1127 }
1128
1129 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1130 void* profile,
1131 ExtensionInfoMap* extension_info_map,
1132 bool crosses_incognito,
1133 const std::string& event_name,
1134 const GURL& url,
1135 int tab_id,
1136 int window_id,
1137 ResourceType::Type resource_type,
1138 bool is_request_from_extension,
1139 int* extra_info_spec,
1140 std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
1141 matching_listeners) {
1142 std::set<EventListener>& listeners = listeners_[profile][event_name];
1143 for (std::set<EventListener>::iterator it = listeners.begin();
1144 it != listeners.end(); ++it) {
1145 if (!it->ipc_sender.get()) {
1146 // The IPC sender has been deleted. This listener will be removed soon
1147 // via a call to RemoveEventListener. For now, just skip it.
1148 continue;
1149 }
1150
1151 if (!it->filter.urls.is_empty() && !it->filter.urls.MatchesURL(url))
1152 continue;
1153 if (it->filter.tab_id != -1 && tab_id != it->filter.tab_id)
1154 continue;
1155 if (it->filter.window_id != -1 && window_id != it->filter.window_id)
1156 continue;
1157 if (!it->filter.types.empty() &&
1158 std::find(it->filter.types.begin(), it->filter.types.end(),
1159 resource_type) == it->filter.types.end())
1160 continue;
1161
1162 // extension_info_map can be NULL if this is a system-level request.
1163 if (extension_info_map) {
1164 const Extension* extension =
1165 extension_info_map->extensions().GetByID(it->extension_id);
1166
1167 // Check if this event crosses incognito boundaries when it shouldn't.
1168 if (!extension ||
1169 (crosses_incognito &&
1170 !extension_info_map->CanCrossIncognito(extension)))
1171 continue;
1172
1173 bool blocking_listener =
1174 (it->extra_info_spec &
1175 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
1176
1177 // We do not want to notify extensions about XHR requests that are
1178 // triggered by themselves. This is a workaround to prevent deadlocks
1179 // in case of synchronous XHR requests that block the extension renderer
1180 // and therefore prevent the extension from processing the request
1181 // handler. This is only a problem for blocking listeners.
1182 // http://crbug.com/105656
1183 bool possibly_synchronous_xhr_from_extension =
1184 is_request_from_extension && resource_type == ResourceType::XHR;
1185
1186 // Only send webRequest events for URLs the extension has access to.
1187 if (!CanExtensionAccessURL(extension, url) ||
1188 (blocking_listener && possibly_synchronous_xhr_from_extension)) {
1189 continue;
1190 }
1191 }
1192
1193 matching_listeners->push_back(&(*it));
1194 *extra_info_spec |= it->extra_info_spec;
1195 }
1196 }
1197
1198 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1199 ExtensionWebRequestEventRouter::GetMatchingListeners(
1200 void* profile,
1201 ExtensionInfoMap* extension_info_map,
1202 const std::string& event_name,
1203 net::URLRequest* request,
1204 int* extra_info_spec) {
1205 // TODO(mpcomplete): handle profile == NULL (should collect all listeners).
1206 *extra_info_spec = 0;
1207
1208 bool is_main_frame = false;
1209 int64 frame_id = -1;
1210 bool parent_is_main_frame = false;
1211 int64 parent_frame_id = -1;
1212 int tab_id = -1;
1213 int window_id = -1;
1214 ResourceType::Type resource_type = ResourceType::LAST_TYPE;
1215 const GURL& url = request->url();
1216
1217 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1218 &parent_is_main_frame, &parent_frame_id,
1219 &tab_id, &window_id, &resource_type);
1220
1221 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1222 matching_listeners;
1223
1224 bool is_request_from_extension =
1225 IsRequestFromExtension(request, extension_info_map);
1226
1227 GetMatchingListenersImpl(
1228 profile, extension_info_map, false, event_name, url,
1229 tab_id, window_id, resource_type, is_request_from_extension,
1230 extra_info_spec, &matching_listeners);
1231 CrossProfileMap::const_iterator cross_profile =
1232 cross_profile_map_.find(profile);
1233 if (cross_profile != cross_profile_map_.end()) {
1234 GetMatchingListenersImpl(
1235 cross_profile->second, extension_info_map, true, event_name, url,
1236 tab_id, window_id, resource_type, is_request_from_extension,
1237 extra_info_spec, &matching_listeners);
1238 }
1239
1240 return matching_listeners;
1241 }
1242
1243 namespace {
1244
1245 helpers::EventResponseDelta* CalculateDelta(
1246 ExtensionWebRequestEventRouter::BlockedRequest* blocked_request,
1247 ExtensionWebRequestEventRouter::EventResponse* response) {
1248 switch (blocked_request->event) {
1249 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
1250 return helpers::CalculateOnBeforeRequestDelta(
1251 response->extension_id, response->extension_install_time,
1252 response->cancel, response->new_url);
1253 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders: {
1254 net::HttpRequestHeaders* old_headers = blocked_request->request_headers;
1255 net::HttpRequestHeaders* new_headers = response->request_headers.get();
1256 return helpers::CalculateOnBeforeSendHeadersDelta(
1257 response->extension_id, response->extension_install_time,
1258 response->cancel, old_headers, new_headers);
1259 }
1260 case ExtensionWebRequestEventRouter::kOnHeadersReceived: {
1261 net::HttpResponseHeaders* old_headers =
1262 blocked_request->original_response_headers.get();
1263 helpers::ResponseHeaders* new_headers =
1264 response->response_headers.get();
1265 return helpers::CalculateOnHeadersReceivedDelta(
1266 response->extension_id, response->extension_install_time,
1267 response->cancel, old_headers, new_headers);
1268 }
1269 case ExtensionWebRequestEventRouter::kOnAuthRequired:
1270 return helpers::CalculateOnAuthRequiredDelta(
1271 response->extension_id, response->extension_install_time,
1272 response->cancel, &response->auth_credentials);
1273 default:
1274 NOTREACHED();
1275 break;
1276 }
1277 return NULL;
1278 }
1279
1280 } // namespace
1281
1282 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1283 void* profile,
1284 const std::string& extension_id,
1285 const std::string& event_name,
1286 uint64 request_id,
1287 EventResponse* response) {
1288 scoped_ptr<EventResponse> response_scoped(response);
1289
1290 // It's possible that this request was deleted, or cancelled by a previous
1291 // event handler. If so, ignore this response.
1292 if (blocked_requests_.find(request_id) == blocked_requests_.end())
1293 return;
1294
1295 BlockedRequest& blocked_request = blocked_requests_[request_id];
1296 int num_handlers_blocking = --blocked_request.num_handlers_blocking;
1297 CHECK_GE(num_handlers_blocking, 0);
1298
1299 if (response) {
1300 blocked_request.response_deltas.push_back(
1301 linked_ptr<helpers::EventResponseDelta>(
1302 CalculateDelta(&blocked_request, response)));
1303 }
1304
1305 base::TimeDelta block_time =
1306 base::Time::Now() - blocked_request.blocking_time;
1307 request_time_tracker_->IncrementExtensionBlockTime(
1308 extension_id, request_id, block_time);
1309
1310 if (num_handlers_blocking == 0) {
1311 request_time_tracker_->IncrementTotalBlockTime(request_id, block_time);
1312
1313 bool credentials_set = false;
1314
1315 helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1316 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
1317 std::set<std::string> conflicting_extensions;
1318 helpers::EventLogEntries event_log_entries;
1319
1320 bool canceled = false;
1321 helpers::MergeCancelOfResponses(
1322 blocked_request.response_deltas,
1323 &canceled,
1324 &event_log_entries);
1325
1326 if (blocked_request.event == kOnBeforeRequest) {
1327 CHECK(!blocked_request.callback.is_null());
1328 helpers::MergeOnBeforeRequestResponses(
1329 blocked_request.response_deltas,
1330 blocked_request.new_url,
1331 &conflicting_extensions,
1332 &event_log_entries);
1333 } else if (blocked_request.event == kOnBeforeSendHeaders) {
1334 CHECK(!blocked_request.callback.is_null());
1335 helpers::MergeOnBeforeSendHeadersResponses(
1336 blocked_request.response_deltas,
1337 blocked_request.request_headers,
1338 &conflicting_extensions,
1339 &event_log_entries);
1340 } else if (blocked_request.event == kOnHeadersReceived) {
1341 CHECK(!blocked_request.callback.is_null());
1342 helpers::MergeOnHeadersReceivedResponses(
1343 blocked_request.response_deltas,
1344 blocked_request.original_response_headers.get(),
1345 blocked_request.override_response_headers,
1346 &conflicting_extensions,
1347 &event_log_entries);
1348 } else if (blocked_request.event == kOnAuthRequired) {
1349 CHECK(blocked_request.callback.is_null());
1350 CHECK(!blocked_request.auth_callback.is_null());
1351 credentials_set = helpers::MergeOnAuthRequiredResponses(
1352 blocked_request.response_deltas,
1353 blocked_request.auth_credentials,
1354 &conflicting_extensions,
1355 &event_log_entries);
1356 } else {
1357 NOTREACHED();
1358 }
1359
1360 for (helpers::EventLogEntries::const_iterator i =
1361 event_log_entries.begin();
1362 i != event_log_entries.end(); ++i) {
1363 blocked_request.net_log->AddEvent(i->event_type, i->params);
1364 }
1365 if (!conflicting_extensions.empty()) {
1366 BrowserThread::PostTask(
1367 BrowserThread::UI,
1368 FROM_HERE,
1369 base::Bind(&ExtensionWarningSet::NotifyWarningsOnUI,
1370 profile,
1371 conflicting_extensions,
1372 ExtensionWarningSet::kNetworkConflict));
1373 }
1374
1375 if (canceled) {
1376 request_time_tracker_->SetRequestCanceled(request_id);
1377 } else if (blocked_request.new_url &&
1378 !blocked_request.new_url->is_empty()) {
1379 request_time_tracker_->SetRequestRedirected(request_id);
1380 }
1381
1382 if (!blocked_request.callback.is_null()) {
1383 // This triggers onErrorOccurred.
1384 int rv = canceled ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
1385 net::CompletionCallback callback = blocked_request.callback;
1386 // Ensure that request is removed before callback because the callback
1387 // might trigger the next event.
1388 blocked_requests_.erase(request_id);
1389 callback.Run(rv);
1390 } else if (!blocked_request.auth_callback.is_null()) {
1391 net::NetworkDelegate::AuthRequiredResponse response =
1392 net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1393 if (canceled) {
1394 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
1395 } else if (credentials_set) {
1396 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH;
1397 }
1398 net::NetworkDelegate::AuthCallback callback =
1399 blocked_request.auth_callback;
1400 blocked_requests_.erase(request_id);
1401 callback.Run(response);
1402 } else {
1403 blocked_requests_.erase(request_id);
1404 }
1405 } else {
1406 // Update the URLRequest to indicate it is now blocked on a different
1407 // extension.
1408 std::set<EventListener>& listeners = listeners_[profile][event_name];
1409
1410 for (std::set<EventListener>::iterator it = listeners.begin();
1411 it != listeners.end(); ++it) {
1412 if (it->blocked_requests.count(request_id)) {
1413 blocked_request.request->SetLoadStateParam(
1414 l10n_util::GetStringFUTF16(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1415 UTF8ToUTF16(it->extension_name)));
1416 break;
1417 }
1418 }
1419 }
1420 }
1421
1422 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64 request_id,
1423 EventTypes event_type) {
1424 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
1425 if (iter == signaled_requests_.end()) {
1426 signaled_requests_[request_id] = event_type;
1427 return false;
1428 }
1429 bool was_signaled_before = (iter->second & event_type) != 0;
1430 iter->second |= event_type;
1431 return was_signaled_before;
1432 }
1433
1434 void ExtensionWebRequestEventRouter::ClearSignaled(uint64 request_id,
1435 EventTypes event_type) {
1436 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
1437 if (iter == signaled_requests_.end())
1438 return;
1439 iter->second &= ~event_type;
1440 }
1441
1442 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChanged.
1443 //
1444 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
1445 // of WebKit at the time of the next page load (top level navigation event).
1446 // This quota heuristic is intended to limit the number of times the cache is
1447 // cleared by an extension.
1448 //
1449 // As we want to account for the number of times the cache is really cleared
1450 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
1451 // called), we cannot decide whether a call of
1452 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
1453 // time it is called. Instead we only decrement the bucket counter at the time
1454 // when the cache is cleared (when page loads happen).
1455 class ClearCacheQuotaHeuristic : public QuotaLimitHeuristic {
1456 public:
1457 ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
1458 : QuotaLimitHeuristic(config, map),
1459 callback_registered_(false),
1460 weak_ptr_factory_(this) {}
1461 virtual ~ClearCacheQuotaHeuristic() {}
1462 virtual bool Apply(Bucket* bucket,
1463 const base::TimeTicks& event_time) OVERRIDE;
1464
1465 private:
1466 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
1467 // load.
1468 //
1469 // We don't need to take care of the life time of |bucket|: It is owned by the
1470 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
1471 // long as |this| exists, the respective BucketMapper and its bucket will
1472 // exist as well.
1473 void OnPageLoad(Bucket* bucket);
1474
1475 // Flag to prevent that we register more than one call back in-between
1476 // clearing the cache.
1477 bool callback_registered_;
1478
1479 base::WeakPtrFactory<ClearCacheQuotaHeuristic> weak_ptr_factory_;
1480
1481 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic);
1482 };
1483
1484 bool ClearCacheQuotaHeuristic::Apply(Bucket* bucket,
1485 const base::TimeTicks& event_time) {
1486 if (event_time > bucket->expiration())
1487 bucket->Reset(config(), event_time);
1488
1489 // Call bucket->DeductToken() on a new page load, this is when
1490 // webRequest.handlerBehaviorChanged() clears the cache.
1491 if (!callback_registered_) {
1492 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
1493 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad,
1494 weak_ptr_factory_.GetWeakPtr(),
1495 bucket));
1496 callback_registered_ = true;
1497 }
1498
1499 // We only check whether tokens are left here. Deducting a token happens in
1500 // OnPageLoad().
1501 return bucket->has_tokens();
1502 }
1503
1504 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket* bucket) {
1505 callback_registered_ = false;
1506 bucket->DeductToken();
1507 }
1508
1509 bool WebRequestAddEventListener::RunImpl() {
1510 // Argument 0 is the callback, which we don't use here.
1511
1512 ExtensionWebRequestEventRouter::RequestFilter filter;
1513 DictionaryValue* value = NULL;
1514 error_.clear();
1515 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
1516 // Failure + an empty error string means a fatal error.
1517 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error_) ||
1518 !error_.empty());
1519 if (!error_.empty())
1520 return false;
1521
1522 int extra_info_spec = 0;
1523 if (HasOptionalArgument(2)) {
1524 ListValue* value = NULL;
1525 EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
1526 EXTENSION_FUNCTION_VALIDATE(
1527 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
1528 *value, &extra_info_spec));
1529 }
1530
1531 std::string event_name;
1532 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
1533
1534 std::string sub_event_name;
1535 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
1536
1537 const Extension* extension =
1538 extension_info_map()->extensions().GetByID(extension_id());
1539 std::string extension_name = extension ? extension->name() : extension_id();
1540
1541 // We check automatically whether the extension has the 'webRequest'
1542 // permission. For blocking calls we require the additional permission
1543 // 'webRequestBlocking'.
1544 if ((extra_info_spec &
1545 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
1546 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) &&
1547 !extension->HasAPIPermission(
1548 ExtensionAPIPermission::kWebRequestBlocking)) {
1549 error_ = keys::kBlockingPermissionRequired;
1550 return false;
1551 }
1552
1553 // We allow to subscribe to patterns that are broader than the host
1554 // permissions. E.g., we could subscribe to http://www.example.com/*
1555 // while having host permissions for http://www.example.com/foo/* and
1556 // http://www.example.com/bar/*.
1557 // For this reason we do only a coarse check here to warn the extension
1558 // developer if he does something obviously wrong.
1559 if (extension->GetEffectiveHostPermissions().is_empty()) {
1560 error_ = keys::kHostPermissionsRequired;
1561 return false;
1562 }
1563
1564 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
1565 profile_id(), extension_id(), extension_name,
1566 event_name, sub_event_name, filter,
1567 extra_info_spec, ipc_sender_weak());
1568
1569 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1570 base::Bind(&ClearCacheOnNavigationOnUI));
1571
1572 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
1573 &NotifyWebRequestAPIUsed,
1574 profile_id(), make_scoped_refptr(GetExtension())));
1575
1576 return true;
1577 }
1578
1579 bool WebRequestEventHandled::RunImpl() {
1580 std::string event_name;
1581 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
1582
1583 std::string sub_event_name;
1584 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
1585
1586 std::string request_id_str;
1587 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
1588 uint64 request_id;
1589 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
1590 &request_id));
1591
1592 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
1593 if (HasOptionalArgument(3)) {
1594 DictionaryValue* value = NULL;
1595 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(3, &value));
1596
1597 if (!value->empty()) {
1598 base::Time install_time =
1599 extension_info_map()->GetInstallTime(extension_id());
1600 response.reset(new ExtensionWebRequestEventRouter::EventResponse(
1601 extension_id(), install_time));
1602 }
1603
1604 if (value->HasKey("cancel")) {
1605 // Don't allow cancel mixed with other keys.
1606 if (value->HasKey("redirectUrl") || value->HasKey("requestHeaders")) {
1607 error_ = keys::kInvalidBlockingResponse;
1608 return false;
1609 }
1610
1611 bool cancel = false;
1612 EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
1613 response->cancel = cancel;
1614 }
1615
1616 if (value->HasKey("redirectUrl")) {
1617 std::string new_url_str;
1618 EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
1619 &new_url_str));
1620 response->new_url = GURL(new_url_str);
1621 if (!response->new_url.is_valid()) {
1622 error_ = ExtensionErrorUtils::FormatErrorMessage(
1623 keys::kInvalidRedirectUrl, new_url_str);
1624 return false;
1625 }
1626 }
1627
1628 if (value->HasKey("requestHeaders")) {
1629 ListValue* request_headers_value = NULL;
1630 response->request_headers.reset(new net::HttpRequestHeaders());
1631 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kRequestHeadersKey,
1632 &request_headers_value));
1633 for (size_t i = 0; i < request_headers_value->GetSize(); ++i) {
1634 DictionaryValue* header_value = NULL;
1635 std::string name;
1636 std::string value;
1637 EXTENSION_FUNCTION_VALIDATE(
1638 request_headers_value->GetDictionary(i, &header_value));
1639 EXTENSION_FUNCTION_VALIDATE(
1640 FromHeaderDictionary(header_value, &name, &value));
1641 response->request_headers->SetHeader(name, value);
1642 }
1643 }
1644
1645 if (value->HasKey("responseHeaders")) {
1646 scoped_ptr<helpers::ResponseHeaders> response_headers(
1647 new helpers::ResponseHeaders());
1648 ListValue* response_headers_value = NULL;
1649 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kResponseHeadersKey,
1650 &response_headers_value));
1651 for (size_t i = 0; i < response_headers_value->GetSize(); ++i) {
1652 DictionaryValue* header_value = NULL;
1653 std::string name;
1654 std::string value;
1655 EXTENSION_FUNCTION_VALIDATE(
1656 response_headers_value->GetDictionary(i, &header_value));
1657 EXTENSION_FUNCTION_VALIDATE(
1658 FromHeaderDictionary(header_value, &name, &value));
1659 response_headers->push_back(helpers::ResponseHeader(name, value));
1660 }
1661 response->response_headers.reset(response_headers.release());
1662 }
1663
1664 if (value->HasKey(keys::kAuthCredentialsKey)) {
1665 DictionaryValue* credentials_value = NULL;
1666 EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
1667 keys::kAuthCredentialsKey,
1668 &credentials_value));
1669 string16 username;
1670 string16 password;
1671 EXTENSION_FUNCTION_VALIDATE(
1672 credentials_value->GetString(keys::kUsernameKey, &username));
1673 EXTENSION_FUNCTION_VALIDATE(
1674 credentials_value->GetString(keys::kPasswordKey, &password));
1675 response->auth_credentials.reset(
1676 new net::AuthCredentials(username, password));
1677 }
1678 }
1679
1680 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
1681 profile_id(), extension_id(), event_name, sub_event_name, request_id,
1682 response.release());
1683
1684 return true;
1685 }
1686
1687 bool WebRequestHandlerBehaviorChanged::RunImpl() {
1688 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1689 base::Bind(&ClearCacheOnNavigationOnUI));
1690 return true;
1691 }
1692
1693 void WebRequestHandlerBehaviorChanged::GetQuotaLimitHeuristics(
1694 QuotaLimitHeuristics* heuristics) const {
1695 QuotaLimitHeuristic::Config config = {
1696 20, // Refill 20 tokens per interval.
1697 base::TimeDelta::FromMinutes(10) // 10 minutes refill interval.
1698 };
1699 QuotaLimitHeuristic::BucketMapper* bucket_mapper =
1700 new QuotaLimitHeuristic::SingletonBucketMapper();
1701 ClearCacheQuotaHeuristic* heuristic =
1702 new ClearCacheQuotaHeuristic(config, bucket_mapper);
1703 heuristics->push_back(heuristic);
1704 }
1705
1706 void WebRequestHandlerBehaviorChanged::OnQuotaExceeded() {
1707 // Post warning message.
1708 std::set<std::string> extension_ids;
1709 extension_ids.insert(extension_id());
1710 BrowserThread::PostTask(
1711 BrowserThread::UI,
1712 FROM_HERE,
1713 base::Bind(&ExtensionWarningSet::NotifyWarningsOnUI,
1714 profile_id(),
1715 extension_ids,
1716 ExtensionWarningSet::kRepeatedCacheFlushes));
1717
1718 // Continue gracefully.
1719 Run();
1720 }
1721
1722 void SendExtensionWebRequestStatusToHost(content::RenderProcessHost* host) {
1723 Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
1724 if (!profile || !profile->GetExtensionService())
1725 return;
1726
1727 bool adblock = false;
1728 bool adblock_plus = false;
1729 bool other = false;
1730 const ExtensionSet* extensions =
1731 profile->GetExtensionService()->extensions();
1732 for (ExtensionSet::const_iterator it = extensions->begin();
1733 it != extensions->end(); ++it) {
1734 if (profile->GetExtensionService()->HasUsedWebRequest(*it)) {
1735 if ((*it)->name().find("Adblock Plus") != std::string::npos) {
1736 adblock_plus = true;
1737 } else if ((*it)->name().find("AdBlock") != std::string::npos) {
1738 adblock = true;
1739 } else {
1740 other = true;
1741 }
1742 }
1743 }
1744
1745 host->Send(new ExtensionMsg_UsingWebRequestAPI(adblock, adblock_plus, other));
1746 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698