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