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

Side by Side Diff: chrome/browser/extensions/api/web_request/web_request_api.cc

Issue 584163004: Move web_request directory to //extensions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase again Created 6 years, 3 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/web_request/web_request_api.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/json/json_writer.h"
12 #include "base/lazy_instance.h"
13 #include "base/metrics/histogram.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/time/time.h"
18 #include "base/values.h"
19 #include "chrome/browser/extensions/api/web_request/upload_data_presenter.h"
20 #include "chrome/browser/extensions/api/web_request/web_request_time_tracker.h"
21 #include "chrome/common/extensions/api/web_request.h"
22 #include "content/public/browser/browser_message_filter.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/render_frame_host.h"
25 #include "content/public/browser/render_process_host.h"
26 #include "content/public/browser/resource_request_info.h"
27 #include "content/public/browser/user_metrics.h"
28 #include "extensions/browser/api/activity_log/web_request_constants.h"
29 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
30 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
31 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registr y.h"
32 #include "extensions/browser/api/extensions_api_client.h"
33 #include "extensions/browser/api/web_request/web_request_api_constants.h"
34 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
35 #include "extensions/browser/api/web_request/web_request_api_utils.h"
36 #include "extensions/browser/api/web_request/web_request_api_utils.h"
37 #include "extensions/browser/api/web_request/web_request_event_router_delegate.h "
38 #include "extensions/browser/event_router.h"
39 #include "extensions/browser/extension_message_filter.h"
40 #include "extensions/browser/extension_prefs.h"
41 #include "extensions/browser/extension_registry.h"
42 #include "extensions/browser/extension_system.h"
43 #include "extensions/browser/extensions_browser_client.h"
44 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
45 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
46 #include "extensions/browser/info_map.h"
47 #include "extensions/browser/runtime_data.h"
48 #include "extensions/browser/warning_service.h"
49 #include "extensions/browser/warning_set.h"
50 #include "extensions/common/error_utils.h"
51 #include "extensions/common/event_filtering_info.h"
52 #include "extensions/common/extension.h"
53 #include "extensions/common/features/feature.h"
54 #include "extensions/common/permissions/permissions_data.h"
55 #include "extensions/common/url_pattern.h"
56 #include "extensions/strings/grit/extensions_strings.h"
57 #include "net/base/auth.h"
58 #include "net/base/net_errors.h"
59 #include "net/base/upload_data_stream.h"
60 #include "net/http/http_response_headers.h"
61 #include "net/http/http_util.h"
62 #include "net/url_request/url_request.h"
63 #include "ui/base/l10n/l10n_util.h"
64 #include "url/gurl.h"
65
66 using base::DictionaryValue;
67 using base::ListValue;
68 using base::StringValue;
69 using content::BrowserMessageFilter;
70 using content::BrowserThread;
71 using content::ResourceRequestInfo;
72 using content::ResourceType;
73 using extensions::ErrorUtils;
74 using extensions::Extension;
75 using extensions::InfoMap;
76 using extensions::Feature;
77 using extensions::RulesRegistryService;
78 using extensions::Warning;
79 using extensions::WarningService;
80 using extensions::WarningSet;
81
82 namespace activitylog = activity_log_web_request_constants;
83 namespace helpers = extension_web_request_api_helpers;
84 namespace utils = extension_web_request_api_utils;
85 namespace keys = extension_web_request_api_constants;
86 namespace web_request = extensions::api::web_request;
87 namespace declarative_keys = extensions::declarative_webrequest_constants;
88
89 namespace {
90
91 const char kWebRequestEventPrefix[] = "webRequest.";
92
93 // List of all the webRequest events.
94 const char* const kWebRequestEvents[] = {
95 keys::kOnBeforeRedirectEvent,
96 web_request::OnBeforeRequest::kEventName,
97 keys::kOnBeforeSendHeadersEvent,
98 keys::kOnCompletedEvent,
99 web_request::OnErrorOccurred::kEventName,
100 keys::kOnSendHeadersEvent,
101 keys::kOnAuthRequiredEvent,
102 keys::kOnResponseStartedEvent,
103 keys::kOnHeadersReceivedEvent,
104 };
105
106 const size_t kWebRequestEventsLength = arraysize(kWebRequestEvents);
107
108 const char* GetRequestStageAsString(
109 ExtensionWebRequestEventRouter::EventTypes type) {
110 switch (type) {
111 case ExtensionWebRequestEventRouter::kInvalidEvent:
112 return "Invalid";
113 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
114 return keys::kOnBeforeRequest;
115 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders:
116 return keys::kOnBeforeSendHeaders;
117 case ExtensionWebRequestEventRouter::kOnSendHeaders:
118 return keys::kOnSendHeaders;
119 case ExtensionWebRequestEventRouter::kOnHeadersReceived:
120 return keys::kOnHeadersReceived;
121 case ExtensionWebRequestEventRouter::kOnBeforeRedirect:
122 return keys::kOnBeforeRedirect;
123 case ExtensionWebRequestEventRouter::kOnAuthRequired:
124 return keys::kOnAuthRequired;
125 case ExtensionWebRequestEventRouter::kOnResponseStarted:
126 return keys::kOnResponseStarted;
127 case ExtensionWebRequestEventRouter::kOnErrorOccurred:
128 return keys::kOnErrorOccurred;
129 case ExtensionWebRequestEventRouter::kOnCompleted:
130 return keys::kOnCompleted;
131 }
132 NOTREACHED();
133 return "Not reached";
134 }
135
136 int GetFrameId(bool is_main_frame, int frame_id) {
137 return is_main_frame ? 0 : frame_id;
138 }
139
140 bool IsWebRequestEvent(const std::string& event_name) {
141 std::string web_request_event_name(event_name);
142 if (StartsWithASCII(
143 web_request_event_name, webview::kWebViewEventPrefix, true)) {
144 web_request_event_name.replace(
145 0, strlen(webview::kWebViewEventPrefix), kWebRequestEventPrefix);
146 }
147 return std::find(
148 kWebRequestEvents,
149 kWebRequestEvents + kWebRequestEventsLength,
150 web_request_event_name) != (kWebRequestEvents + kWebRequestEventsLength);
151 }
152
153 // Returns whether |request| has been triggered by an extension in
154 // |extension_info_map|.
155 bool IsRequestFromExtension(const net::URLRequest* request,
156 const InfoMap* extension_info_map) {
157 // |extension_info_map| is NULL for system-level requests.
158 if (!extension_info_map)
159 return false;
160
161 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
162
163 // If this request was not created by the ResourceDispatcher, |info| is NULL.
164 // All requests from extensions are created by the ResourceDispatcher.
165 if (!info)
166 return false;
167
168 return extension_info_map->process_map().Contains(info->GetChildID());
169 }
170
171 void ExtractRequestRoutingInfo(net::URLRequest* request,
172 int* render_process_host_id,
173 int* routing_id) {
174 if (!request->GetUserData(NULL))
175 return;
176 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
177 *render_process_host_id = info->GetChildID();
178 *routing_id = info->GetRouteID();
179 }
180
181 // Given a |request|, this function determines whether it originated from
182 // a <webview> guest process or not. If it is from a <webview> guest process,
183 // then |web_view_info| is returned with information about the instance ID
184 // that uniquely identifies the <webview> and its embedder.
185 bool GetWebViewInfo(
186 net::URLRequest* request,
187 extensions::WebViewRendererState::WebViewInfo* web_view_info) {
188 int render_process_host_id = -1;
189 int routing_id = -1;
190 ExtractRequestRoutingInfo(request, &render_process_host_id, &routing_id);
191 return extensions::WebViewRendererState::GetInstance()->
192 GetInfo(render_process_host_id, routing_id, web_view_info);
193 }
194
195 void ExtractRequestInfoDetails(net::URLRequest* request,
196 bool* is_main_frame,
197 int* frame_id,
198 bool* parent_is_main_frame,
199 int* parent_frame_id,
200 int* render_process_host_id,
201 int* routing_id,
202 ResourceType* resource_type) {
203 if (!request->GetUserData(NULL))
204 return;
205
206 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
207 *frame_id = info->GetRenderFrameID();
208 *is_main_frame = info->IsMainFrame();
209 *parent_frame_id = info->GetParentRenderFrameID();
210 *parent_is_main_frame = info->ParentIsMainFrame();
211 *render_process_host_id = info->GetChildID();
212 *routing_id = info->GetRouteID();
213
214 // Restrict the resource type to the values we care about.
215 if (utils::IsRelevantResourceType(info->GetResourceType()))
216 *resource_type = info->GetResourceType();
217 else
218 *resource_type = content::RESOURCE_TYPE_LAST_TYPE;
219 }
220
221 // Extracts the body from |request| and writes the data into |out|.
222 void ExtractRequestInfoBody(const net::URLRequest* request,
223 base::DictionaryValue* out) {
224 const net::UploadDataStream* upload_data = request->get_upload();
225 if (!upload_data ||
226 (request->method() != "POST" && request->method() != "PUT"))
227 return; // Need to exit without "out->Set(keys::kRequestBodyKey, ...);" .
228
229 base::DictionaryValue* requestBody = new base::DictionaryValue();
230 out->Set(keys::kRequestBodyKey, requestBody);
231
232 // Get the data presenters, ordered by how specific they are.
233 extensions::ParsedDataPresenter parsed_data_presenter(*request);
234 extensions::RawDataPresenter raw_data_presenter;
235 extensions::UploadDataPresenter* const presenters[] = {
236 &parsed_data_presenter, // 1: any parseable forms? (Specific to forms.)
237 &raw_data_presenter // 2: any data at all? (Non-specific.)
238 };
239 // Keys for the results of the corresponding presenters.
240 static const char* const kKeys[] = {
241 keys::kRequestBodyFormDataKey,
242 keys::kRequestBodyRawKey
243 };
244
245 const ScopedVector<net::UploadElementReader>& readers =
246 upload_data->element_readers();
247 bool some_succeeded = false;
248 for (size_t i = 0; !some_succeeded && i < arraysize(presenters); ++i) {
249 ScopedVector<net::UploadElementReader>::const_iterator reader;
250 for (reader = readers.begin(); reader != readers.end(); ++reader)
251 presenters[i]->FeedNext(**reader);
252 if (presenters[i]->Succeeded()) {
253 requestBody->Set(kKeys[i], presenters[i]->Result().release());
254 some_succeeded = true;
255 }
256 }
257 if (!some_succeeded)
258 requestBody->SetString(keys::kRequestBodyErrorKey, "Unknown error.");
259 }
260
261 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
262 // true if successful.
263 bool FromHeaderDictionary(const base::DictionaryValue* header_value,
264 std::string* name,
265 std::string* value) {
266 if (!header_value->GetString(keys::kHeaderNameKey, name))
267 return false;
268
269 // We require either a "value" or a "binaryValue" entry.
270 if (!(header_value->HasKey(keys::kHeaderValueKey) ^
271 header_value->HasKey(keys::kHeaderBinaryValueKey)))
272 return false;
273
274 if (header_value->HasKey(keys::kHeaderValueKey)) {
275 if (!header_value->GetString(keys::kHeaderValueKey, value)) {
276 return false;
277 }
278 } else if (header_value->HasKey(keys::kHeaderBinaryValueKey)) {
279 const base::ListValue* list = NULL;
280 if (!header_value->HasKey(keys::kHeaderBinaryValueKey)) {
281 *value = "";
282 } else if (!header_value->GetList(keys::kHeaderBinaryValueKey, &list) ||
283 !helpers::CharListToString(list, value)) {
284 return false;
285 }
286 }
287 return true;
288 }
289
290 // Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
291 // NULL, the list is empty. Ownership is passed to the caller.
292 base::ListValue* GetResponseHeadersList(
293 const net::HttpResponseHeaders* headers) {
294 base::ListValue* headers_value = new base::ListValue();
295 if (headers) {
296 void* iter = NULL;
297 std::string name;
298 std::string value;
299 while (headers->EnumerateHeaderLines(&iter, &name, &value))
300 headers_value->Append(helpers::CreateHeaderDictionary(name, value));
301 }
302 return headers_value;
303 }
304
305 base::ListValue* GetRequestHeadersList(const net::HttpRequestHeaders& headers) {
306 base::ListValue* headers_value = new base::ListValue();
307 for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext(); )
308 headers_value->Append(
309 helpers::CreateHeaderDictionary(it.name(), it.value()));
310 return headers_value;
311 }
312
313 // Creates a base::StringValue with the status line of |headers|. If |headers|
314 // is NULL, an empty string is returned. Ownership is passed to the caller.
315 base::StringValue* GetStatusLine(net::HttpResponseHeaders* headers) {
316 return new base::StringValue(
317 headers ? headers->GetStatusLine() : std::string());
318 }
319
320 void RemoveEventListenerOnUI(
321 void* browser_context_id,
322 const std::string& event_name,
323 int process_id,
324 const std::string& extension_id) {
325 DCHECK_CURRENTLY_ON(BrowserThread::UI);
326
327 content::BrowserContext* browser_context =
328 reinterpret_cast<content::BrowserContext*>(browser_context_id);
329 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(
330 browser_context))
331 return;
332
333 extensions::EventRouter* event_router =
334 extensions::EventRouter::Get(browser_context);
335 if (!event_router)
336 return;
337
338 content::RenderProcessHost* process =
339 content::RenderProcessHost::FromID(process_id);
340 if (!process)
341 return;
342
343 event_router->RemoveEventListener(event_name, process, extension_id);
344 }
345
346 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
347 // to subscribers of webview.onMessage if the action is being operated upon
348 // a <webview> guest renderer.
349 // |extension_id| identifies the extension that sends and receives the event.
350 // |is_web_view_guest| indicates whether the action is for a <webview>.
351 // |web_view_info| is a struct containing information about the <webview>
352 // embedder.
353 // |event_argument| is passed to the event listener.
354 void SendOnMessageEventOnUI(
355 void* browser_context_id,
356 const std::string& extension_id,
357 bool is_web_view_guest,
358 const extensions::WebViewRendererState::WebViewInfo& web_view_info,
359 scoped_ptr<base::DictionaryValue> event_argument) {
360 DCHECK_CURRENTLY_ON(BrowserThread::UI);
361
362 content::BrowserContext* browser_context =
363 reinterpret_cast<content::BrowserContext*>(browser_context_id);
364 if (!extensions::ExtensionsBrowserClient::Get()->IsValidContext(
365 browser_context))
366 return;
367
368 scoped_ptr<base::ListValue> event_args(new base::ListValue);
369 event_args->Append(event_argument.release());
370
371 extensions::EventRouter* event_router =
372 extensions::EventRouter::Get(browser_context);
373
374 extensions::EventFilteringInfo event_filtering_info;
375
376 std::string event_name;
377 // The instance ID uniquely identifies a <webview> instance within an embedder
378 // process. We use a filter here so that only event listeners for a particular
379 // <webview> will fire.
380 if (is_web_view_guest) {
381 event_filtering_info.SetInstanceID(web_view_info.instance_id);
382 event_name = webview::kEventMessage;
383 } else {
384 event_name = declarative_keys::kOnMessage;
385 }
386
387 scoped_ptr<extensions::Event> event(new extensions::Event(
388 event_name,
389 event_args.Pass(), browser_context, GURL(),
390 extensions::EventRouter::USER_GESTURE_UNKNOWN,
391 event_filtering_info));
392 event_router->DispatchEventToExtension(extension_id, event.Pass());
393 }
394
395 void RemoveEventListenerOnIOThread(
396 content::BrowserContext* browser_context,
397 const std::string& extension_id,
398 const std::string& sub_event_name) {
399 ExtensionWebRequestEventRouter::GetInstance()->RemoveEventListener(
400 browser_context, extension_id, sub_event_name);
401 }
402
403 } // namespace
404
405 namespace extensions {
406
407 WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
408 : browser_context_(context) {
409 EventRouter* event_router = EventRouter::Get(browser_context_);
410 for (size_t i = 0; i < arraysize(kWebRequestEvents); ++i) {
411 // Observe the webRequest event.
412 std::string event_name = kWebRequestEvents[i];
413 event_router->RegisterObserver(this, event_name);
414
415 // Also observe the corresponding webview event.
416 event_name.replace(
417 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
418 event_router->RegisterObserver(this, event_name);
419 }
420 }
421
422 WebRequestAPI::~WebRequestAPI() {
423 EventRouter::Get(browser_context_)->UnregisterObserver(this);
424 }
425
426 static base::LazyInstance<BrowserContextKeyedAPIFactory<WebRequestAPI> >
427 g_factory = LAZY_INSTANCE_INITIALIZER;
428
429 // static
430 BrowserContextKeyedAPIFactory<WebRequestAPI>*
431 WebRequestAPI::GetFactoryInstance() {
432 return g_factory.Pointer();
433 }
434
435 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo& details) {
436 DCHECK_CURRENTLY_ON(BrowserThread::UI);
437 // Note that details.event_name includes the sub-event details (e.g. "/123").
438 BrowserThread::PostTask(BrowserThread::IO,
439 FROM_HERE,
440 base::Bind(&RemoveEventListenerOnIOThread,
441 details.browser_context,
442 details.extension_id,
443 details.event_name));
444 }
445
446 } // namespace extensions
447
448 // Represents a single unique listener to an event, along with whatever filter
449 // parameters and extra_info_spec were specified at the time the listener was
450 // added.
451 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
452 // not play well with event pages. See downloads.onDeterminingFilename and
453 // ExtensionDownloadsEventRouter for an alternative approach.
454 struct ExtensionWebRequestEventRouter::EventListener {
455 std::string extension_id;
456 std::string extension_name;
457 std::string sub_event_name;
458 RequestFilter filter;
459 int extra_info_spec;
460 int embedder_process_id;
461 int webview_instance_id;
462 base::WeakPtr<IPC::Sender> ipc_sender;
463 mutable std::set<uint64> blocked_requests;
464
465 // Comparator to work with std::set.
466 bool operator<(const EventListener& that) const {
467 if (extension_id < that.extension_id)
468 return true;
469 if (extension_id == that.extension_id &&
470 sub_event_name < that.sub_event_name)
471 return true;
472 return false;
473 }
474
475 EventListener() : extra_info_spec(0) {}
476 };
477
478 // Contains info about requests that are blocked waiting for a response from
479 // an extension.
480 struct ExtensionWebRequestEventRouter::BlockedRequest {
481 // The request that is being blocked.
482 net::URLRequest* request;
483
484 // Whether the request originates from an incognito tab.
485 bool is_incognito;
486
487 // The event that we're currently blocked on.
488 EventTypes event;
489
490 // The number of event handlers that we are awaiting a response from.
491 int num_handlers_blocking;
492
493 // Pointer to NetLog to report significant changes to the request for
494 // debugging.
495 const net::BoundNetLog* net_log;
496
497 // The callback to call when we get a response from all event handlers.
498 net::CompletionCallback callback;
499
500 // If non-empty, this contains the new URL that the request will redirect to.
501 // Only valid for OnBeforeRequest and OnHeadersReceived.
502 GURL* new_url;
503
504 // The request headers that will be issued along with this request. Only valid
505 // for OnBeforeSendHeaders.
506 net::HttpRequestHeaders* request_headers;
507
508 // The response headers that were received from the server. Only valid for
509 // OnHeadersReceived.
510 scoped_refptr<const net::HttpResponseHeaders> original_response_headers;
511
512 // Location where to override response headers. Only valid for
513 // OnHeadersReceived.
514 scoped_refptr<net::HttpResponseHeaders>* override_response_headers;
515
516 // If non-empty, this contains the auth credentials that may be filled in.
517 // Only valid for OnAuthRequired.
518 net::AuthCredentials* auth_credentials;
519
520 // The callback to invoke for auth. If |auth_callback.is_null()| is false,
521 // |callback| must be NULL.
522 // Only valid for OnAuthRequired.
523 net::NetworkDelegate::AuthCallback auth_callback;
524
525 // Time the request was paused. Used for logging purposes.
526 base::Time blocking_time;
527
528 // Changes requested by extensions.
529 helpers::EventResponseDeltas response_deltas;
530
531 // Provider of meta data about extensions, only used and non-NULL for events
532 // that are delayed until the rules registry is ready.
533 InfoMap* extension_info_map;
534
535 BlockedRequest()
536 : request(NULL),
537 is_incognito(false),
538 event(kInvalidEvent),
539 num_handlers_blocking(0),
540 net_log(NULL),
541 new_url(NULL),
542 request_headers(NULL),
543 override_response_headers(NULL),
544 auth_credentials(NULL),
545 extension_info_map(NULL) {}
546 };
547
548 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
549 const base::DictionaryValue& value, std::string* error) {
550 if (!value.HasKey("urls"))
551 return false;
552
553 for (base::DictionaryValue::Iterator it(value); !it.IsAtEnd(); it.Advance()) {
554 if (it.key() == "urls") {
555 const base::ListValue* urls_value = NULL;
556 if (!it.value().GetAsList(&urls_value))
557 return false;
558 for (size_t i = 0; i < urls_value->GetSize(); ++i) {
559 std::string url;
560 URLPattern pattern(
561 URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
562 URLPattern::SCHEME_FTP | URLPattern::SCHEME_FILE |
563 URLPattern::SCHEME_EXTENSION);
564 if (!urls_value->GetString(i, &url) ||
565 pattern.Parse(url) != URLPattern::PARSE_SUCCESS) {
566 *error = ErrorUtils::FormatErrorMessage(
567 keys::kInvalidRequestFilterUrl, url);
568 return false;
569 }
570 urls.AddPattern(pattern);
571 }
572 } else if (it.key() == "types") {
573 const base::ListValue* types_value = NULL;
574 if (!it.value().GetAsList(&types_value))
575 return false;
576 for (size_t i = 0; i < types_value->GetSize(); ++i) {
577 std::string type_str;
578 ResourceType type;
579 if (!types_value->GetString(i, &type_str) ||
580 !utils::ParseResourceType(type_str, &type))
581 return false;
582 types.push_back(type);
583 }
584 } else if (it.key() == "tabId") {
585 if (!it.value().GetAsInteger(&tab_id))
586 return false;
587 } else if (it.key() == "windowId") {
588 if (!it.value().GetAsInteger(&window_id))
589 return false;
590 } else {
591 return false;
592 }
593 }
594 return true;
595 }
596
597 // static
598 bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
599 const base::ListValue& value, int* extra_info_spec) {
600 *extra_info_spec = 0;
601 for (size_t i = 0; i < value.GetSize(); ++i) {
602 std::string str;
603 if (!value.GetString(i, &str))
604 return false;
605
606 if (str == "requestHeaders")
607 *extra_info_spec |= REQUEST_HEADERS;
608 else if (str == "responseHeaders")
609 *extra_info_spec |= RESPONSE_HEADERS;
610 else if (str == "blocking")
611 *extra_info_spec |= BLOCKING;
612 else if (str == "asyncBlocking")
613 *extra_info_spec |= ASYNC_BLOCKING;
614 else if (str == "requestBody")
615 *extra_info_spec |= REQUEST_BODY;
616 else
617 return false;
618
619 // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
620 if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
621 return false;
622 }
623 return true;
624 }
625
626
627 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
628 const std::string& extension_id, const base::Time& extension_install_time)
629 : extension_id(extension_id),
630 extension_install_time(extension_install_time),
631 cancel(false) {
632 }
633
634 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
635 }
636
637 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
638 : tab_id(-1), window_id(-1) {
639 }
640
641 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() {
642 }
643
644 //
645 // ExtensionWebRequestEventRouter
646 //
647
648 // static
649 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
650 return Singleton<ExtensionWebRequestEventRouter>::get();
651 }
652
653 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
654 : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
655 web_request_event_router_delegate_.reset(
656 extensions::ExtensionsAPIClient::Get()->
657 CreateWebRequestEventRouterDelegate());
658 }
659
660 ExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
661 }
662
663 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
664 void* browser_context,
665 const extensions::RulesRegistry::WebViewKey& webview_key,
666 scoped_refptr<extensions::WebRequestRulesRegistry> rules_registry) {
667 RulesRegistryKey key(browser_context, webview_key);
668 if (rules_registry.get())
669 rules_registries_[key] = rules_registry;
670 else
671 rules_registries_.erase(key);
672 }
673
674 void ExtensionWebRequestEventRouter::ExtractRequestInfo(
675 net::URLRequest* request, base::DictionaryValue* out) {
676 bool is_main_frame = false;
677 int frame_id = -1;
678 bool parent_is_main_frame = false;
679 int parent_frame_id = -1;
680 int frame_id_for_extension = -1;
681 int parent_frame_id_for_extension = -1;
682 int render_process_host_id = -1;
683 int routing_id = -1;
684 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
685 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
686 &parent_is_main_frame, &parent_frame_id,
687 &render_process_host_id, &routing_id,
688 &resource_type);
689 frame_id_for_extension = GetFrameId(is_main_frame, frame_id);
690 parent_frame_id_for_extension = GetFrameId(parent_is_main_frame,
691 parent_frame_id);
692
693 out->SetString(keys::kRequestIdKey,
694 base::Uint64ToString(request->identifier()));
695 out->SetString(keys::kUrlKey, request->url().spec());
696 out->SetString(keys::kMethodKey, request->method());
697 out->SetInteger(keys::kFrameIdKey, frame_id_for_extension);
698 out->SetInteger(keys::kParentFrameIdKey, parent_frame_id_for_extension);
699 out->SetString(keys::kTypeKey, utils::ResourceTypeToString(resource_type));
700 out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
701 if (web_request_event_router_delegate_) {
702 web_request_event_router_delegate_->ExtractExtraRequestDetails(
703 request, out);
704 }
705 }
706
707 int ExtensionWebRequestEventRouter::OnBeforeRequest(
708 void* browser_context,
709 InfoMap* extension_info_map,
710 net::URLRequest* request,
711 const net::CompletionCallback& callback,
712 GURL* new_url) {
713 // We hide events from the system context as well as sensitive requests.
714 if (!browser_context ||
715 WebRequestPermissions::HideRequest(extension_info_map, request))
716 return net::OK;
717
718 if (IsPageLoad(request))
719 NotifyPageLoad();
720
721 request_time_tracker_->LogRequestStartTime(request->identifier(),
722 base::Time::Now(),
723 request->url(),
724 browser_context);
725
726 // Whether to initialized blocked_requests_.
727 bool initialize_blocked_requests = false;
728
729 initialize_blocked_requests |=
730 ProcessDeclarativeRules(browser_context, extension_info_map,
731 web_request::OnBeforeRequest::kEventName, request,
732 extensions::ON_BEFORE_REQUEST, NULL);
733
734 int extra_info_spec = 0;
735 std::vector<const EventListener*> listeners =
736 GetMatchingListeners(browser_context, extension_info_map,
737 web_request::OnBeforeRequest::kEventName, request,
738 &extra_info_spec);
739 if (!listeners.empty() &&
740 !GetAndSetSignaled(request->identifier(), kOnBeforeRequest)) {
741 base::ListValue args;
742 base::DictionaryValue* dict = new base::DictionaryValue();
743 ExtractRequestInfo(request, dict);
744 if (extra_info_spec & ExtraInfoSpec::REQUEST_BODY)
745 ExtractRequestInfoBody(request, dict);
746 args.Append(dict);
747
748 initialize_blocked_requests |=
749 DispatchEvent(browser_context, request, listeners, args);
750 }
751
752 if (!initialize_blocked_requests)
753 return net::OK; // Nobody saw a reason for modifying the request.
754
755 blocked_requests_[request->identifier()].event = kOnBeforeRequest;
756 blocked_requests_[request->identifier()].is_incognito |=
757 IsIncognitoBrowserContext(browser_context);
758 blocked_requests_[request->identifier()].request = request;
759 blocked_requests_[request->identifier()].callback = callback;
760 blocked_requests_[request->identifier()].new_url = new_url;
761 blocked_requests_[request->identifier()].net_log = &request->net_log();
762
763 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
764 // If there are no blocking handlers, only the declarative rules tried
765 // to modify the request and we can respond synchronously.
766 return ExecuteDeltas(browser_context, request->identifier(),
767 false /* call_callback*/);
768 } else {
769 return net::ERR_IO_PENDING;
770 }
771 }
772
773 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
774 void* browser_context,
775 InfoMap* extension_info_map,
776 net::URLRequest* request,
777 const net::CompletionCallback& callback,
778 net::HttpRequestHeaders* headers) {
779 // We hide events from the system context as well as sensitive requests.
780 if (!browser_context ||
781 WebRequestPermissions::HideRequest(extension_info_map, request))
782 return net::OK;
783
784 bool initialize_blocked_requests = false;
785
786 initialize_blocked_requests |=
787 ProcessDeclarativeRules(browser_context, extension_info_map,
788 keys::kOnBeforeSendHeadersEvent, request,
789 extensions::ON_BEFORE_SEND_HEADERS, NULL);
790
791 int extra_info_spec = 0;
792 std::vector<const EventListener*> listeners =
793 GetMatchingListeners(browser_context, extension_info_map,
794 keys::kOnBeforeSendHeadersEvent, request,
795 &extra_info_spec);
796 if (!listeners.empty() &&
797 !GetAndSetSignaled(request->identifier(), kOnBeforeSendHeaders)) {
798 base::ListValue args;
799 base::DictionaryValue* dict = new base::DictionaryValue();
800 ExtractRequestInfo(request, dict);
801 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
802 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(*headers));
803 args.Append(dict);
804
805 initialize_blocked_requests |=
806 DispatchEvent(browser_context, request, listeners, args);
807 }
808
809 if (!initialize_blocked_requests)
810 return net::OK; // Nobody saw a reason for modifying the request.
811
812 blocked_requests_[request->identifier()].event = kOnBeforeSendHeaders;
813 blocked_requests_[request->identifier()].is_incognito |=
814 IsIncognitoBrowserContext(browser_context);
815 blocked_requests_[request->identifier()].request = request;
816 blocked_requests_[request->identifier()].callback = callback;
817 blocked_requests_[request->identifier()].request_headers = headers;
818 blocked_requests_[request->identifier()].net_log = &request->net_log();
819
820 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
821 // If there are no blocking handlers, only the declarative rules tried
822 // to modify the request and we can respond synchronously.
823 return ExecuteDeltas(browser_context, request->identifier(),
824 false /* call_callback*/);
825 } else {
826 return net::ERR_IO_PENDING;
827 }
828 }
829
830 void ExtensionWebRequestEventRouter::OnSendHeaders(
831 void* browser_context,
832 InfoMap* extension_info_map,
833 net::URLRequest* request,
834 const net::HttpRequestHeaders& headers) {
835 // We hide events from the system context as well as sensitive requests.
836 if (!browser_context ||
837 WebRequestPermissions::HideRequest(extension_info_map, request))
838 return;
839
840 if (GetAndSetSignaled(request->identifier(), kOnSendHeaders))
841 return;
842
843 ClearSignaled(request->identifier(), kOnBeforeRedirect);
844
845 int extra_info_spec = 0;
846 std::vector<const EventListener*> listeners =
847 GetMatchingListeners(browser_context, extension_info_map,
848 keys::kOnSendHeadersEvent, request,
849 &extra_info_spec);
850 if (listeners.empty())
851 return;
852
853 base::ListValue args;
854 base::DictionaryValue* dict = new base::DictionaryValue();
855 ExtractRequestInfo(request, dict);
856 if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
857 dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
858 args.Append(dict);
859
860 DispatchEvent(browser_context, request, listeners, args);
861 }
862
863 int ExtensionWebRequestEventRouter::OnHeadersReceived(
864 void* browser_context,
865 InfoMap* extension_info_map,
866 net::URLRequest* request,
867 const net::CompletionCallback& callback,
868 const net::HttpResponseHeaders* original_response_headers,
869 scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
870 GURL* allowed_unsafe_redirect_url) {
871 // We hide events from the system context as well as sensitive requests.
872 if (!browser_context ||
873 WebRequestPermissions::HideRequest(extension_info_map, request))
874 return net::OK;
875
876 bool initialize_blocked_requests = false;
877
878 initialize_blocked_requests |=
879 ProcessDeclarativeRules(browser_context, extension_info_map,
880 keys::kOnHeadersReceivedEvent, request,
881 extensions::ON_HEADERS_RECEIVED,
882 original_response_headers);
883
884 int extra_info_spec = 0;
885 std::vector<const EventListener*> listeners =
886 GetMatchingListeners(browser_context, extension_info_map,
887 keys::kOnHeadersReceivedEvent, request,
888 &extra_info_spec);
889
890 if (!listeners.empty() &&
891 !GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) {
892 base::ListValue args;
893 base::DictionaryValue* dict = new base::DictionaryValue();
894 ExtractRequestInfo(request, dict);
895 dict->SetString(keys::kStatusLineKey,
896 original_response_headers->GetStatusLine());
897 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
898 dict->Set(keys::kResponseHeadersKey,
899 GetResponseHeadersList(original_response_headers));
900 }
901 args.Append(dict);
902
903 initialize_blocked_requests |=
904 DispatchEvent(browser_context, request, listeners, args);
905 }
906
907 if (!initialize_blocked_requests)
908 return net::OK; // Nobody saw a reason for modifying the request.
909
910 blocked_requests_[request->identifier()].event = kOnHeadersReceived;
911 blocked_requests_[request->identifier()].is_incognito |=
912 IsIncognitoBrowserContext(browser_context);
913 blocked_requests_[request->identifier()].request = request;
914 blocked_requests_[request->identifier()].callback = callback;
915 blocked_requests_[request->identifier()].net_log = &request->net_log();
916 blocked_requests_[request->identifier()].override_response_headers =
917 override_response_headers;
918 blocked_requests_[request->identifier()].original_response_headers =
919 original_response_headers;
920 blocked_requests_[request->identifier()].new_url =
921 allowed_unsafe_redirect_url;
922
923 if (blocked_requests_[request->identifier()].num_handlers_blocking == 0) {
924 // If there are no blocking handlers, only the declarative rules tried
925 // to modify the request and we can respond synchronously.
926 return ExecuteDeltas(browser_context, request->identifier(),
927 false /* call_callback*/);
928 } else {
929 return net::ERR_IO_PENDING;
930 }
931 }
932
933 net::NetworkDelegate::AuthRequiredResponse
934 ExtensionWebRequestEventRouter::OnAuthRequired(
935 void* browser_context,
936 InfoMap* extension_info_map,
937 net::URLRequest* request,
938 const net::AuthChallengeInfo& auth_info,
939 const net::NetworkDelegate::AuthCallback& callback,
940 net::AuthCredentials* credentials) {
941 // No browser_context means that this is for authentication challenges in the
942 // system context. Skip in that case. Also skip sensitive requests.
943 if (!browser_context ||
944 WebRequestPermissions::HideRequest(extension_info_map, request))
945 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
946
947 int extra_info_spec = 0;
948 std::vector<const EventListener*> listeners =
949 GetMatchingListeners(browser_context, extension_info_map,
950 keys::kOnAuthRequiredEvent, request,
951 &extra_info_spec);
952 if (listeners.empty())
953 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
954
955 base::ListValue args;
956 base::DictionaryValue* dict = new base::DictionaryValue();
957 ExtractRequestInfo(request, dict);
958 dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
959 if (!auth_info.scheme.empty())
960 dict->SetString(keys::kSchemeKey, auth_info.scheme);
961 if (!auth_info.realm.empty())
962 dict->SetString(keys::kRealmKey, auth_info.realm);
963 base::DictionaryValue* challenger = new base::DictionaryValue();
964 challenger->SetString(keys::kHostKey, auth_info.challenger.host());
965 challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
966 dict->Set(keys::kChallengerKey, challenger);
967 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
968 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
969 dict->Set(keys::kResponseHeadersKey,
970 GetResponseHeadersList(request->response_headers()));
971 }
972 args.Append(dict);
973
974 if (DispatchEvent(browser_context, request, listeners, args)) {
975 blocked_requests_[request->identifier()].event = kOnAuthRequired;
976 blocked_requests_[request->identifier()].is_incognito |=
977 IsIncognitoBrowserContext(browser_context);
978 blocked_requests_[request->identifier()].request = request;
979 blocked_requests_[request->identifier()].auth_callback = callback;
980 blocked_requests_[request->identifier()].auth_credentials = credentials;
981 blocked_requests_[request->identifier()].net_log = &request->net_log();
982 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING;
983 }
984 return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
985 }
986
987 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
988 void* browser_context,
989 InfoMap* extension_info_map,
990 net::URLRequest* request,
991 const GURL& new_location) {
992 // We hide events from the system context as well as sensitive requests.
993 if (!browser_context ||
994 WebRequestPermissions::HideRequest(extension_info_map, request))
995 return;
996
997 if (GetAndSetSignaled(request->identifier(), kOnBeforeRedirect))
998 return;
999
1000 ClearSignaled(request->identifier(), kOnBeforeRequest);
1001 ClearSignaled(request->identifier(), kOnBeforeSendHeaders);
1002 ClearSignaled(request->identifier(), kOnSendHeaders);
1003 ClearSignaled(request->identifier(), kOnHeadersReceived);
1004
1005 int extra_info_spec = 0;
1006 std::vector<const EventListener*> listeners =
1007 GetMatchingListeners(browser_context, extension_info_map,
1008 keys::kOnBeforeRedirectEvent, request,
1009 &extra_info_spec);
1010 if (listeners.empty())
1011 return;
1012
1013 int http_status_code = request->GetResponseCode();
1014
1015 std::string response_ip = request->GetSocketAddress().host();
1016
1017 base::ListValue args;
1018 base::DictionaryValue* dict = new base::DictionaryValue();
1019 ExtractRequestInfo(request, dict);
1020 dict->SetString(keys::kRedirectUrlKey, new_location.spec());
1021 dict->SetInteger(keys::kStatusCodeKey, http_status_code);
1022 if (!response_ip.empty())
1023 dict->SetString(keys::kIpKey, response_ip);
1024 dict->SetBoolean(keys::kFromCache, request->was_cached());
1025 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1026 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1027 dict->Set(keys::kResponseHeadersKey,
1028 GetResponseHeadersList(request->response_headers()));
1029 }
1030 args.Append(dict);
1031
1032 DispatchEvent(browser_context, request, listeners, args);
1033 }
1034
1035 void ExtensionWebRequestEventRouter::OnResponseStarted(
1036 void* browser_context,
1037 InfoMap* extension_info_map,
1038 net::URLRequest* request) {
1039 // We hide events from the system context as well as sensitive requests.
1040 if (!browser_context ||
1041 WebRequestPermissions::HideRequest(extension_info_map, request))
1042 return;
1043
1044 // OnResponseStarted is even triggered, when the request was cancelled.
1045 if (request->status().status() != net::URLRequestStatus::SUCCESS)
1046 return;
1047
1048 int extra_info_spec = 0;
1049 std::vector<const EventListener*> listeners =
1050 GetMatchingListeners(browser_context, extension_info_map,
1051 keys::kOnResponseStartedEvent, request,
1052 &extra_info_spec);
1053 if (listeners.empty())
1054 return;
1055
1056 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1057 int response_code = 200;
1058 if (request->response_headers())
1059 response_code = request->response_headers()->response_code();
1060
1061 std::string response_ip = request->GetSocketAddress().host();
1062
1063 base::ListValue args;
1064 base::DictionaryValue* dict = new base::DictionaryValue();
1065 ExtractRequestInfo(request, dict);
1066 if (!response_ip.empty())
1067 dict->SetString(keys::kIpKey, response_ip);
1068 dict->SetBoolean(keys::kFromCache, request->was_cached());
1069 dict->SetInteger(keys::kStatusCodeKey, response_code);
1070 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1071 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1072 dict->Set(keys::kResponseHeadersKey,
1073 GetResponseHeadersList(request->response_headers()));
1074 }
1075 args.Append(dict);
1076
1077 DispatchEvent(browser_context, request, listeners, args);
1078 }
1079
1080 void ExtensionWebRequestEventRouter::OnCompleted(void* browser_context,
1081 InfoMap* extension_info_map,
1082 net::URLRequest* request) {
1083 // We hide events from the system context as well as sensitive requests.
1084 // However, if the request first became sensitive after redirecting we have
1085 // already signaled it and thus we have to signal the end of it. This is
1086 // risk-free because the handler cannot modify the request now.
1087 if (!browser_context ||
1088 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1089 !WasSignaled(*request)))
1090 return;
1091
1092 request_time_tracker_->LogRequestEndTime(request->identifier(),
1093 base::Time::Now());
1094
1095 DCHECK(request->status().status() == net::URLRequestStatus::SUCCESS);
1096
1097 DCHECK(!GetAndSetSignaled(request->identifier(), kOnCompleted));
1098
1099 ClearPendingCallbacks(request);
1100
1101 int extra_info_spec = 0;
1102 std::vector<const EventListener*> listeners =
1103 GetMatchingListeners(browser_context, extension_info_map,
1104 keys::kOnCompletedEvent, request, &extra_info_spec);
1105 if (listeners.empty())
1106 return;
1107
1108 // UrlRequestFileJobs do not send headers, so we simulate their behavior.
1109 int response_code = 200;
1110 if (request->response_headers())
1111 response_code = request->response_headers()->response_code();
1112
1113 std::string response_ip = request->GetSocketAddress().host();
1114
1115 base::ListValue args;
1116 base::DictionaryValue* dict = new base::DictionaryValue();
1117 ExtractRequestInfo(request, dict);
1118 dict->SetInteger(keys::kStatusCodeKey, response_code);
1119 if (!response_ip.empty())
1120 dict->SetString(keys::kIpKey, response_ip);
1121 dict->SetBoolean(keys::kFromCache, request->was_cached());
1122 dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
1123 if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
1124 dict->Set(keys::kResponseHeadersKey,
1125 GetResponseHeadersList(request->response_headers()));
1126 }
1127 args.Append(dict);
1128
1129 DispatchEvent(browser_context, request, listeners, args);
1130 }
1131
1132 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1133 void* browser_context,
1134 InfoMap* extension_info_map,
1135 net::URLRequest* request,
1136 bool started) {
1137 // We hide events from the system context as well as sensitive requests.
1138 // However, if the request first became sensitive after redirecting we have
1139 // already signaled it and thus we have to signal the end of it. This is
1140 // risk-free because the handler cannot modify the request now.
1141 if (!browser_context ||
1142 (WebRequestPermissions::HideRequest(extension_info_map, request) &&
1143 !WasSignaled(*request)))
1144 return;
1145
1146 request_time_tracker_->LogRequestEndTime(request->identifier(),
1147 base::Time::Now());
1148
1149 DCHECK(request->status().status() == net::URLRequestStatus::FAILED ||
1150 request->status().status() == net::URLRequestStatus::CANCELED);
1151
1152 DCHECK(!GetAndSetSignaled(request->identifier(), kOnErrorOccurred));
1153
1154 ClearPendingCallbacks(request);
1155
1156 int extra_info_spec = 0;
1157 std::vector<const EventListener*> listeners =
1158 GetMatchingListeners(browser_context, extension_info_map,
1159 web_request::OnErrorOccurred::kEventName, request,
1160 &extra_info_spec);
1161 if (listeners.empty())
1162 return;
1163
1164 base::ListValue args;
1165 base::DictionaryValue* dict = new base::DictionaryValue();
1166 ExtractRequestInfo(request, dict);
1167 if (started) {
1168 std::string response_ip = request->GetSocketAddress().host();
1169 if (!response_ip.empty())
1170 dict->SetString(keys::kIpKey, response_ip);
1171 }
1172 dict->SetBoolean(keys::kFromCache, request->was_cached());
1173 dict->SetString(keys::kErrorKey,
1174 net::ErrorToString(request->status().error()));
1175 args.Append(dict);
1176
1177 DispatchEvent(browser_context, request, listeners, args);
1178 }
1179
1180 void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
1181 void* browser_context, net::URLRequest* request) {
1182 ClearPendingCallbacks(request);
1183
1184 signaled_requests_.erase(request->identifier());
1185
1186 request_time_tracker_->LogRequestEndTime(request->identifier(),
1187 base::Time::Now());
1188 }
1189
1190 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1191 net::URLRequest* request) {
1192 blocked_requests_.erase(request->identifier());
1193 }
1194
1195 bool ExtensionWebRequestEventRouter::DispatchEvent(
1196 void* browser_context,
1197 net::URLRequest* request,
1198 const std::vector<const EventListener*>& listeners,
1199 const base::ListValue& args) {
1200 // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1201 // pairs into a single message sent to a list of sub_event_names.
1202 int num_handlers_blocking = 0;
1203 for (std::vector<const EventListener*>::const_iterator it = listeners.begin();
1204 it != listeners.end(); ++it) {
1205 // Filter out the optional keys that this listener didn't request.
1206 scoped_ptr<base::ListValue> args_filtered(args.DeepCopy());
1207 base::DictionaryValue* dict = NULL;
1208 CHECK(args_filtered->GetDictionary(0, &dict) && dict);
1209 if (!((*it)->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS))
1210 dict->Remove(keys::kRequestHeadersKey, NULL);
1211 if (!((*it)->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS))
1212 dict->Remove(keys::kResponseHeadersKey, NULL);
1213
1214 extensions::EventRouter::DispatchEvent(
1215 (*it)->ipc_sender.get(), browser_context,
1216 (*it)->extension_id, (*it)->sub_event_name,
1217 args_filtered.Pass(),
1218 extensions::EventRouter::USER_GESTURE_UNKNOWN,
1219 extensions::EventFilteringInfo());
1220 if ((*it)->extra_info_spec &
1221 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
1222 (*it)->blocked_requests.insert(request->identifier());
1223 // If this is the first delegate blocking the request, go ahead and log
1224 // it.
1225 if (num_handlers_blocking == 0) {
1226 std::string delegate_info =
1227 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1228 base::UTF8ToUTF16((*it)->extension_name));
1229 // LobAndReport allows extensions that block requests to be displayed in
1230 // the load status bar.
1231 request->LogAndReportBlockedBy(delegate_info.c_str());
1232 }
1233 ++num_handlers_blocking;
1234 }
1235 }
1236
1237 if (num_handlers_blocking > 0) {
1238 blocked_requests_[request->identifier()].request = request;
1239 blocked_requests_[request->identifier()].is_incognito |=
1240 IsIncognitoBrowserContext(browser_context);
1241 blocked_requests_[request->identifier()].num_handlers_blocking +=
1242 num_handlers_blocking;
1243 blocked_requests_[request->identifier()].blocking_time = base::Time::Now();
1244
1245 return true;
1246 }
1247
1248 return false;
1249 }
1250
1251 void ExtensionWebRequestEventRouter::OnEventHandled(
1252 void* browser_context,
1253 const std::string& extension_id,
1254 const std::string& event_name,
1255 const std::string& sub_event_name,
1256 uint64 request_id,
1257 EventResponse* response) {
1258 EventListener listener;
1259 listener.extension_id = extension_id;
1260 listener.sub_event_name = sub_event_name;
1261
1262 // The listener may have been removed (e.g. due to the process going away)
1263 // before we got here.
1264 std::set<EventListener>::iterator found =
1265 listeners_[browser_context][event_name].find(listener);
1266 if (found != listeners_[browser_context][event_name].end())
1267 found->blocked_requests.erase(request_id);
1268
1269 DecrementBlockCount(
1270 browser_context, extension_id, event_name, request_id, response);
1271 }
1272
1273 bool ExtensionWebRequestEventRouter::AddEventListener(
1274 void* browser_context,
1275 const std::string& extension_id,
1276 const std::string& extension_name,
1277 const std::string& event_name,
1278 const std::string& sub_event_name,
1279 const RequestFilter& filter,
1280 int extra_info_spec,
1281 int embedder_process_id,
1282 int webview_instance_id,
1283 base::WeakPtr<IPC::Sender> ipc_sender) {
1284 if (!IsWebRequestEvent(event_name))
1285 return false;
1286
1287 EventListener listener;
1288 listener.extension_id = extension_id;
1289 listener.extension_name = extension_name;
1290 listener.sub_event_name = sub_event_name;
1291 listener.filter = filter;
1292 listener.extra_info_spec = extra_info_spec;
1293 listener.ipc_sender = ipc_sender;
1294 listener.embedder_process_id = embedder_process_id;
1295 listener.webview_instance_id = webview_instance_id;
1296 if (listener.webview_instance_id) {
1297 content::RecordAction(
1298 base::UserMetricsAction("WebView.WebRequest.AddListener"));
1299 }
1300
1301 if (listeners_[browser_context][event_name].count(listener) != 0u) {
1302 // This is likely an abuse of the API by a malicious extension.
1303 return false;
1304 }
1305 listeners_[browser_context][event_name].insert(listener);
1306 return true;
1307 }
1308
1309 void ExtensionWebRequestEventRouter::RemoveEventListener(
1310 void* browser_context,
1311 const std::string& extension_id,
1312 const std::string& sub_event_name) {
1313 std::string event_name =
1314 extensions::EventRouter::GetBaseEventName(sub_event_name);
1315 DCHECK(IsWebRequestEvent(event_name));
1316
1317 EventListener listener;
1318 listener.extension_id = extension_id;
1319 listener.sub_event_name = sub_event_name;
1320
1321 // It's possible for AddEventListener to fail asynchronously. In that case,
1322 // the renderer believes the listener exists, while the browser does not.
1323 // Ignore a RemoveEventListener in that case.
1324 std::set<EventListener>::iterator found =
1325 listeners_[browser_context][event_name].find(listener);
1326 if (found == listeners_[browser_context][event_name].end())
1327 return;
1328
1329 CHECK_EQ(listeners_[browser_context][event_name].count(listener), 1u) <<
1330 "extension=" << extension_id << " event=" << event_name;
1331
1332 // Unblock any request that this event listener may have been blocking.
1333 for (std::set<uint64>::iterator it = found->blocked_requests.begin();
1334 it != found->blocked_requests.end(); ++it) {
1335 DecrementBlockCount(browser_context, extension_id, event_name, *it, NULL);
1336 }
1337
1338 listeners_[browser_context][event_name].erase(listener);
1339
1340 helpers::ClearCacheOnNavigation();
1341 }
1342
1343 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1344 void* browser_context,
1345 const std::string& extension_id,
1346 int embedder_process_id,
1347 int webview_instance_id) {
1348 // Iterate over all listeners of all WebRequest events to delete
1349 // any listeners that belong to the provided <webview>.
1350 ListenerMapForBrowserContext& map_for_browser_context =
1351 listeners_[browser_context];
1352 for (ListenerMapForBrowserContext::iterator event_iter =
1353 map_for_browser_context.begin();
1354 event_iter != map_for_browser_context.end(); ++event_iter) {
1355 std::vector<EventListener> listeners_to_delete;
1356 std::set<EventListener>& listeners = event_iter->second;
1357 for (std::set<EventListener>::iterator listener_iter = listeners.begin();
1358 listener_iter != listeners.end(); ++listener_iter) {
1359 const EventListener& listener = *listener_iter;
1360 if (listener.embedder_process_id == embedder_process_id &&
1361 listener.webview_instance_id == webview_instance_id)
1362 listeners_to_delete.push_back(listener);
1363 }
1364 for (size_t i = 0; i < listeners_to_delete.size(); ++i) {
1365 EventListener& listener = listeners_to_delete[i];
1366 content::BrowserThread::PostTask(
1367 content::BrowserThread::UI,
1368 FROM_HERE,
1369 base::Bind(&RemoveEventListenerOnUI,
1370 browser_context,
1371 listener.sub_event_name,
1372 embedder_process_id,
1373 extension_id));
1374 }
1375 }
1376 }
1377
1378 void ExtensionWebRequestEventRouter::OnOTRBrowserContextCreated(
1379 void* original_browser_context, void* otr_browser_context) {
1380 cross_browser_context_map_[original_browser_context] =
1381 std::make_pair(false, otr_browser_context);
1382 cross_browser_context_map_[otr_browser_context] =
1383 std::make_pair(true, original_browser_context);
1384 }
1385
1386 void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
1387 void* original_browser_context, void* otr_browser_context) {
1388 cross_browser_context_map_.erase(otr_browser_context);
1389 cross_browser_context_map_.erase(original_browser_context);
1390 }
1391
1392 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1393 const base::Closure& callback) {
1394 callbacks_for_page_load_.push_back(callback);
1395 }
1396
1397 bool ExtensionWebRequestEventRouter::IsPageLoad(
1398 net::URLRequest* request) const {
1399 bool is_main_frame = false;
1400 int frame_id = -1;
1401 bool parent_is_main_frame = false;
1402 int parent_frame_id = -1;
1403 int render_process_host_id = -1;
1404 int routing_id = -1;
1405 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1406
1407 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1408 &parent_is_main_frame, &parent_frame_id,
1409 &render_process_host_id,
1410 &routing_id, &resource_type);
1411
1412 return resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
1413 }
1414
1415 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1416 for (CallbacksForPageLoad::const_iterator i =
1417 callbacks_for_page_load_.begin();
1418 i != callbacks_for_page_load_.end(); ++i) {
1419 i->Run();
1420 }
1421 callbacks_for_page_load_.clear();
1422 }
1423
1424 void* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
1425 void* browser_context) const {
1426 CrossBrowserContextMap::const_iterator cross_browser_context =
1427 cross_browser_context_map_.find(browser_context);
1428 if (cross_browser_context == cross_browser_context_map_.end())
1429 return NULL;
1430 return cross_browser_context->second.second;
1431 }
1432
1433 bool ExtensionWebRequestEventRouter::IsIncognitoBrowserContext(
1434 void* browser_context) const {
1435 CrossBrowserContextMap::const_iterator cross_browser_context =
1436 cross_browser_context_map_.find(browser_context);
1437 if (cross_browser_context == cross_browser_context_map_.end())
1438 return false;
1439 return cross_browser_context->second.first;
1440 }
1441
1442 bool ExtensionWebRequestEventRouter::WasSignaled(
1443 const net::URLRequest& request) const {
1444 SignaledRequestMap::const_iterator flag =
1445 signaled_requests_.find(request.identifier());
1446 return (flag != signaled_requests_.end()) && (flag->second != 0);
1447 }
1448
1449 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1450 void* browser_context,
1451 net::URLRequest* request,
1452 InfoMap* extension_info_map,
1453 bool crosses_incognito,
1454 const std::string& event_name,
1455 const GURL& url,
1456 int render_process_host_id,
1457 int routing_id,
1458 ResourceType resource_type,
1459 bool is_async_request,
1460 bool is_request_from_extension,
1461 int* extra_info_spec,
1462 std::vector<const ExtensionWebRequestEventRouter::EventListener*>*
1463 matching_listeners) {
1464 std::string web_request_event_name(event_name);
1465 extensions::WebViewRendererState::WebViewInfo web_view_info;
1466 bool is_web_view_guest = extensions::WebViewRendererState::GetInstance()->
1467 GetInfo(render_process_host_id, routing_id, &web_view_info);
1468 if (is_web_view_guest) {
1469 web_request_event_name.replace(
1470 0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
1471 }
1472
1473 std::set<EventListener>& listeners =
1474 listeners_[browser_context][web_request_event_name];
1475 for (std::set<EventListener>::iterator it = listeners.begin();
1476 it != listeners.end(); ++it) {
1477 if (!it->ipc_sender.get()) {
1478 // The IPC sender has been deleted. This listener will be removed soon
1479 // via a call to RemoveEventListener. For now, just skip it.
1480 continue;
1481 }
1482
1483 if (is_web_view_guest &&
1484 (it->embedder_process_id != web_view_info.embedder_process_id ||
1485 it->webview_instance_id != web_view_info.instance_id))
1486 continue;
1487
1488 if (!it->filter.urls.is_empty() && !it->filter.urls.MatchesURL(url))
1489 continue;
1490 if (web_request_event_router_delegate_ &&
1491 web_request_event_router_delegate_->OnGetMatchingListenersImplCheck(
1492 it->filter.tab_id, it->filter.window_id, request))
1493 continue;
1494 if (!it->filter.types.empty() &&
1495 std::find(it->filter.types.begin(), it->filter.types.end(),
1496 resource_type) == it->filter.types.end())
1497 continue;
1498
1499 if (!is_web_view_guest && !WebRequestPermissions::CanExtensionAccessURL(
1500 extension_info_map, it->extension_id, url, crosses_incognito,
1501 WebRequestPermissions::REQUIRE_HOST_PERMISSION))
1502 continue;
1503
1504 bool blocking_listener =
1505 (it->extra_info_spec &
1506 (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
1507
1508 // We do not want to notify extensions about XHR requests that are
1509 // triggered by themselves. This is a workaround to prevent deadlocks
1510 // in case of synchronous XHR requests that block the extension renderer
1511 // and therefore prevent the extension from processing the request
1512 // handler. This is only a problem for blocking listeners.
1513 // http://crbug.com/105656
1514 bool synchronous_xhr_from_extension =
1515 !is_async_request && is_request_from_extension &&
1516 resource_type == content::RESOURCE_TYPE_XHR;
1517
1518 // Only send webRequest events for URLs the extension has access to.
1519 if (blocking_listener && synchronous_xhr_from_extension)
1520 continue;
1521
1522 matching_listeners->push_back(&(*it));
1523 *extra_info_spec |= it->extra_info_spec;
1524 }
1525 }
1526
1527 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1528 ExtensionWebRequestEventRouter::GetMatchingListeners(
1529 void* browser_context,
1530 InfoMap* extension_info_map,
1531 const std::string& event_name,
1532 net::URLRequest* request,
1533 int* extra_info_spec) {
1534 // TODO(mpcomplete): handle browser_context == NULL (should collect all
1535 // listeners).
1536 *extra_info_spec = 0;
1537
1538 bool is_main_frame = false;
1539 int frame_id = -1;
1540 bool parent_is_main_frame = false;
1541 int parent_frame_id = -1;
1542 int render_process_host_id = -1;
1543 int routing_id = -1;
1544 ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
1545 const GURL& url = request->url();
1546
1547 ExtractRequestInfoDetails(request, &is_main_frame, &frame_id,
1548 &parent_is_main_frame, &parent_frame_id,
1549 &render_process_host_id,
1550 &routing_id, &resource_type);
1551
1552 std::vector<const ExtensionWebRequestEventRouter::EventListener*>
1553 matching_listeners;
1554
1555 bool is_request_from_extension =
1556 IsRequestFromExtension(request, extension_info_map);
1557
1558 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
1559 // We are conservative here and assume requests are asynchronous in case
1560 // we don't have an info object. We don't want to risk a deadlock.
1561 bool is_async_request = !info || info->IsAsync();
1562
1563 GetMatchingListenersImpl(
1564 browser_context, request, extension_info_map, false, event_name,
1565 url, render_process_host_id, routing_id, resource_type,
1566 is_async_request, is_request_from_extension, extra_info_spec,
1567 &matching_listeners);
1568 void* cross_browser_context = GetCrossBrowserContext(browser_context);
1569 if (cross_browser_context) {
1570 GetMatchingListenersImpl(
1571 cross_browser_context, request, extension_info_map, true, event_name,
1572 url, render_process_host_id, routing_id, resource_type,
1573 is_async_request, is_request_from_extension, extra_info_spec,
1574 &matching_listeners);
1575 }
1576
1577 return matching_listeners;
1578 }
1579
1580 namespace {
1581
1582 helpers::EventResponseDelta* CalculateDelta(
1583 ExtensionWebRequestEventRouter::BlockedRequest* blocked_request,
1584 ExtensionWebRequestEventRouter::EventResponse* response) {
1585 switch (blocked_request->event) {
1586 case ExtensionWebRequestEventRouter::kOnBeforeRequest:
1587 return helpers::CalculateOnBeforeRequestDelta(
1588 response->extension_id, response->extension_install_time,
1589 response->cancel, response->new_url);
1590 case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders: {
1591 net::HttpRequestHeaders* old_headers = blocked_request->request_headers;
1592 net::HttpRequestHeaders* new_headers = response->request_headers.get();
1593 return helpers::CalculateOnBeforeSendHeadersDelta(
1594 response->extension_id, response->extension_install_time,
1595 response->cancel, old_headers, new_headers);
1596 }
1597 case ExtensionWebRequestEventRouter::kOnHeadersReceived: {
1598 const net::HttpResponseHeaders* old_headers =
1599 blocked_request->original_response_headers.get();
1600 helpers::ResponseHeaders* new_headers =
1601 response->response_headers.get();
1602 return helpers::CalculateOnHeadersReceivedDelta(
1603 response->extension_id,
1604 response->extension_install_time,
1605 response->cancel,
1606 response->new_url,
1607 old_headers,
1608 new_headers);
1609 }
1610 case ExtensionWebRequestEventRouter::kOnAuthRequired:
1611 return helpers::CalculateOnAuthRequiredDelta(
1612 response->extension_id, response->extension_install_time,
1613 response->cancel, &response->auth_credentials);
1614 default:
1615 NOTREACHED();
1616 break;
1617 }
1618 return NULL;
1619 }
1620
1621 base::Value* SerializeResponseHeaders(const helpers::ResponseHeaders& headers) {
1622 scoped_ptr<base::ListValue> serialized_headers(new base::ListValue());
1623 for (helpers::ResponseHeaders::const_iterator i = headers.begin();
1624 i != headers.end(); ++i) {
1625 serialized_headers->Append(
1626 helpers::CreateHeaderDictionary(i->first, i->second));
1627 }
1628 return serialized_headers.release();
1629 }
1630
1631 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
1632 // base::ListValue which summarizes the changes made. This is templated since
1633 // the two types (request/response) are different but contain essentially the
1634 // same fields.
1635 template<typename CookieType>
1636 base::ListValue* SummarizeCookieModifications(
1637 const std::vector<linked_ptr<CookieType> >& modifications) {
1638 scoped_ptr<base::ListValue> cookie_modifications(new base::ListValue());
1639 for (typename std::vector<linked_ptr<CookieType> >::const_iterator i =
1640 modifications.begin();
1641 i != modifications.end(); ++i) {
1642 scoped_ptr<base::DictionaryValue> summary(new base::DictionaryValue());
1643 const CookieType& mod = *i->get();
1644 switch (mod.type) {
1645 case helpers::ADD:
1646 summary->SetString(activitylog::kCookieModificationTypeKey,
1647 activitylog::kCookieModificationAdd);
1648 break;
1649 case helpers::EDIT:
1650 summary->SetString(activitylog::kCookieModificationTypeKey,
1651 activitylog::kCookieModificationEdit);
1652 break;
1653 case helpers::REMOVE:
1654 summary->SetString(activitylog::kCookieModificationTypeKey,
1655 activitylog::kCookieModificationRemove);
1656 break;
1657 }
1658 if (mod.filter) {
1659 if (mod.filter->name)
1660 summary->SetString(activitylog::kCookieFilterNameKey,
1661 *mod.modification->name);
1662 if (mod.filter->domain)
1663 summary->SetString(activitylog::kCookieFilterDomainKey,
1664 *mod.modification->name);
1665 }
1666 if (mod.modification) {
1667 if (mod.modification->name)
1668 summary->SetString(activitylog::kCookieModDomainKey,
1669 *mod.modification->name);
1670 if (mod.modification->domain)
1671 summary->SetString(activitylog::kCookieModDomainKey,
1672 *mod.modification->name);
1673 }
1674 cookie_modifications->Append(summary.release());
1675 }
1676 return cookie_modifications.release();
1677 }
1678
1679 // Converts an EventResponseDelta object to a dictionary value suitable for the
1680 // activity log.
1681 scoped_ptr<base::DictionaryValue> SummarizeResponseDelta(
1682 const std::string& event_name,
1683 const helpers::EventResponseDelta& delta) {
1684 scoped_ptr<base::DictionaryValue> details(new base::DictionaryValue());
1685 if (delta.cancel) {
1686 details->SetBoolean(activitylog::kCancelKey, true);
1687 }
1688 if (!delta.new_url.is_empty()) {
1689 details->SetString(activitylog::kNewUrlKey, delta.new_url.spec());
1690 }
1691
1692 scoped_ptr<base::ListValue> modified_headers(new base::ListValue());
1693 net::HttpRequestHeaders::Iterator iter(delta.modified_request_headers);
1694 while (iter.GetNext()) {
1695 modified_headers->Append(
1696 helpers::CreateHeaderDictionary(iter.name(), iter.value()));
1697 }
1698 if (!modified_headers->empty()) {
1699 details->Set(activitylog::kModifiedRequestHeadersKey,
1700 modified_headers.release());
1701 }
1702
1703 scoped_ptr<base::ListValue> deleted_headers(new base::ListValue());
1704 deleted_headers->AppendStrings(delta.deleted_request_headers);
1705 if (!deleted_headers->empty()) {
1706 details->Set(activitylog::kDeletedRequestHeadersKey,
1707 deleted_headers.release());
1708 }
1709
1710 if (!delta.added_response_headers.empty()) {
1711 details->Set(activitylog::kAddedRequestHeadersKey,
1712 SerializeResponseHeaders(delta.added_response_headers));
1713 }
1714 if (!delta.deleted_response_headers.empty()) {
1715 details->Set(activitylog::kDeletedResponseHeadersKey,
1716 SerializeResponseHeaders(delta.deleted_response_headers));
1717 }
1718 if (delta.auth_credentials) {
1719 details->SetString(activitylog::kAuthCredentialsKey,
1720 base::UTF16ToUTF8(
1721 delta.auth_credentials->username()) + ":*");
1722 }
1723
1724 if (!delta.response_cookie_modifications.empty()) {
1725 details->Set(
1726 activitylog::kResponseCookieModificationsKey,
1727 SummarizeCookieModifications(delta.response_cookie_modifications));
1728 }
1729
1730 return details.Pass();
1731 }
1732
1733 } // namespace
1734
1735 void ExtensionWebRequestEventRouter::LogExtensionActivity(
1736 void* browser_context_id,
1737 bool is_incognito,
1738 const std::string& extension_id,
1739 const GURL& url,
1740 const std::string& api_call,
1741 scoped_ptr<base::DictionaryValue> details) {
1742 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
1743 BrowserThread::PostTask(
1744 BrowserThread::UI,
1745 FROM_HERE,
1746 base::Bind(&ExtensionWebRequestEventRouter::LogExtensionActivity,
1747 base::Unretained(this),
1748 browser_context_id,
1749 is_incognito,
1750 extension_id,
1751 url,
1752 api_call,
1753 base::Passed(&details)));
1754 } else {
1755 if (web_request_event_router_delegate_) {
1756 web_request_event_router_delegate_->LogExtensionActivity(
1757 reinterpret_cast<content::BrowserContext*>(browser_context_id),
1758 is_incognito, extension_id, url, api_call, details.Pass());
1759 }
1760 }
1761 }
1762
1763 void ExtensionWebRequestEventRouter::DecrementBlockCount(
1764 void* browser_context,
1765 const std::string& extension_id,
1766 const std::string& event_name,
1767 uint64 request_id,
1768 EventResponse* response) {
1769 scoped_ptr<EventResponse> response_scoped(response);
1770
1771 // It's possible that this request was deleted, or cancelled by a previous
1772 // event handler. If so, ignore this response.
1773 if (blocked_requests_.find(request_id) == blocked_requests_.end())
1774 return;
1775
1776 BlockedRequest& blocked_request = blocked_requests_[request_id];
1777 int num_handlers_blocking = --blocked_request.num_handlers_blocking;
1778 CHECK_GE(num_handlers_blocking, 0);
1779
1780 if (response) {
1781 helpers::EventResponseDelta* delta =
1782 CalculateDelta(&blocked_request, response);
1783
1784 LogExtensionActivity(browser_context,
1785 blocked_request.is_incognito,
1786 extension_id,
1787 blocked_request.request->url(),
1788 event_name,
1789 SummarizeResponseDelta(event_name, *delta));
1790
1791 blocked_request.response_deltas.push_back(
1792 linked_ptr<helpers::EventResponseDelta>(delta));
1793 }
1794
1795 base::TimeDelta block_time =
1796 base::Time::Now() - blocked_request.blocking_time;
1797 if (!extension_id.empty()) {
1798 request_time_tracker_->IncrementExtensionBlockTime(
1799 extension_id, request_id, block_time);
1800 } else {
1801 // |extension_id| is empty for requests blocked on startup waiting for the
1802 // declarative rules to be read from disk.
1803 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayStartup", block_time);
1804 }
1805
1806 if (num_handlers_blocking == 0) {
1807 blocked_request.request->LogUnblocked();
1808 ExecuteDeltas(browser_context, request_id, true);
1809 } else {
1810 // Update the URLRequest to make sure it's tagged with an extension that's
1811 // still blocking it. This may end up being the same extension as before.
1812 std::set<EventListener>& listeners =
1813 listeners_[browser_context][event_name];
1814
1815 for (std::set<EventListener>::iterator it = listeners.begin();
1816 it != listeners.end(); ++it) {
1817 if (it->blocked_requests.count(request_id) == 0)
1818 continue;
1819 std::string delegate_info =
1820 l10n_util::GetStringFUTF8(IDS_LOAD_STATE_PARAMETER_EXTENSION,
1821 base::UTF8ToUTF16(it->extension_name));
1822 blocked_request.request->LogAndReportBlockedBy(delegate_info.c_str());
1823 break;
1824 }
1825 }
1826 }
1827
1828 void ExtensionWebRequestEventRouter::SendMessages(
1829 void* browser_context,
1830 const BlockedRequest& blocked_request) {
1831 const helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1832 for (helpers::EventResponseDeltas::const_iterator delta = deltas.begin();
1833 delta != deltas.end(); ++delta) {
1834 const std::set<std::string>& messages = (*delta)->messages_to_extension;
1835 for (std::set<std::string>::const_iterator message = messages.begin();
1836 message != messages.end(); ++message) {
1837 scoped_ptr<base::DictionaryValue> argument(new base::DictionaryValue);
1838 ExtractRequestInfo(blocked_request.request, argument.get());
1839 extensions::WebViewRendererState::WebViewInfo web_view_info;
1840 bool is_web_view_guest = GetWebViewInfo(blocked_request.request,
1841 &web_view_info);
1842 argument->SetString(keys::kMessageKey, *message);
1843 argument->SetString(keys::kStageKey,
1844 GetRequestStageAsString(blocked_request.event));
1845
1846 BrowserThread::PostTask(
1847 BrowserThread::UI,
1848 FROM_HERE,
1849 base::Bind(&SendOnMessageEventOnUI,
1850 browser_context,
1851 (*delta)->extension_id,
1852 is_web_view_guest,
1853 web_view_info,
1854 base::Passed(&argument)));
1855 }
1856 }
1857 }
1858
1859 int ExtensionWebRequestEventRouter::ExecuteDeltas(
1860 void* browser_context,
1861 uint64 request_id,
1862 bool call_callback) {
1863 BlockedRequest& blocked_request = blocked_requests_[request_id];
1864 CHECK(blocked_request.num_handlers_blocking == 0);
1865 helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
1866 base::TimeDelta block_time =
1867 base::Time::Now() - blocked_request.blocking_time;
1868 request_time_tracker_->IncrementTotalBlockTime(request_id, block_time);
1869
1870 bool credentials_set = false;
1871
1872 deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
1873 WarningSet warnings;
1874
1875 bool canceled = false;
1876 helpers::MergeCancelOfResponses(
1877 blocked_request.response_deltas,
1878 &canceled,
1879 blocked_request.net_log);
1880
1881 if (blocked_request.event == kOnBeforeRequest) {
1882 CHECK(!blocked_request.callback.is_null());
1883 helpers::MergeOnBeforeRequestResponses(
1884 blocked_request.response_deltas,
1885 blocked_request.new_url,
1886 &warnings,
1887 blocked_request.net_log);
1888 } else if (blocked_request.event == kOnBeforeSendHeaders) {
1889 CHECK(!blocked_request.callback.is_null());
1890 helpers::MergeOnBeforeSendHeadersResponses(
1891 blocked_request.response_deltas,
1892 blocked_request.request_headers,
1893 &warnings,
1894 blocked_request.net_log);
1895 } else if (blocked_request.event == kOnHeadersReceived) {
1896 CHECK(!blocked_request.callback.is_null());
1897 helpers::MergeOnHeadersReceivedResponses(
1898 blocked_request.response_deltas,
1899 blocked_request.original_response_headers.get(),
1900 blocked_request.override_response_headers,
1901 blocked_request.new_url,
1902 &warnings,
1903 blocked_request.net_log);
1904 } else if (blocked_request.event == kOnAuthRequired) {
1905 CHECK(blocked_request.callback.is_null());
1906 CHECK(!blocked_request.auth_callback.is_null());
1907 credentials_set = helpers::MergeOnAuthRequiredResponses(
1908 blocked_request.response_deltas,
1909 blocked_request.auth_credentials,
1910 &warnings,
1911 blocked_request.net_log);
1912 } else {
1913 NOTREACHED();
1914 }
1915
1916 SendMessages(browser_context, blocked_request);
1917
1918 if (!warnings.empty()) {
1919 BrowserThread::PostTask(
1920 BrowserThread::UI,
1921 FROM_HERE,
1922 base::Bind(&WarningService::NotifyWarningsOnUI,
1923 browser_context, warnings));
1924 }
1925
1926 if (canceled) {
1927 request_time_tracker_->SetRequestCanceled(request_id);
1928 } else if (blocked_request.new_url &&
1929 !blocked_request.new_url->is_empty()) {
1930 request_time_tracker_->SetRequestRedirected(request_id);
1931 }
1932
1933 // This triggers onErrorOccurred if canceled is true.
1934 int rv = canceled ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
1935
1936 if (!blocked_request.callback.is_null()) {
1937 net::CompletionCallback callback = blocked_request.callback;
1938 // Ensure that request is removed before callback because the callback
1939 // might trigger the next event.
1940 blocked_requests_.erase(request_id);
1941 if (call_callback)
1942 callback.Run(rv);
1943 } else if (!blocked_request.auth_callback.is_null()) {
1944 net::NetworkDelegate::AuthRequiredResponse response =
1945 net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1946 if (canceled) {
1947 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
1948 } else if (credentials_set) {
1949 response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH;
1950 }
1951 net::NetworkDelegate::AuthCallback callback = blocked_request.auth_callback;
1952 blocked_requests_.erase(request_id);
1953 if (call_callback)
1954 callback.Run(response);
1955 } else {
1956 blocked_requests_.erase(request_id);
1957 }
1958 return rv;
1959 }
1960
1961 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
1962 void* browser_context,
1963 InfoMap* extension_info_map,
1964 const std::string& event_name,
1965 net::URLRequest* request,
1966 extensions::RequestStage request_stage,
1967 const net::HttpResponseHeaders* original_response_headers) {
1968 extensions::WebViewRendererState::WebViewInfo web_view_info;
1969 bool is_web_view_guest = GetWebViewInfo(request, &web_view_info);
1970
1971 extensions::RulesRegistry::WebViewKey webview_key(
1972 is_web_view_guest ? web_view_info.embedder_process_id : 0,
1973 is_web_view_guest ? web_view_info.instance_id : 0);
1974 RulesRegistryKey rules_key(browser_context, webview_key);
1975 // If this check fails, check that the active stages are up-to-date in
1976 // extensions/browser/api/declarative_webrequest/request_stage.h .
1977 DCHECK(request_stage & extensions::kActiveStages);
1978
1979 // Rules of the current |browser_context| may apply but we need to check also
1980 // whether there are applicable rules from extensions whose background page
1981 // spans from regular to incognito mode.
1982
1983 // First parameter identifies the registry, the second indicates whether the
1984 // registry belongs to the cross browser_context.
1985 typedef std::pair<extensions::WebRequestRulesRegistry*, bool>
1986 RelevantRegistry;
1987 typedef std::vector<RelevantRegistry> RelevantRegistries;
1988 RelevantRegistries relevant_registries;
1989
1990 if (rules_registries_.find(rules_key) != rules_registries_.end()) {
1991 relevant_registries.push_back(
1992 std::make_pair(rules_registries_[rules_key].get(), false));
1993 }
1994
1995 void* cross_browser_context = GetCrossBrowserContext(browser_context);
1996 RulesRegistryKey cross_browser_context_rules_key(
1997 cross_browser_context, webview_key);
1998 if (cross_browser_context &&
1999 rules_registries_.find(cross_browser_context_rules_key) !=
2000 rules_registries_.end()) {
2001 relevant_registries.push_back(
2002 std::make_pair(
2003 rules_registries_[cross_browser_context_rules_key].get(), true));
2004 }
2005
2006 // The following block is experimentally enabled and its impact on load time
2007 // logged with UMA Extensions.NetworkDelayRegistryLoad. crbug.com/175961
2008 for (RelevantRegistries::iterator i = relevant_registries.begin();
2009 i != relevant_registries.end(); ++i) {
2010 extensions::WebRequestRulesRegistry* rules_registry = i->first;
2011 if (!rules_registry->ready().is_signaled()) {
2012 // The rules registry is still loading. Block this request until it
2013 // finishes.
2014 rules_registry->ready().Post(
2015 FROM_HERE,
2016 base::Bind(&ExtensionWebRequestEventRouter::OnRulesRegistryReady,
2017 AsWeakPtr(),
2018 browser_context,
2019 event_name,
2020 request->identifier(),
2021 request_stage));
2022 blocked_requests_[request->identifier()].num_handlers_blocking++;
2023 blocked_requests_[request->identifier()].request = request;
2024 blocked_requests_[request->identifier()].is_incognito |=
2025 IsIncognitoBrowserContext(browser_context);
2026 blocked_requests_[request->identifier()].blocking_time =
2027 base::Time::Now();
2028 blocked_requests_[request->identifier()].original_response_headers =
2029 original_response_headers;
2030 blocked_requests_[request->identifier()].extension_info_map =
2031 extension_info_map;
2032 return true;
2033 }
2034 }
2035
2036 base::Time start = base::Time::Now();
2037
2038 bool deltas_created = false;
2039 for (RelevantRegistries::iterator i = relevant_registries.begin();
2040 i != relevant_registries.end(); ++i) {
2041 extensions::WebRequestRulesRegistry* rules_registry =
2042 i->first;
2043 helpers::EventResponseDeltas result =
2044 rules_registry->CreateDeltas(
2045 extension_info_map,
2046 extensions::WebRequestData(
2047 request, request_stage, original_response_headers),
2048 i->second);
2049
2050 if (!result.empty()) {
2051 helpers::EventResponseDeltas& deltas =
2052 blocked_requests_[request->identifier()].response_deltas;
2053 deltas.insert(deltas.end(), result.begin(), result.end());
2054 deltas_created = true;
2055 }
2056 }
2057
2058 base::TimeDelta elapsed_time = start - base::Time::Now();
2059 UMA_HISTOGRAM_TIMES("Extensions.DeclarativeWebRequestNetworkDelay",
2060 elapsed_time);
2061
2062 return deltas_created;
2063 }
2064
2065 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2066 void* browser_context,
2067 const std::string& event_name,
2068 uint64 request_id,
2069 extensions::RequestStage request_stage) {
2070 // It's possible that this request was deleted, or cancelled by a previous
2071 // event handler. If so, ignore this response.
2072 if (blocked_requests_.find(request_id) == blocked_requests_.end())
2073 return;
2074
2075 BlockedRequest& blocked_request = blocked_requests_[request_id];
2076 base::TimeDelta block_time =
2077 base::Time::Now() - blocked_request.blocking_time;
2078 UMA_HISTOGRAM_TIMES("Extensions.NetworkDelayRegistryLoad", block_time);
2079
2080 ProcessDeclarativeRules(browser_context,
2081 blocked_request.extension_info_map,
2082 event_name,
2083 blocked_request.request,
2084 request_stage,
2085 blocked_request.original_response_headers.get());
2086 // Reset to NULL so that nobody relies on this being set.
2087 blocked_request.extension_info_map = NULL;
2088 DecrementBlockCount(
2089 browser_context, std::string(), event_name, request_id, NULL);
2090 }
2091
2092 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64 request_id,
2093 EventTypes event_type) {
2094 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2095 if (iter == signaled_requests_.end()) {
2096 signaled_requests_[request_id] = event_type;
2097 return false;
2098 }
2099 bool was_signaled_before = (iter->second & event_type) != 0;
2100 iter->second |= event_type;
2101 return was_signaled_before;
2102 }
2103
2104 void ExtensionWebRequestEventRouter::ClearSignaled(uint64 request_id,
2105 EventTypes event_type) {
2106 SignaledRequestMap::iterator iter = signaled_requests_.find(request_id);
2107 if (iter == signaled_requests_.end())
2108 return;
2109 iter->second &= ~event_type;
2110 }
2111
2112 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2113 //
2114 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2115 // of WebKit at the time of the next page load (top level navigation event).
2116 // This quota heuristic is intended to limit the number of times the cache is
2117 // cleared by an extension.
2118 //
2119 // As we want to account for the number of times the cache is really cleared
2120 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2121 // called), we cannot decide whether a call of
2122 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2123 // time it is called. Instead we only decrement the bucket counter at the time
2124 // when the cache is cleared (when page loads happen).
2125 class ClearCacheQuotaHeuristic : public extensions::QuotaLimitHeuristic {
2126 public:
2127 ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
2128 : QuotaLimitHeuristic(
2129 config,
2130 map,
2131 "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2132 callback_registered_(false),
2133 weak_ptr_factory_(this) {}
2134 virtual ~ClearCacheQuotaHeuristic() {}
2135 virtual bool Apply(Bucket* bucket,
2136 const base::TimeTicks& event_time) OVERRIDE;
2137
2138 private:
2139 // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2140 // load.
2141 //
2142 // We don't need to take care of the life time of |bucket|: It is owned by the
2143 // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2144 // long as |this| exists, the respective BucketMapper and its bucket will
2145 // exist as well.
2146 void OnPageLoad(Bucket* bucket);
2147
2148 // Flag to prevent that we register more than one call back in-between
2149 // clearing the cache.
2150 bool callback_registered_;
2151
2152 base::WeakPtrFactory<ClearCacheQuotaHeuristic> weak_ptr_factory_;
2153
2154 DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic);
2155 };
2156
2157 bool ClearCacheQuotaHeuristic::Apply(Bucket* bucket,
2158 const base::TimeTicks& event_time) {
2159 if (event_time > bucket->expiration())
2160 bucket->Reset(config(), event_time);
2161
2162 // Call bucket->DeductToken() on a new page load, this is when
2163 // webRequest.handlerBehaviorChanged() clears the cache.
2164 if (!callback_registered_) {
2165 ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2166 base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad,
2167 weak_ptr_factory_.GetWeakPtr(),
2168 bucket));
2169 callback_registered_ = true;
2170 }
2171
2172 // We only check whether tokens are left here. Deducting a token happens in
2173 // OnPageLoad().
2174 return bucket->has_tokens();
2175 }
2176
2177 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket* bucket) {
2178 callback_registered_ = false;
2179 bucket->DeductToken();
2180 }
2181
2182 bool WebRequestInternalAddEventListenerFunction::RunSync() {
2183 // Argument 0 is the callback, which we don't use here.
2184 ExtensionWebRequestEventRouter::RequestFilter filter;
2185 base::DictionaryValue* value = NULL;
2186 error_.clear();
2187 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
2188 // Failure + an empty error string means a fatal error.
2189 EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error_) ||
2190 !error_.empty());
2191 if (!error_.empty())
2192 return false;
2193
2194 int extra_info_spec = 0;
2195 if (HasOptionalArgument(2)) {
2196 base::ListValue* value = NULL;
2197 EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
2198 EXTENSION_FUNCTION_VALIDATE(
2199 ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
2200 *value, &extra_info_spec));
2201 }
2202
2203 std::string event_name;
2204 EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
2205
2206 std::string sub_event_name;
2207 EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
2208
2209 int webview_instance_id = 0;
2210 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &webview_instance_id));
2211
2212 base::WeakPtr<extensions::ExtensionMessageFilter> ipc_sender =
2213 ipc_sender_weak();
2214 int embedder_process_id =
2215 ipc_sender.get() ? ipc_sender->render_process_id() : -1;
2216
2217 const Extension* extension =
2218 extension_info_map()->extensions().GetByID(extension_id());
2219 std::string extension_name = extension ? extension->name() : extension_id();
2220
2221 bool is_web_view_guest = webview_instance_id != 0;
2222 // We check automatically whether the extension has the 'webRequest'
2223 // permission. For blocking calls we require the additional permission
2224 // 'webRequestBlocking'.
2225 if ((!is_web_view_guest &&
2226 extra_info_spec &
2227 (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
2228 ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) &&
2229 !extension->permissions_data()->HasAPIPermission(
2230 extensions::APIPermission::kWebRequestBlocking)) {
2231 error_ = keys::kBlockingPermissionRequired;
2232 return false;
2233 }
2234
2235 // We allow to subscribe to patterns that are broader than the host
2236 // permissions. E.g., we could subscribe to http://www.example.com/*
2237 // while having host permissions for http://www.example.com/foo/* and
2238 // http://www.example.com/bar/*.
2239 // For this reason we do only a coarse check here to warn the extension
2240 // developer if he does something obviously wrong.
2241 if (!is_web_view_guest &&
2242 extension->permissions_data()->GetEffectiveHostPermissions().is_empty()) {
2243 error_ = keys::kHostPermissionsRequired;
2244 return false;
2245 }
2246
2247 bool success =
2248 ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
2249 profile_id(), extension_id(), extension_name,
2250 event_name, sub_event_name, filter, extra_info_spec,
2251 embedder_process_id, webview_instance_id, ipc_sender_weak());
2252 EXTENSION_FUNCTION_VALIDATE(success);
2253
2254 helpers::ClearCacheOnNavigation();
2255
2256 BrowserThread::PostTask(BrowserThread::UI,
2257 FROM_HERE,
2258 base::Bind(&helpers::NotifyWebRequestAPIUsed,
2259 profile_id(),
2260 make_scoped_refptr(extension)));
2261
2262 return true;
2263 }
2264
2265 void WebRequestInternalEventHandledFunction::RespondWithError(
2266 const std::string& event_name,
2267 const std::string& sub_event_name,
2268 uint64 request_id,
2269 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response,
2270 const std::string& error) {
2271 error_ = error;
2272 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2273 profile_id(),
2274 extension_id(),
2275 event_name,
2276 sub_event_name,
2277 request_id,
2278 response.release());
2279 }
2280
2281 bool WebRequestInternalEventHandledFunction::RunSync() {
2282 std::string event_name;
2283 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
2284
2285 std::string sub_event_name;
2286 EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
2287
2288 std::string request_id_str;
2289 EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
2290 uint64 request_id;
2291 EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
2292 &request_id));
2293
2294 scoped_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
2295 if (HasOptionalArgument(3)) {
2296 base::DictionaryValue* value = NULL;
2297 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(3, &value));
2298
2299 if (!value->empty()) {
2300 base::Time install_time =
2301 extension_info_map()->GetInstallTime(extension_id());
2302 response.reset(new ExtensionWebRequestEventRouter::EventResponse(
2303 extension_id(), install_time));
2304 }
2305
2306 if (value->HasKey("cancel")) {
2307 // Don't allow cancel mixed with other keys.
2308 if (value->size() != 1) {
2309 RespondWithError(event_name,
2310 sub_event_name,
2311 request_id,
2312 response.Pass(),
2313 keys::kInvalidBlockingResponse);
2314 return false;
2315 }
2316
2317 bool cancel = false;
2318 EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
2319 response->cancel = cancel;
2320 }
2321
2322 if (value->HasKey("redirectUrl")) {
2323 std::string new_url_str;
2324 EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
2325 &new_url_str));
2326 response->new_url = GURL(new_url_str);
2327 if (!response->new_url.is_valid()) {
2328 RespondWithError(event_name,
2329 sub_event_name,
2330 request_id,
2331 response.Pass(),
2332 ErrorUtils::FormatErrorMessage(
2333 keys::kInvalidRedirectUrl, new_url_str));
2334 return false;
2335 }
2336 }
2337
2338 const bool hasRequestHeaders = value->HasKey("requestHeaders");
2339 const bool hasResponseHeaders = value->HasKey("responseHeaders");
2340 if (hasRequestHeaders || hasResponseHeaders) {
2341 if (hasRequestHeaders && hasResponseHeaders) {
2342 // Allow only one of the keys, not both.
2343 RespondWithError(event_name,
2344 sub_event_name,
2345 request_id,
2346 response.Pass(),
2347 keys::kInvalidHeaderKeyCombination);
2348 return false;
2349 }
2350
2351 base::ListValue* headers_value = NULL;
2352 scoped_ptr<net::HttpRequestHeaders> request_headers;
2353 scoped_ptr<helpers::ResponseHeaders> response_headers;
2354 if (hasRequestHeaders) {
2355 request_headers.reset(new net::HttpRequestHeaders());
2356 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kRequestHeadersKey,
2357 &headers_value));
2358 } else {
2359 response_headers.reset(new helpers::ResponseHeaders());
2360 EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kResponseHeadersKey,
2361 &headers_value));
2362 }
2363
2364 for (size_t i = 0; i < headers_value->GetSize(); ++i) {
2365 base::DictionaryValue* header_value = NULL;
2366 std::string name;
2367 std::string value;
2368 EXTENSION_FUNCTION_VALIDATE(
2369 headers_value->GetDictionary(i, &header_value));
2370 if (!FromHeaderDictionary(header_value, &name, &value)) {
2371 std::string serialized_header;
2372 base::JSONWriter::Write(header_value, &serialized_header);
2373 RespondWithError(event_name,
2374 sub_event_name,
2375 request_id,
2376 response.Pass(),
2377 ErrorUtils::FormatErrorMessage(keys::kInvalidHeader,
2378 serialized_header));
2379 return false;
2380 }
2381 if (!net::HttpUtil::IsValidHeaderName(name)) {
2382 RespondWithError(event_name,
2383 sub_event_name,
2384 request_id,
2385 response.Pass(),
2386 keys::kInvalidHeaderName);
2387 return false;
2388 }
2389 if (!net::HttpUtil::IsValidHeaderValue(value)) {
2390 RespondWithError(event_name,
2391 sub_event_name,
2392 request_id,
2393 response.Pass(),
2394 ErrorUtils::FormatErrorMessage(
2395 keys::kInvalidHeaderValue, name));
2396 return false;
2397 }
2398 if (hasRequestHeaders)
2399 request_headers->SetHeader(name, value);
2400 else
2401 response_headers->push_back(helpers::ResponseHeader(name, value));
2402 }
2403 if (hasRequestHeaders)
2404 response->request_headers.reset(request_headers.release());
2405 else
2406 response->response_headers.reset(response_headers.release());
2407 }
2408
2409 if (value->HasKey(keys::kAuthCredentialsKey)) {
2410 base::DictionaryValue* credentials_value = NULL;
2411 EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
2412 keys::kAuthCredentialsKey,
2413 &credentials_value));
2414 base::string16 username;
2415 base::string16 password;
2416 EXTENSION_FUNCTION_VALIDATE(
2417 credentials_value->GetString(keys::kUsernameKey, &username));
2418 EXTENSION_FUNCTION_VALIDATE(
2419 credentials_value->GetString(keys::kPasswordKey, &password));
2420 response->auth_credentials.reset(
2421 new net::AuthCredentials(username, password));
2422 }
2423 }
2424
2425 ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2426 profile_id(), extension_id(), event_name, sub_event_name, request_id,
2427 response.release());
2428
2429 return true;
2430 }
2431
2432 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2433 extensions::QuotaLimitHeuristics* heuristics) const {
2434 extensions::QuotaLimitHeuristic::Config config = {
2435 // See web_request.json for current value.
2436 web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
2437 base::TimeDelta::FromMinutes(10)};
2438 extensions::QuotaLimitHeuristic::BucketMapper* bucket_mapper =
2439 new extensions::QuotaLimitHeuristic::SingletonBucketMapper();
2440 ClearCacheQuotaHeuristic* heuristic =
2441 new ClearCacheQuotaHeuristic(config, bucket_mapper);
2442 heuristics->push_back(heuristic);
2443 }
2444
2445 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2446 const std::string& violation_error) {
2447 // Post warning message.
2448 WarningSet warnings;
2449 warnings.insert(
2450 Warning::CreateRepeatedCacheFlushesWarning(extension_id()));
2451 BrowserThread::PostTask(
2452 BrowserThread::UI,
2453 FROM_HERE,
2454 base::Bind(&WarningService::NotifyWarningsOnUI, profile_id(), warnings));
2455
2456 // Continue gracefully.
2457 RunSync();
2458 }
2459
2460 bool WebRequestHandlerBehaviorChangedFunction::RunSync() {
2461 helpers::ClearCacheOnNavigation();
2462 return true;
2463 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698