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 "extensions/browser/api/web_request/web_request_api.h"
6 
7 #include <stddef.h>
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/bind.h"
15 #include "base/callback_helpers.h"
16 #include "base/containers/flat_map.h"
17 #include "base/json/json_writer.h"
18 #include "base/lazy_instance.h"
19 #include "base/metrics/histogram_macros.h"
20 #include "base/metrics/user_metrics.h"
21 #include "base/stl_util.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "base/strings/string_piece.h"
24 #include "base/strings/string_util.h"
25 #include "base/strings/utf_string_conversions.h"
26 #include "base/task/post_task.h"
27 #include "base/time/time.h"
28 #include "base/values.h"
29 #include "build/chromeos_buildflags.h"
30 #include "components/ukm/content/source_url_recorder.h"
31 #include "content/public/browser/browser_context.h"
32 #include "content/public/browser/browser_task_traits.h"
33 #include "content/public/browser/browser_thread.h"
34 #include "content/public/browser/render_frame_host.h"
35 #include "content/public/browser/render_process_host.h"
36 #include "content/public/browser/storage_partition.h"
37 #include "content/public/browser/web_contents.h"
38 #include "content/public/common/child_process_host.h"
39 #include "content/public/common/url_constants.h"
40 #include "extensions/browser/api/activity_log/web_request_constants.h"
41 #include "extensions/browser/api/declarative/rules_registry_service.h"
42 #include "extensions/browser/api/declarative_net_request/request_action.h"
43 #include "extensions/browser/api/declarative_net_request/rules_monitor_service.h"
44 #include "extensions/browser/api/declarative_webrequest/request_stage.h"
45 #include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
46 #include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
47 #include "extensions/browser/api/extensions_api_client.h"
48 #include "extensions/browser/api/web_request/permission_helper.h"
49 #include "extensions/browser/api/web_request/web_request_api_constants.h"
50 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
51 #include "extensions/browser/api/web_request/web_request_event_details.h"
52 #include "extensions/browser/api/web_request/web_request_info.h"
53 #include "extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h"
54 #include "extensions/browser/api/web_request/web_request_proxying_websocket.h"
55 #include "extensions/browser/api/web_request/web_request_resource_type.h"
56 #include "extensions/browser/api/web_request/web_request_time_tracker.h"
57 #include "extensions/browser/api_activity_monitor.h"
58 #include "extensions/browser/device_local_account_util.h"
59 #include "extensions/browser/event_router.h"
60 #include "extensions/browser/extension_navigation_ui_data.h"
61 #include "extensions/browser/extension_prefs.h"
62 #include "extensions/browser/extension_registry.h"
63 #include "extensions/browser/extension_system.h"
64 #include "extensions/browser/extensions_browser_client.h"
65 #include "extensions/browser/guest_view/guest_view_events.h"
66 #include "extensions/browser/guest_view/web_view/web_view_constants.h"
67 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
68 #include "extensions/browser/process_map.h"
69 #include "extensions/browser/runtime_data.h"
70 #include "extensions/browser/warning_service.h"
71 #include "extensions/browser/warning_set.h"
72 #include "extensions/common/api/web_request.h"
73 #include "extensions/common/constants.h"
74 #include "extensions/common/error_utils.h"
75 #include "extensions/common/event_filtering_info.h"
76 #include "extensions/common/extension.h"
77 #include "extensions/common/extension_features.h"
78 #include "extensions/common/features/feature.h"
79 #include "extensions/common/features/feature_provider.h"
80 #include "extensions/common/identifiability_metrics.h"
81 #include "extensions/common/permissions/permissions_data.h"
82 #include "extensions/common/url_pattern.h"
83 #include "extensions/strings/grit/extensions_strings.h"
84 #include "mojo/public/cpp/bindings/pending_remote.h"
85 #include "net/base/auth.h"
86 #include "net/base/net_errors.h"
87 #include "net/http/http_util.h"
88 #include "services/metrics/public/cpp/ukm_source_id.h"
89 #include "services/network/public/mojom/fetch_api.mojom-shared.h"
90 #include "ui/base/l10n/l10n_util.h"
91 #include "url/gurl.h"
92 
93 #if BUILDFLAG(IS_CHROMEOS_ASH)
94 #include "chromeos/login/login_state/login_state.h"
95 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
96 
97 using content::BrowserThread;
98 using extension_web_request_api_helpers::ExtraInfoSpec;
99 
100 namespace activity_log = activity_log_web_request_constants;
101 namespace helpers = extension_web_request_api_helpers;
102 namespace keys = extension_web_request_api_constants;
103 using URLLoaderFactoryType =
104     content::ContentBrowserClient::URLLoaderFactoryType;
105 using DNRRequestAction = extensions::declarative_net_request::RequestAction;
106 
107 namespace extensions {
108 
109 namespace declarative_keys = declarative_webrequest_constants;
110 namespace web_request = api::web_request;
111 
112 namespace {
113 
114 // Describes the action taken by the Web Request API for a given stage of a web
115 // request.
116 // These values are written to logs.  New enum values can be added, but existing
117 // enum values must never be renumbered or deleted and reused.
118 enum RequestAction {
119   CANCEL = 0,
120   REDIRECT = 1,
121   MODIFY_REQUEST_HEADERS = 2,
122   MODIFY_RESPONSE_HEADERS = 3,
123   SET_AUTH_CREDENTIALS = 4,
124   MAX
125 };
126 
127 // Corresponds to the "WebRequestEventResponse" histogram enumeration type in
128 // src/tools/metrics/histograms/enums.xml.
129 //
130 // DO NOT REORDER OR CHANGE THE MEANING OF THESE VALUES.
131 enum class WebRequestEventResponse {
132   kIgnored,
133   kObserved,
134   kMaxValue = kObserved,
135 };
136 
137 const char kWebRequestEventPrefix[] = "webRequest.";
138 
139 // List of all the webRequest events. Note: this doesn't include
140 // "onActionIgnored" which is not related to a request's lifecycle and is
141 // handled as a normal event (as opposed to a WebRequestEvent at the bindings
142 // layer).
143 const char* const kWebRequestEvents[] = {
144     keys::kOnBeforeRedirectEvent,
145     web_request::OnBeforeRequest::kEventName,
146     keys::kOnBeforeSendHeadersEvent,
147     keys::kOnCompletedEvent,
148     web_request::OnErrorOccurred::kEventName,
149     keys::kOnSendHeadersEvent,
150     keys::kOnAuthRequiredEvent,
151     keys::kOnResponseStartedEvent,
152     keys::kOnHeadersReceivedEvent,
153 };
154 
GetRequestStageAsString(ExtensionWebRequestEventRouter::EventTypes type)155 const char* GetRequestStageAsString(
156     ExtensionWebRequestEventRouter::EventTypes type) {
157   switch (type) {
158     case ExtensionWebRequestEventRouter::kInvalidEvent:
159       return "Invalid";
160     case ExtensionWebRequestEventRouter::kOnBeforeRequest:
161       return keys::kOnBeforeRequest;
162     case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders:
163       return keys::kOnBeforeSendHeaders;
164     case ExtensionWebRequestEventRouter::kOnSendHeaders:
165       return keys::kOnSendHeaders;
166     case ExtensionWebRequestEventRouter::kOnHeadersReceived:
167       return keys::kOnHeadersReceived;
168     case ExtensionWebRequestEventRouter::kOnBeforeRedirect:
169       return keys::kOnBeforeRedirect;
170     case ExtensionWebRequestEventRouter::kOnAuthRequired:
171       return keys::kOnAuthRequired;
172     case ExtensionWebRequestEventRouter::kOnResponseStarted:
173       return keys::kOnResponseStarted;
174     case ExtensionWebRequestEventRouter::kOnErrorOccurred:
175       return keys::kOnErrorOccurred;
176     case ExtensionWebRequestEventRouter::kOnCompleted:
177       return keys::kOnCompleted;
178   }
179   NOTREACHED();
180   return "Not reached";
181 }
182 
LogRequestAction(RequestAction action)183 void LogRequestAction(RequestAction action) {
184   DCHECK_NE(RequestAction::MAX, action);
185   UMA_HISTOGRAM_ENUMERATION("Extensions.WebRequestAction", action,
186                             RequestAction::MAX);
187 }
188 
189 // Returns the corresponding EventTypes for the given |event_name|. If
190 // |event_name| is an invalid event, returns EventTypes::kInvalidEvent.
GetEventTypeFromEventName(base::StringPiece event_name)191 ExtensionWebRequestEventRouter::EventTypes GetEventTypeFromEventName(
192     base::StringPiece event_name) {
193   static const base::flat_map<base::StringPiece,
194                               ExtensionWebRequestEventRouter::EventTypes>
195       kRequestStageMap(
196           {{keys::kOnBeforeRequest,
197             ExtensionWebRequestEventRouter::kOnBeforeRequest},
198            {keys::kOnBeforeSendHeaders,
199             ExtensionWebRequestEventRouter::kOnBeforeSendHeaders},
200            {keys::kOnSendHeaders,
201             ExtensionWebRequestEventRouter::kOnSendHeaders},
202            {keys::kOnHeadersReceived,
203             ExtensionWebRequestEventRouter::kOnHeadersReceived},
204            {keys::kOnBeforeRedirect,
205             ExtensionWebRequestEventRouter::kOnBeforeRedirect},
206            {keys::kOnAuthRequired,
207             ExtensionWebRequestEventRouter::kOnAuthRequired},
208            {keys::kOnResponseStarted,
209             ExtensionWebRequestEventRouter::kOnResponseStarted},
210            {keys::kOnErrorOccurred,
211             ExtensionWebRequestEventRouter::kOnErrorOccurred},
212            {keys::kOnCompleted, ExtensionWebRequestEventRouter::kOnCompleted}});
213 
214   DCHECK_EQ(kRequestStageMap.size(), base::size(kWebRequestEvents));
215 
216   static const size_t kWebRequestEventPrefixLen =
217       strlen(kWebRequestEventPrefix);
218   static const size_t kWebViewEventPrefixLen =
219       strlen(webview::kWebViewEventPrefix);
220 
221   // Canonicalize the |event_name| to the request stage.
222   if (base::StartsWith(event_name, kWebRequestEventPrefix))
223     event_name.remove_prefix(kWebRequestEventPrefixLen);
224   else if (base::StartsWith(event_name, webview::kWebViewEventPrefix))
225     event_name.remove_prefix(kWebViewEventPrefixLen);
226   else
227     return ExtensionWebRequestEventRouter::kInvalidEvent;
228 
229   auto it = kRequestStageMap.find(event_name);
230   if (it == kRequestStageMap.end())
231     return ExtensionWebRequestEventRouter::kInvalidEvent;
232 
233   return it->second;
234 }
235 
IsWebRequestEvent(base::StringPiece event_name)236 bool IsWebRequestEvent(base::StringPiece event_name) {
237   return GetEventTypeFromEventName(event_name) !=
238          ExtensionWebRequestEventRouter::kInvalidEvent;
239 }
240 
241 // Returns whether |request| has been triggered by an extension enabled in
242 // |context|.
IsRequestFromExtension(const WebRequestInfo & request,content::BrowserContext * context)243 bool IsRequestFromExtension(const WebRequestInfo& request,
244                             content::BrowserContext* context) {
245   if (request.render_process_id == -1)
246     return false;
247 
248   const std::set<std::string> extension_ids =
249       ProcessMap::Get(context)->GetExtensionsInProcess(
250           request.render_process_id);
251   if (extension_ids.empty())
252     return false;
253 
254   // Treat hosted apps as normal web pages (crbug.com/526413).
255   for (const std::string& extension_id : extension_ids) {
256     const Extension* extension =
257         ExtensionRegistry::Get(context)->enabled_extensions().GetByID(
258             extension_id);
259     if (extension && !extension->is_hosted_app())
260       return true;
261   }
262   return false;
263 }
264 
265 // Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
266 // true if successful.
FromHeaderDictionary(const base::DictionaryValue * header_value,std::string * name,std::string * value)267 bool FromHeaderDictionary(const base::DictionaryValue* header_value,
268                           std::string* name,
269                           std::string* value) {
270   if (!header_value->GetString(keys::kHeaderNameKey, name))
271     return false;
272 
273   // We require either a "value" or a "binaryValue" entry.
274   if (!(header_value->HasKey(keys::kHeaderValueKey) ^
275         header_value->HasKey(keys::kHeaderBinaryValueKey))) {
276     return false;
277   }
278 
279   if (header_value->HasKey(keys::kHeaderValueKey)) {
280     if (!header_value->GetString(keys::kHeaderValueKey, value)) {
281       return false;
282     }
283   } else if (header_value->HasKey(keys::kHeaderBinaryValueKey)) {
284     const base::ListValue* list = NULL;
285     if (!header_value->HasKey(keys::kHeaderBinaryValueKey)) {
286       *value = "";
287     } else if (!header_value->GetList(keys::kHeaderBinaryValueKey, &list) ||
288                !helpers::CharListToString(list, value)) {
289       return false;
290     }
291   }
292   return true;
293 }
294 
295 // Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
296 // to subscribers of webview.onMessage if the action is being operated upon
297 // a <webview> guest renderer.
298 // |extension_id| identifies the extension that sends and receives the event.
299 // |is_web_view_guest| indicates whether the action is for a <webview>.
300 // |web_view_instance_id| is a valid if |is_web_view_guest| is true.
301 // |event_details| is passed to the event listener.
SendOnMessageEventOnUI(content::BrowserContext * browser_context,const std::string & extension_id,bool is_web_view_guest,int web_view_instance_id,std::unique_ptr<WebRequestEventDetails> event_details)302 void SendOnMessageEventOnUI(
303     content::BrowserContext* browser_context,
304     const std::string& extension_id,
305     bool is_web_view_guest,
306     int web_view_instance_id,
307     std::unique_ptr<WebRequestEventDetails> event_details) {
308   DCHECK_CURRENTLY_ON(BrowserThread::UI);
309 
310   if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
311     return;
312 
313   std::unique_ptr<base::ListValue> event_args(new base::ListValue);
314   event_args->Append(event_details->GetAndClearDict());
315 
316   EventRouter* event_router = EventRouter::Get(browser_context);
317 
318   EventFilteringInfo event_filtering_info;
319 
320   events::HistogramValue histogram_value = events::UNKNOWN;
321   std::string event_name;
322   // The instance ID uniquely identifies a <webview> instance within an embedder
323   // process. We use a filter here so that only event listeners for a particular
324   // <webview> will fire.
325   if (is_web_view_guest) {
326     event_filtering_info.instance_id = web_view_instance_id;
327     histogram_value = events::WEB_VIEW_INTERNAL_ON_MESSAGE;
328     event_name = webview::kEventMessage;
329   } else {
330     histogram_value = events::DECLARATIVE_WEB_REQUEST_ON_MESSAGE;
331     event_name = declarative_keys::kOnMessage;
332   }
333 
334   std::unique_ptr<Event> event(new Event(
335       histogram_value, event_name, std::move(event_args), browser_context,
336       GURL(), EventRouter::USER_GESTURE_UNKNOWN, event_filtering_info));
337   event_router->DispatchEventToExtension(extension_id, std::move(event));
338 }
339 
340 // Helper to dispatch the "onActionIgnored" event.
NotifyIgnoredActionsOnUI(content::BrowserContext * browser_context,uint64_t request_id,extension_web_request_api_helpers::IgnoredActions ignored_actions)341 void NotifyIgnoredActionsOnUI(
342     content::BrowserContext* browser_context,
343     uint64_t request_id,
344     extension_web_request_api_helpers::IgnoredActions ignored_actions) {
345   DCHECK_CURRENTLY_ON(BrowserThread::UI);
346 
347   if (!ExtensionsBrowserClient::Get()->IsValidContext(browser_context))
348     return;
349 
350   EventRouter* event_router = EventRouter::Get(browser_context);
351   web_request::OnActionIgnored::Details details;
352   details.request_id = base::NumberToString(request_id);
353   details.action = web_request::IGNORED_ACTION_TYPE_NONE;
354   for (const auto& ignored_action : ignored_actions) {
355     DCHECK_NE(web_request::IGNORED_ACTION_TYPE_NONE,
356               ignored_action.action_type);
357 
358     details.action = ignored_action.action_type;
359     auto event = std::make_unique<Event>(
360         events::WEB_REQUEST_ON_ACTION_IGNORED,
361         web_request::OnActionIgnored::kEventName,
362         web_request::OnActionIgnored::Create(details), browser_context);
363     event_router->DispatchEventToExtension(ignored_action.extension_id,
364                                            std::move(event));
365   }
366 }
367 
GetEventHistogramValue(const std::string & event_name)368 events::HistogramValue GetEventHistogramValue(const std::string& event_name) {
369   // Event names will either be webRequest events, or guest view (probably web
370   // view) events that map to webRequest events. Check webRequest first.
371   static struct ValueAndName {
372     events::HistogramValue histogram_value;
373     const char* const event_name;
374   } values_and_names[] = {
375       {events::WEB_REQUEST_ON_BEFORE_REDIRECT, keys::kOnBeforeRedirectEvent},
376       {events::WEB_REQUEST_ON_BEFORE_REQUEST,
377        web_request::OnBeforeRequest::kEventName},
378       {events::WEB_REQUEST_ON_BEFORE_SEND_HEADERS,
379        keys::kOnBeforeSendHeadersEvent},
380       {events::WEB_REQUEST_ON_COMPLETED, keys::kOnCompletedEvent},
381       {events::WEB_REQUEST_ON_ERROR_OCCURRED,
382        web_request::OnErrorOccurred::kEventName},
383       {events::WEB_REQUEST_ON_SEND_HEADERS, keys::kOnSendHeadersEvent},
384       {events::WEB_REQUEST_ON_AUTH_REQUIRED, keys::kOnAuthRequiredEvent},
385       {events::WEB_REQUEST_ON_RESPONSE_STARTED, keys::kOnResponseStartedEvent},
386       {events::WEB_REQUEST_ON_HEADERS_RECEIVED, keys::kOnHeadersReceivedEvent}};
387   static_assert(base::size(kWebRequestEvents) == base::size(values_and_names),
388                 "kWebRequestEvents and values_and_names must be the same");
389   for (const ValueAndName& value_and_name : values_and_names) {
390     if (value_and_name.event_name == event_name)
391       return value_and_name.histogram_value;
392   }
393 
394   // If there is no webRequest event, it might be a guest view webRequest event.
395   events::HistogramValue guest_view_histogram_value =
396       guest_view_events::GetEventHistogramValue(event_name);
397   if (guest_view_histogram_value != events::UNKNOWN)
398     return guest_view_histogram_value;
399 
400   // There is no histogram value for this event name. It should be added to
401   // either the mapping here, or in guest_view_events.
402   NOTREACHED() << "Event " << event_name << " must have a histogram value";
403   return events::UNKNOWN;
404 }
405 
406 // We hide events from the system context as well as sensitive requests.
ShouldHideEvent(content::BrowserContext * browser_context,const WebRequestInfo & request)407 bool ShouldHideEvent(content::BrowserContext* browser_context,
408                      const WebRequestInfo& request) {
409   return (!browser_context ||
410           WebRequestPermissions::HideRequest(
411               PermissionHelper::Get(browser_context), request));
412 }
413 
414 // Returns true if we're in a Public Session and restrictions are enabled.
ArePublicSessionRestrictionsEnabled()415 bool ArePublicSessionRestrictionsEnabled() {
416 #if BUILDFLAG(IS_CHROMEOS_ASH)
417   if (chromeos::LoginState::IsInitialized()) {
418     return chromeos::LoginState::Get()->ArePublicSessionRestrictionsEnabled();
419   }
420 #endif
421   return false;
422 }
423 
424 // Returns event details for a given request.
CreateEventDetails(const WebRequestInfo & request,int extra_info_spec)425 std::unique_ptr<WebRequestEventDetails> CreateEventDetails(
426     const WebRequestInfo& request,
427     int extra_info_spec) {
428   return std::make_unique<WebRequestEventDetails>(request, extra_info_spec);
429 }
430 
431 // Checks whether the extension has any permissions that would use the web
432 // request API.
HasAnyWebRequestPermissions(const Extension * extension)433 bool HasAnyWebRequestPermissions(const Extension* extension) {
434   static const APIPermission::ID kWebRequestPermissions[] = {
435       APIPermission::ID::kWebRequest,
436       APIPermission::ID::kWebRequestBlocking,
437       APIPermission::ID::kDeclarativeWebRequest,
438       APIPermission::ID::kDeclarativeNetRequest,
439       APIPermission::ID::kWebView,
440   };
441 
442   const PermissionsData* permissions = extension->permissions_data();
443   for (auto permission : kWebRequestPermissions) {
444     if (permissions->HasAPIPermission(permission))
445       return true;
446   }
447   return false;
448 }
449 
450 // Mirrors the histogram enum of the same name. DO NOT REORDER THESE VALUES OR
451 // CHANGE THEIR MEANING.
452 enum class WebRequestEventListenerFlag {
453   kTotal,
454   kNone,
455   kRequestHeaders,
456   kResponseHeaders,
457   kBlocking,
458   kAsyncBlocking,
459   kRequestBody,
460   kExtraHeaders,
461   kMaxValue = kExtraHeaders,
462 };
463 
LogEventListenerFlag(WebRequestEventListenerFlag flag)464 void LogEventListenerFlag(WebRequestEventListenerFlag flag) {
465   UMA_HISTOGRAM_ENUMERATION("Extensions.WebRequest.EventListenerFlag", flag);
466 }
467 
RecordAddEventListenerUMAs(int extra_info_spec)468 void RecordAddEventListenerUMAs(int extra_info_spec) {
469   LogEventListenerFlag(WebRequestEventListenerFlag::kTotal);
470   if (extra_info_spec == 0) {
471     LogEventListenerFlag(WebRequestEventListenerFlag::kNone);
472     return;
473   }
474 
475   if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
476     LogEventListenerFlag(WebRequestEventListenerFlag::kRequestHeaders);
477   if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS)
478     LogEventListenerFlag(WebRequestEventListenerFlag::kResponseHeaders);
479   if (extra_info_spec & ExtraInfoSpec::BLOCKING)
480     LogEventListenerFlag(WebRequestEventListenerFlag::kBlocking);
481   if (extra_info_spec & ExtraInfoSpec::ASYNC_BLOCKING)
482     LogEventListenerFlag(WebRequestEventListenerFlag::kAsyncBlocking);
483   if (extra_info_spec & ExtraInfoSpec::REQUEST_BODY)
484     LogEventListenerFlag(WebRequestEventListenerFlag::kRequestBody);
485   if (extra_info_spec & ExtraInfoSpec::EXTRA_HEADERS)
486     LogEventListenerFlag(WebRequestEventListenerFlag::kExtraHeaders);
487 }
488 
489 // Helper to record a matched DNR action in RulesetManager's ActionTracker.
OnDNRActionMatched(content::BrowserContext * browser_context,const WebRequestInfo & request,const DNRRequestAction & action)490 void OnDNRActionMatched(content::BrowserContext* browser_context,
491                         const WebRequestInfo& request,
492                         const DNRRequestAction& action) {
493   if (action.tracked)
494     return;
495 
496   declarative_net_request::ActionTracker& action_tracker =
497       declarative_net_request::RulesMonitorService::Get(browser_context)
498           ->action_tracker();
499 
500   action_tracker.OnRuleMatched(action, request);
501   action.tracked = true;
502 }
503 
504 }  // namespace
505 
HandleAuthRequest(const net::AuthChallengeInfo & auth_info,scoped_refptr<net::HttpResponseHeaders> response_headers,int32_t request_id,AuthRequestCallback callback)506 void WebRequestAPI::Proxy::HandleAuthRequest(
507     const net::AuthChallengeInfo& auth_info,
508     scoped_refptr<net::HttpResponseHeaders> response_headers,
509     int32_t request_id,
510     AuthRequestCallback callback) {
511   // Default implementation cancels the request.
512   base::SequencedTaskRunnerHandle::Get()->PostTask(
513       FROM_HERE, base::BindOnce(std::move(callback), base::nullopt,
514                                 false /* should_cancel */));
515 }
516 
ProxySet()517 WebRequestAPI::ProxySet::ProxySet() {
518   DCHECK_CURRENTLY_ON(BrowserThread::UI);
519 }
520 
~ProxySet()521 WebRequestAPI::ProxySet::~ProxySet() {
522   DCHECK_CURRENTLY_ON(BrowserThread::UI);
523 }
524 
AddProxy(std::unique_ptr<Proxy> proxy)525 void WebRequestAPI::ProxySet::AddProxy(std::unique_ptr<Proxy> proxy) {
526   DCHECK_CURRENTLY_ON(BrowserThread::UI);
527 
528   proxies_.insert(std::move(proxy));
529 }
530 
RemoveProxy(Proxy * proxy)531 void WebRequestAPI::ProxySet::RemoveProxy(Proxy* proxy) {
532   DCHECK_CURRENTLY_ON(BrowserThread::UI);
533 
534   auto requests_it = proxy_to_request_id_map_.find(proxy);
535   if (requests_it != proxy_to_request_id_map_.end()) {
536     for (const auto& id : requests_it->second)
537       request_id_to_proxy_map_.erase(id);
538     proxy_to_request_id_map_.erase(requests_it);
539   }
540 
541   auto proxy_it = proxies_.find(proxy);
542   DCHECK(proxy_it != proxies_.end());
543   proxies_.erase(proxy_it);
544 }
545 
AssociateProxyWithRequestId(Proxy * proxy,const content::GlobalRequestID & id)546 void WebRequestAPI::ProxySet::AssociateProxyWithRequestId(
547     Proxy* proxy,
548     const content::GlobalRequestID& id) {
549   DCHECK(proxy);
550   DCHECK(proxies_.count(proxy));
551   DCHECK(id.request_id);
552   auto result = request_id_to_proxy_map_.emplace(id, proxy);
553   DCHECK(result.second) << "Unexpected request ID collision.";
554   proxy_to_request_id_map_[proxy].insert(id);
555 }
556 
DisassociateProxyWithRequestId(Proxy * proxy,const content::GlobalRequestID & id)557 void WebRequestAPI::ProxySet::DisassociateProxyWithRequestId(
558     Proxy* proxy,
559     const content::GlobalRequestID& id) {
560   DCHECK(proxy);
561   DCHECK(proxies_.count(proxy));
562   DCHECK(id.request_id);
563   size_t count = request_id_to_proxy_map_.erase(id);
564   DCHECK_GT(count, 0u);
565   count = proxy_to_request_id_map_[proxy].erase(id);
566   DCHECK_GT(count, 0u);
567 }
568 
GetProxyFromRequestId(const content::GlobalRequestID & id)569 WebRequestAPI::Proxy* WebRequestAPI::ProxySet::GetProxyFromRequestId(
570     const content::GlobalRequestID& id) {
571   auto it = request_id_to_proxy_map_.find(id);
572   if (it == request_id_to_proxy_map_.end())
573     return nullptr;
574   return it->second;
575 }
576 
MaybeProxyAuthRequest(const net::AuthChallengeInfo & auth_info,scoped_refptr<net::HttpResponseHeaders> response_headers,const content::GlobalRequestID & request_id,AuthRequestCallback callback)577 void WebRequestAPI::ProxySet::MaybeProxyAuthRequest(
578     const net::AuthChallengeInfo& auth_info,
579     scoped_refptr<net::HttpResponseHeaders> response_headers,
580     const content::GlobalRequestID& request_id,
581     AuthRequestCallback callback) {
582   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
583   Proxy* proxy = GetProxyFromRequestId(request_id);
584   if (!proxy) {
585     // Run the |callback| which will display a dialog for the user to enter
586     // their auth credentials.
587     base::SequencedTaskRunnerHandle::Get()->PostTask(
588         FROM_HERE, base::BindOnce(std::move(callback), base::nullopt,
589                                   false /* should_cancel */));
590     return;
591   }
592 
593   proxy->HandleAuthRequest(auth_info, std::move(response_headers),
594                            request_id.request_id, std::move(callback));
595 }
596 
597 WebRequestAPI::RequestIDGenerator::RequestIDGenerator() = default;
598 WebRequestAPI::RequestIDGenerator::~RequestIDGenerator() = default;
599 
Generate(int32_t routing_id,int32_t network_service_request_id)600 int64_t WebRequestAPI::RequestIDGenerator::Generate(
601     int32_t routing_id,
602     int32_t network_service_request_id) {
603   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
604   auto it = saved_id_map_.find({routing_id, network_service_request_id});
605   if (it != saved_id_map_.end()) {
606     int64_t id = it->second;
607     saved_id_map_.erase(it);
608     return id;
609   }
610   return ++id_;
611 }
612 
SaveID(int32_t routing_id,int32_t network_service_request_id,uint64_t request_id)613 void WebRequestAPI::RequestIDGenerator::SaveID(
614     int32_t routing_id,
615     int32_t network_service_request_id,
616     uint64_t request_id) {
617   // If |network_service_request_id| is 0, we cannot reliably match the
618   // generated ID to a future request, so ignore it.
619   if (network_service_request_id != 0) {
620     saved_id_map_.insert(
621         {{routing_id, network_service_request_id}, request_id});
622   }
623 }
624 
WebRequestAPI(content::BrowserContext * context)625 WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
626     : browser_context_(context),
627       proxies_(std::make_unique<ProxySet>()),
628       may_have_proxies_(MayHaveProxies()) {
629   EventRouter* event_router = EventRouter::Get(browser_context_);
630   for (size_t i = 0; i < base::size(kWebRequestEvents); ++i) {
631     // Observe the webRequest event.
632     std::string event_name = kWebRequestEvents[i];
633     event_router->RegisterObserver(this, event_name);
634 
635     // Also observe the corresponding webview event.
636     event_name.replace(
637         0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
638     event_router->RegisterObserver(this, event_name);
639   }
640   extensions::ExtensionRegistry::Get(browser_context_)->AddObserver(this);
641 }
642 
~WebRequestAPI()643 WebRequestAPI::~WebRequestAPI() {
644 }
645 
Shutdown()646 void WebRequestAPI::Shutdown() {
647   proxies_.reset();
648   EventRouter::Get(browser_context_)->UnregisterObserver(this);
649   extensions::ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
650 }
651 
652 static base::LazyInstance<
653     BrowserContextKeyedAPIFactory<WebRequestAPI>>::DestructorAtExit g_factory =
654     LAZY_INSTANCE_INITIALIZER;
655 
656 // static
657 BrowserContextKeyedAPIFactory<WebRequestAPI>*
GetFactoryInstance()658 WebRequestAPI::GetFactoryInstance() {
659   return g_factory.Pointer();
660 }
661 
OnListenerRemoved(const EventListenerInfo & details)662 void WebRequestAPI::OnListenerRemoved(const EventListenerInfo& details) {
663   DCHECK_CURRENTLY_ON(BrowserThread::UI);
664   // Note that details.event_name includes the sub-event details (e.g. "/123").
665   // TODO(fsamuel): <webview> events will not be removed through this code path.
666   // <webview> events will be removed in RemoveWebViewEventListeners. Ideally,
667   // this code should be decoupled from extensions, we should use the host ID
668   // instead, and not have two different code paths. This is a huge undertaking
669   // unfortunately, so we'll resort to two code paths for now.
670   //
671   // Note that details.event_name is actually the sub_event_name!
672   ExtensionWebRequestEventRouter::EventListener::ID id(
673       details.browser_context, details.extension_id, details.event_name, 0, 0,
674       details.worker_thread_id, details.service_worker_version_id);
675 
676   // This PostTask is necessary even though we are already on the UI thread to
677   // allow cases where blocking listeners remove themselves inside the handler.
678   // This Unretained is safe because the ExtensionWebRequestEventRouter
679   // singleton is leaked.
680   base::SequencedTaskRunnerHandle::Get()->PostTask(
681       FROM_HERE,
682       base::BindOnce(
683           &ExtensionWebRequestEventRouter::RemoveEventListener,
684           base::Unretained(ExtensionWebRequestEventRouter::GetInstance()), id,
685           false /* not strict */));
686 }
687 
MaybeProxyURLLoaderFactory(content::BrowserContext * browser_context,content::RenderFrameHost * frame,int render_process_id,URLLoaderFactoryType type,base::Optional<int64_t> navigation_id,ukm::SourceIdObj ukm_source_id,mojo::PendingReceiver<network::mojom::URLLoaderFactory> * factory_receiver,mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient> * header_client)688 bool WebRequestAPI::MaybeProxyURLLoaderFactory(
689     content::BrowserContext* browser_context,
690     content::RenderFrameHost* frame,
691     int render_process_id,
692     URLLoaderFactoryType type,
693     base::Optional<int64_t> navigation_id,
694     ukm::SourceIdObj ukm_source_id,
695     mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
696     mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
697         header_client) {
698   DCHECK_CURRENTLY_ON(BrowserThread::UI);
699   auto* web_contents = content::WebContents::FromRenderFrameHost(frame);
700   if (!MayHaveProxies()) {
701     bool skip_proxy = true;
702     // There are a few internal WebUIs that use WebView tag that are whitelisted
703     // for webRequest.
704     if (web_contents && WebViewGuest::IsGuest(web_contents)) {
705       auto* guest_web_contents =
706           WebViewGuest::GetTopLevelWebContents(web_contents);
707       auto& guest_url = guest_web_contents->GetURL();
708       if (guest_url.SchemeIs(content::kChromeUIScheme)) {
709         auto* feature = FeatureProvider::GetAPIFeature("webRequestInternal");
710         if (feature
711                 ->IsAvailableToContext(nullptr, Feature::WEBUI_CONTEXT,
712                                        guest_url)
713                 .is_available()) {
714           skip_proxy = false;
715         }
716       }
717     }
718 
719     if (skip_proxy)
720       return false;
721   }
722 
723   auto proxied_receiver = std::move(*factory_receiver);
724   mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_remote;
725   *factory_receiver = target_factory_remote.InitWithNewPipeAndPassReceiver();
726 
727   std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data;
728   const bool is_navigation = (type == URLLoaderFactoryType::kNavigation);
729   if (is_navigation) {
730     DCHECK(frame);
731     DCHECK(navigation_id);
732     int tab_id;
733     int window_id;
734     ExtensionsBrowserClient::Get()->GetTabAndWindowIdForWebContents(
735         content::WebContents::FromRenderFrameHost(frame), &tab_id, &window_id);
736     navigation_ui_data =
737         std::make_unique<ExtensionNavigationUIData>(frame, tab_id, window_id);
738   }
739 
740   mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
741       header_client_receiver;
742   if (header_client)
743     header_client_receiver = header_client->InitWithNewPipeAndPassReceiver();
744 
745   // NOTE: This request may be proxied on behalf of an incognito frame, but
746   // |this| will always be bound to a regular profile (see
747   // |BrowserContextKeyedAPI::kServiceRedirectedInIncognito|).
748   DCHECK(browser_context == browser_context_ ||
749          (browser_context->IsOffTheRecord() &&
750           ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context) ==
751               browser_context_));
752   WebRequestProxyingURLLoaderFactory::StartProxying(
753       browser_context, is_navigation ? -1 : render_process_id,
754       &request_id_generator_, std::move(navigation_ui_data),
755       std::move(navigation_id), ukm_source_id, std::move(proxied_receiver),
756       std::move(target_factory_remote), std::move(header_client_receiver),
757       proxies_.get(), type);
758   return true;
759 }
760 
MaybeProxyAuthRequest(content::BrowserContext * browser_context,const net::AuthChallengeInfo & auth_info,scoped_refptr<net::HttpResponseHeaders> response_headers,const content::GlobalRequestID & request_id,bool is_main_frame,AuthRequestCallback callback)761 bool WebRequestAPI::MaybeProxyAuthRequest(
762     content::BrowserContext* browser_context,
763     const net::AuthChallengeInfo& auth_info,
764     scoped_refptr<net::HttpResponseHeaders> response_headers,
765     const content::GlobalRequestID& request_id,
766     bool is_main_frame,
767     AuthRequestCallback callback) {
768   if (!MayHaveProxies())
769     return false;
770 
771   content::GlobalRequestID proxied_request_id = request_id;
772   if (is_main_frame)
773     proxied_request_id.child_id = -1;
774 
775   // NOTE: This request may be proxied on behalf of an incognito frame, but
776   // |this| will always be bound to a regular profile (see
777   // |BrowserContextKeyedAPI::kServiceRedirectedInIncognito|).
778   DCHECK(browser_context == browser_context_ ||
779          (browser_context->IsOffTheRecord() &&
780           ExtensionsBrowserClient::Get()->GetOriginalContext(browser_context) ==
781               browser_context_));
782   proxies_->MaybeProxyAuthRequest(auth_info, std::move(response_headers),
783                                   proxied_request_id, std::move(callback));
784   return true;
785 }
786 
ProxyWebSocket(content::RenderFrameHost * frame,content::ContentBrowserClient::WebSocketFactory factory,const GURL & url,const GURL & site_for_cookies,const base::Optional<std::string> & user_agent,mojo::PendingRemote<network::mojom::WebSocketHandshakeClient> handshake_client)787 void WebRequestAPI::ProxyWebSocket(
788     content::RenderFrameHost* frame,
789     content::ContentBrowserClient::WebSocketFactory factory,
790     const GURL& url,
791     const GURL& site_for_cookies,
792     const base::Optional<std::string>& user_agent,
793     mojo::PendingRemote<network::mojom::WebSocketHandshakeClient>
794         handshake_client) {
795   DCHECK_CURRENTLY_ON(BrowserThread::UI);
796   DCHECK(MayHaveProxies());
797 
798   const bool has_extra_headers =
799       ExtensionWebRequestEventRouter::GetInstance()->HasAnyExtraHeadersListener(
800           frame->GetProcess()->GetBrowserContext());
801 
802   auto* web_contents = content::WebContents::FromRenderFrameHost(frame);
803   const ukm::SourceIdObj ukm_source_id =
804       web_contents ? ukm::SourceIdObj::FromInt64(
805                          ukm::GetSourceIdForWebContentsDocument(web_contents))
806                    : ukm::kInvalidSourceIdObj;
807   WebRequestProxyingWebSocket::StartProxying(
808       std::move(factory), url, site_for_cookies, user_agent,
809       std::move(handshake_client), has_extra_headers,
810       frame->GetProcess()->GetID(), frame->GetRoutingID(), ukm_source_id,
811       &request_id_generator_, frame->GetLastCommittedOrigin(),
812       frame->GetProcess()->GetBrowserContext(), proxies_.get());
813 }
814 
ForceProxyForTesting()815 void WebRequestAPI::ForceProxyForTesting() {
816   ++web_request_extension_count_;
817   UpdateMayHaveProxies();
818 }
819 
MayHaveProxies() const820 bool WebRequestAPI::MayHaveProxies() const {
821   DCHECK_CURRENTLY_ON(BrowserThread::UI);
822   if (base::FeatureList::IsEnabled(
823           extensions_features::kForceWebRequestProxyForTest)) {
824     return true;
825   }
826 
827   return web_request_extension_count_ > 0;
828 }
829 
UpdateMayHaveProxies()830 void WebRequestAPI::UpdateMayHaveProxies() {
831   bool may_have_proxies = MayHaveProxies();
832   if (!may_have_proxies_ && may_have_proxies) {
833     content::BrowserContext::GetDefaultStoragePartition(browser_context_)
834         ->ResetURLLoaderFactories();
835   }
836   may_have_proxies_ = may_have_proxies;
837 }
838 
OnExtensionLoaded(content::BrowserContext * browser_context,const Extension * extension)839 void WebRequestAPI::OnExtensionLoaded(content::BrowserContext* browser_context,
840                                       const Extension* extension) {
841   if (HasAnyWebRequestPermissions(extension)) {
842     ++web_request_extension_count_;
843     UpdateMayHaveProxies();
844   }
845 }
846 
OnExtensionUnloaded(content::BrowserContext * browser_context,const Extension * extension,UnloadedExtensionReason reason)847 void WebRequestAPI::OnExtensionUnloaded(
848     content::BrowserContext* browser_context,
849     const Extension* extension,
850     UnloadedExtensionReason reason) {
851   if (HasAnyWebRequestPermissions(extension)) {
852     --web_request_extension_count_;
853     UpdateMayHaveProxies();
854   }
855 }
856 
857 // Represents a single unique listener to an event, along with whatever filter
858 // parameters and extra_info_spec were specified at the time the listener was
859 // added.
860 // NOTE(benjhayden) New APIs should not use this sub_event_name trick! It does
861 // not play well with event pages. See downloads.onDeterminingFilename and
862 // ExtensionDownloadsEventRouter for an alternative approach.
EventListener(ID id)863 ExtensionWebRequestEventRouter::EventListener::EventListener(ID id) : id(id) {}
~EventListener()864 ExtensionWebRequestEventRouter::EventListener::~EventListener() {}
865 
866 // Contains info about requests that are blocked waiting for a response from
867 // an extension.
868 struct ExtensionWebRequestEventRouter::BlockedRequest {
869   BlockedRequest() = default;
870 
871   // Information about the request that is being blocked. Not owned.
872   const WebRequestInfo* request = nullptr;
873 
874   // Whether the request originates from an incognito tab.
875   bool is_incognito = false;
876 
877   // The event that we're currently blocked on.
878   EventTypes event = kInvalidEvent;
879 
880   // The number of event handlers that we are awaiting a response from.
881   int num_handlers_blocking = 0;
882 
883   // The callback to call when we get a response from all event handlers.
884   net::CompletionOnceCallback callback;
885 
886   // The callback to invoke for onBeforeSendHeaders. If
887   // |before_send_headers_callback.is_null()| is false, |callback| must be NULL.
888   // Only valid for OnBeforeSendHeaders.
889   BeforeSendHeadersCallback before_send_headers_callback;
890 
891   // The callback to invoke for auth. If |auth_callback.is_null()| is false,
892   // |callback| must be NULL.
893   // Only valid for OnAuthRequired.
894   AuthCallback auth_callback;
895 
896   // If non-empty, this contains the auth credentials that may be filled in.
897   // Only valid for OnAuthRequired.
898   net::AuthCredentials* auth_credentials = nullptr;
899 
900   // If non-empty, this contains the new URL that the request will redirect to.
901   // Only valid for OnBeforeRequest and OnHeadersReceived.
902   GURL* new_url = nullptr;
903 
904   // The request headers that will be issued along with this request. Only valid
905   // for OnBeforeSendHeaders.
906   net::HttpRequestHeaders* request_headers = nullptr;
907 
908   // The response headers that were received from the server. Only valid for
909   // OnHeadersReceived.
910   scoped_refptr<const net::HttpResponseHeaders> original_response_headers;
911 
912   // Location where to override response headers. Only valid for
913   // OnHeadersReceived.
914   scoped_refptr<net::HttpResponseHeaders>* override_response_headers = nullptr;
915 
916   // Time the request was paused. Used for logging purposes.
917   base::Time blocking_time;
918 
919   // Changes requested by extensions.
920   helpers::EventResponseDeltas response_deltas;
921 };
922 
InitFromValue(const base::DictionaryValue & value,std::string * error)923 bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
924     const base::DictionaryValue& value, std::string* error) {
925   if (!value.HasKey("urls"))
926     return false;
927 
928   for (base::DictionaryValue::Iterator it(value); !it.IsAtEnd(); it.Advance()) {
929     if (it.key() == "urls") {
930       const base::ListValue* urls_value = NULL;
931       if (!it.value().GetAsList(&urls_value))
932         return false;
933       for (size_t i = 0; i < urls_value->GetSize(); ++i) {
934         std::string url;
935         URLPattern pattern(URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS |
936                            URLPattern::SCHEME_FTP | URLPattern::SCHEME_FILE |
937                            URLPattern::SCHEME_EXTENSION |
938                            URLPattern::SCHEME_WS | URLPattern::SCHEME_WSS);
939         if (!urls_value->GetString(i, &url) ||
940             pattern.Parse(url) != URLPattern::ParseResult::kSuccess) {
941           *error = ErrorUtils::FormatErrorMessage(
942               keys::kInvalidRequestFilterUrl, url);
943           return false;
944         }
945         urls.AddPattern(pattern);
946       }
947     } else if (it.key() == "types") {
948       const base::ListValue* types_value = NULL;
949       if (!it.value().GetAsList(&types_value))
950         return false;
951       for (size_t i = 0; i < types_value->GetSize(); ++i) {
952         std::string type_str;
953         types.push_back(WebRequestResourceType::OTHER);
954         if (!types_value->GetString(i, &type_str) ||
955             !ParseWebRequestResourceType(type_str, &types.back())) {
956           return false;
957         }
958       }
959     } else if (it.key() == "tabId") {
960       if (!it.value().GetAsInteger(&tab_id))
961         return false;
962     } else if (it.key() == "windowId") {
963       if (!it.value().GetAsInteger(&window_id))
964         return false;
965     } else {
966       return false;
967     }
968   }
969   return true;
970 }
971 
EventResponse(const std::string & extension_id,const base::Time & extension_install_time)972 ExtensionWebRequestEventRouter::EventResponse::EventResponse(
973     const std::string& extension_id, const base::Time& extension_install_time)
974     : extension_id(extension_id),
975       extension_install_time(extension_install_time),
976       cancel(false) {
977 }
978 
~EventResponse()979 ExtensionWebRequestEventRouter::EventResponse::~EventResponse() {
980 }
981 
RequestFilter()982 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter()
983     : tab_id(-1), window_id(-1) {}
984 ExtensionWebRequestEventRouter::RequestFilter::~RequestFilter() = default;
985 
RequestFilter(const RequestFilter & other)986 ExtensionWebRequestEventRouter::RequestFilter::RequestFilter(
987     const RequestFilter& other)
988     : urls(other.urls.Clone()),
989       types(other.types),
990       tab_id(other.tab_id),
991       window_id(other.window_id) {}
992 ExtensionWebRequestEventRouter::RequestFilter&
operator =(const RequestFilter & other)993 ExtensionWebRequestEventRouter::RequestFilter::operator=(
994     const RequestFilter& other) {
995   urls = other.urls.Clone();
996   types = other.types;
997   tab_id = other.tab_id;
998   window_id = other.window_id;
999   return *this;
1000 }
1001 
1002 //
1003 // ExtensionWebRequestEventRouter
1004 //
1005 
1006 // static
GetInstance()1007 ExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
1008   static base::NoDestructor<ExtensionWebRequestEventRouter> instance;
1009   return instance.get();
1010 }
1011 
ExtensionWebRequestEventRouter()1012 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
1013     : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
1014 }
1015 
RegisterRulesRegistry(content::BrowserContext * browser_context,int rules_registry_id,scoped_refptr<WebRequestRulesRegistry> rules_registry)1016 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
1017     content::BrowserContext* browser_context,
1018     int rules_registry_id,
1019     scoped_refptr<WebRequestRulesRegistry> rules_registry) {
1020   RulesRegistryKey key(browser_context, rules_registry_id);
1021   if (rules_registry.get())
1022     rules_registries_[key] = rules_registry;
1023   else
1024     rules_registries_.erase(key);
1025 }
1026 
OnBeforeRequest(content::BrowserContext * browser_context,WebRequestInfo * request,net::CompletionOnceCallback callback,GURL * new_url,bool * should_collapse_initiator)1027 int ExtensionWebRequestEventRouter::OnBeforeRequest(
1028     content::BrowserContext* browser_context,
1029     WebRequestInfo* request,
1030     net::CompletionOnceCallback callback,
1031     GURL* new_url,
1032     bool* should_collapse_initiator) {
1033   DCHECK(should_collapse_initiator);
1034 
1035   if (ShouldHideEvent(browser_context, *request)) {
1036     request->dnr_actions = std::vector<DNRRequestAction>();
1037     return net::OK;
1038   }
1039 
1040   if (IsPageLoad(*request))
1041     NotifyPageLoad();
1042 
1043   bool has_listener = false;
1044   for (const auto& kv : listeners_[browser_context]) {
1045     if (!kv.second.empty()) {
1046       has_listener = true;
1047       break;
1048     }
1049   }
1050   request_time_tracker_->LogRequestStartTime(
1051       request->id, base::TimeTicks::Now(), has_listener,
1052       HasExtraHeadersListenerForRequest(browser_context, request));
1053 
1054   const bool is_incognito_context = IsIncognitoBrowserContext(browser_context);
1055 
1056   // Whether to initialized |blocked_requests_|.
1057   bool initialize_blocked_requests = false;
1058 
1059   initialize_blocked_requests |= ProcessDeclarativeRules(
1060       browser_context, web_request::OnBeforeRequest::kEventName, request,
1061       ON_BEFORE_REQUEST, nullptr);
1062 
1063   int extra_info_spec = 0;
1064   RawListeners listeners = GetMatchingListeners(
1065       browser_context, web_request::OnBeforeRequest::kEventName, request,
1066       &extra_info_spec);
1067   if (!listeners.empty() && !GetAndSetSignaled(request->id, kOnBeforeRequest)) {
1068     std::unique_ptr<WebRequestEventDetails> event_details(
1069         CreateEventDetails(*request, extra_info_spec));
1070     event_details->SetRequestBody(request);
1071 
1072     initialize_blocked_requests |= DispatchEvent(
1073         browser_context, request, listeners, std::move(event_details));
1074   }
1075 
1076   // Handle Declarative Net Request API rules. In case the request is blocked or
1077   // redirected, we un-block the request and ignore any subsequent responses
1078   // from webRequestBlocking listeners. Note: We don't remove the request from
1079   // the |EventListener::blocked_requests| set of any blocking listeners it was
1080   // dispatched to, since the listener's response will be ignored in
1081   // |DecrementBlockCount| anyway.
1082 
1083   // Only checking the rules in the OnBeforeRequest stage works, since the rules
1084   // currently only depend on the request url, initiator and resource type,
1085   // which should stay the same during the diffierent network request stages. A
1086   // redirect should cause another OnBeforeRequest call.
1087   const std::vector<DNRRequestAction>& actions =
1088       declarative_net_request::RulesMonitorService::Get(browser_context)
1089           ->ruleset_manager()
1090           ->EvaluateRequest(*request, is_incognito_context);
1091   for (const auto& action : actions) {
1092     switch (action.type) {
1093       case DNRRequestAction::Type::BLOCK:
1094         ClearPendingCallbacks(*request);
1095         DCHECK_EQ(1u, actions.size());
1096         OnDNRActionMatched(browser_context, *request, action);
1097         RecordNetworkRequestBlocked(request->ukm_source_id,
1098                                     action.extension_id);
1099         return net::ERR_BLOCKED_BY_CLIENT;
1100       case DNRRequestAction::Type::COLLAPSE:
1101         ClearPendingCallbacks(*request);
1102         DCHECK_EQ(1u, actions.size());
1103         OnDNRActionMatched(browser_context, *request, action);
1104         *should_collapse_initiator = true;
1105         RecordNetworkRequestBlocked(request->ukm_source_id,
1106                                     action.extension_id);
1107         return net::ERR_BLOCKED_BY_CLIENT;
1108       case DNRRequestAction::Type::ALLOW:
1109       case DNRRequestAction::Type::ALLOW_ALL_REQUESTS:
1110         DCHECK_EQ(1u, actions.size());
1111         OnDNRActionMatched(browser_context, *request, action);
1112         break;
1113       case DNRRequestAction::Type::REDIRECT:
1114       case DNRRequestAction::Type::UPGRADE:
1115         ClearPendingCallbacks(*request);
1116         DCHECK_EQ(1u, actions.size());
1117         DCHECK(action.redirect_url);
1118         OnDNRActionMatched(browser_context, *request, action);
1119         *new_url = action.redirect_url.value();
1120         return net::OK;
1121       case DNRRequestAction::Type::MODIFY_HEADERS:
1122         // Unlike other actions, allow web request extensions to intercept the
1123         // request here. The headers will be modified during subsequent request
1124         // stages.
1125         DCHECK(std::all_of(request->dnr_actions->begin(),
1126                            request->dnr_actions->end(), [](const auto& action) {
1127                              return action.type ==
1128                                     DNRRequestAction::Type::MODIFY_HEADERS;
1129                            }));
1130         break;
1131     }
1132   }
1133 
1134   if (!initialize_blocked_requests)
1135     return net::OK;  // Nobody saw a reason for modifying the request.
1136 
1137   BlockedRequest& blocked_request = blocked_requests_[request->id];
1138   blocked_request.event = kOnBeforeRequest;
1139   blocked_request.is_incognito |= is_incognito_context;
1140   blocked_request.request = request;
1141   blocked_request.callback = std::move(callback);
1142   blocked_request.new_url = new_url;
1143 
1144   if (blocked_request.num_handlers_blocking == 0) {
1145     // If there are no blocking handlers, only the declarative rules tried
1146     // to modify the request and we can respond synchronously.
1147     return ExecuteDeltas(browser_context, request, false /* call_callback*/);
1148   }
1149   return net::ERR_IO_PENDING;
1150 }
1151 
OnBeforeSendHeaders(content::BrowserContext * browser_context,const WebRequestInfo * request,BeforeSendHeadersCallback callback,net::HttpRequestHeaders * headers)1152 int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
1153     content::BrowserContext* browser_context,
1154     const WebRequestInfo* request,
1155     BeforeSendHeadersCallback callback,
1156     net::HttpRequestHeaders* headers) {
1157   if (ShouldHideEvent(browser_context, *request))
1158     return net::OK;
1159 
1160   bool initialize_blocked_requests = false;
1161 
1162   initialize_blocked_requests |=
1163       ProcessDeclarativeRules(browser_context, keys::kOnBeforeSendHeadersEvent,
1164                               request, ON_BEFORE_SEND_HEADERS, nullptr);
1165 
1166   DCHECK(request->dnr_actions);
1167   initialize_blocked_requests |= std::any_of(
1168       request->dnr_actions->begin(), request->dnr_actions->end(),
1169       [](const DNRRequestAction& action) {
1170         return action.type == DNRRequestAction::Type::MODIFY_HEADERS &&
1171                !action.request_headers_to_modify.empty();
1172       });
1173 
1174   int extra_info_spec = 0;
1175   RawListeners listeners =
1176       GetMatchingListeners(browser_context, keys::kOnBeforeSendHeadersEvent,
1177                            request, &extra_info_spec);
1178   if (!listeners.empty() &&
1179       !GetAndSetSignaled(request->id, kOnBeforeSendHeaders)) {
1180     std::unique_ptr<WebRequestEventDetails> event_details(
1181         CreateEventDetails(*request, extra_info_spec));
1182     event_details->SetRequestHeaders(*headers);
1183 
1184     initialize_blocked_requests |= DispatchEvent(
1185         browser_context, request, listeners, std::move(event_details));
1186   }
1187 
1188   UMA_HISTOGRAM_ENUMERATION(
1189       "Extensions.WebRequest.OnBeforeSendHeadersEventResponse",
1190       initialize_blocked_requests ? WebRequestEventResponse::kObserved
1191                                   : WebRequestEventResponse::kIgnored);
1192 
1193   if (!initialize_blocked_requests)
1194     return net::OK;  // Nobody saw a reason for modifying the request.
1195 
1196   BlockedRequest& blocked_request = blocked_requests_[request->id];
1197   blocked_request.event = kOnBeforeSendHeaders;
1198   blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
1199   blocked_request.request = request;
1200   blocked_request.before_send_headers_callback = std::move(callback);
1201   blocked_request.request_headers = headers;
1202 
1203   if (blocked_request.num_handlers_blocking == 0) {
1204     // If there are no blocking handlers, only the declarative rules tried
1205     // to modify the request and we can respond synchronously.
1206     return ExecuteDeltas(browser_context, request, false /* call_callback*/);
1207   }
1208   return net::ERR_IO_PENDING;
1209 }
1210 
OnSendHeaders(content::BrowserContext * browser_context,const WebRequestInfo * request,const net::HttpRequestHeaders & headers)1211 void ExtensionWebRequestEventRouter::OnSendHeaders(
1212     content::BrowserContext* browser_context,
1213     const WebRequestInfo* request,
1214     const net::HttpRequestHeaders& headers) {
1215   if (ShouldHideEvent(browser_context, *request))
1216     return;
1217 
1218   if (GetAndSetSignaled(request->id, kOnSendHeaders))
1219     return;
1220 
1221   ClearSignaled(request->id, kOnBeforeRedirect);
1222 
1223   int extra_info_spec = 0;
1224   RawListeners listeners = GetMatchingListeners(
1225       browser_context, keys::kOnSendHeadersEvent, request, &extra_info_spec);
1226   if (listeners.empty())
1227     return;
1228 
1229   std::unique_ptr<WebRequestEventDetails> event_details(
1230       CreateEventDetails(*request, extra_info_spec));
1231   event_details->SetRequestHeaders(headers);
1232 
1233   DispatchEvent(browser_context, request, listeners, std::move(event_details));
1234 }
1235 
OnHeadersReceived(content::BrowserContext * browser_context,const WebRequestInfo * request,net::CompletionOnceCallback callback,const net::HttpResponseHeaders * original_response_headers,scoped_refptr<net::HttpResponseHeaders> * override_response_headers,GURL * preserve_fragment_on_redirect_url)1236 int ExtensionWebRequestEventRouter::OnHeadersReceived(
1237     content::BrowserContext* browser_context,
1238     const WebRequestInfo* request,
1239     net::CompletionOnceCallback callback,
1240     const net::HttpResponseHeaders* original_response_headers,
1241     scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
1242     GURL* preserve_fragment_on_redirect_url) {
1243   if (ShouldHideEvent(browser_context, *request))
1244     return net::OK;
1245 
1246   bool initialize_blocked_requests = false;
1247 
1248   DCHECK(request->dnr_actions);
1249   initialize_blocked_requests |= std::any_of(
1250       request->dnr_actions->begin(), request->dnr_actions->end(),
1251       [](const DNRRequestAction& action) {
1252         return action.type == DNRRequestAction::Type::MODIFY_HEADERS &&
1253                !action.response_headers_to_modify.empty();
1254       });
1255 
1256   initialize_blocked_requests |= ProcessDeclarativeRules(
1257       browser_context, keys::kOnHeadersReceivedEvent, request,
1258       ON_HEADERS_RECEIVED, original_response_headers);
1259 
1260   int extra_info_spec = 0;
1261   RawListeners listeners =
1262       GetMatchingListeners(browser_context, keys::kOnHeadersReceivedEvent,
1263                            request, &extra_info_spec);
1264 
1265   if (!listeners.empty() &&
1266       !GetAndSetSignaled(request->id, kOnHeadersReceived)) {
1267     std::unique_ptr<WebRequestEventDetails> event_details(
1268         CreateEventDetails(*request, extra_info_spec));
1269     event_details->SetResponseHeaders(*request, original_response_headers);
1270 
1271     initialize_blocked_requests |= DispatchEvent(
1272         browser_context, request, listeners, std::move(event_details));
1273   }
1274 
1275   UMA_HISTOGRAM_ENUMERATION(
1276       "Extensions.WebRequest.OnHeadersReceivedEventResponse",
1277       initialize_blocked_requests ? WebRequestEventResponse::kObserved
1278                                   : WebRequestEventResponse::kIgnored);
1279 
1280   if (!initialize_blocked_requests)
1281     return net::OK;  // Nobody saw a reason for modifying the request.
1282 
1283   BlockedRequest& blocked_request = blocked_requests_[request->id];
1284   blocked_request.event = kOnHeadersReceived;
1285   blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
1286   blocked_request.request = request;
1287   blocked_request.callback = std::move(callback);
1288   blocked_request.override_response_headers = override_response_headers;
1289   blocked_request.original_response_headers = original_response_headers;
1290   blocked_request.new_url = preserve_fragment_on_redirect_url;
1291 
1292   if (blocked_request.num_handlers_blocking == 0) {
1293     // If there are no blocking handlers, only the declarative rules tried
1294     // to modify the request and we can respond synchronously.
1295     return ExecuteDeltas(browser_context, request, false /* call_callback*/);
1296   }
1297   return net::ERR_IO_PENDING;
1298 }
1299 
1300 ExtensionWebRequestEventRouter::AuthRequiredResponse
OnAuthRequired(content::BrowserContext * browser_context,const WebRequestInfo * request,const net::AuthChallengeInfo & auth_info,AuthCallback callback,net::AuthCredentials * credentials)1301 ExtensionWebRequestEventRouter::OnAuthRequired(
1302     content::BrowserContext* browser_context,
1303     const WebRequestInfo* request,
1304     const net::AuthChallengeInfo& auth_info,
1305     AuthCallback callback,
1306     net::AuthCredentials* credentials) {
1307   // No browser_context means that this is for authentication challenges in the
1308   // system context. Skip in that case. Also skip sensitive requests.
1309   if (!browser_context ||
1310       WebRequestPermissions::HideRequest(PermissionHelper::Get(browser_context),
1311                                          *request)) {
1312     return AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1313   }
1314 
1315   int extra_info_spec = 0;
1316   RawListeners listeners = GetMatchingListeners(
1317       browser_context, keys::kOnAuthRequiredEvent, request, &extra_info_spec);
1318   if (listeners.empty())
1319     return AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1320 
1321   std::unique_ptr<WebRequestEventDetails> event_details(
1322       CreateEventDetails(*request, extra_info_spec));
1323   event_details->SetResponseHeaders(*request, request->response_headers.get());
1324   event_details->SetAuthInfo(auth_info);
1325 
1326   if (DispatchEvent(browser_context, request, listeners,
1327                     std::move(event_details))) {
1328     BlockedRequest& blocked_request = blocked_requests_[request->id];
1329     blocked_request.event = kOnAuthRequired;
1330     blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
1331     blocked_request.request = request;
1332     blocked_request.auth_callback = std::move(callback);
1333     blocked_request.auth_credentials = credentials;
1334     return AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_IO_PENDING;
1335   }
1336   return AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_NO_ACTION;
1337 }
1338 
OnBeforeRedirect(content::BrowserContext * browser_context,const WebRequestInfo * request,const GURL & new_location)1339 void ExtensionWebRequestEventRouter::OnBeforeRedirect(
1340     content::BrowserContext* browser_context,
1341     const WebRequestInfo* request,
1342     const GURL& new_location) {
1343   if (ShouldHideEvent(browser_context, *request))
1344     return;
1345 
1346   if (GetAndSetSignaled(request->id, kOnBeforeRedirect))
1347     return;
1348 
1349   ClearSignaled(request->id, kOnBeforeRequest);
1350   ClearSignaled(request->id, kOnBeforeSendHeaders);
1351   ClearSignaled(request->id, kOnSendHeaders);
1352   ClearSignaled(request->id, kOnHeadersReceived);
1353 
1354   int extra_info_spec = 0;
1355   RawListeners listeners = GetMatchingListeners(
1356       browser_context, keys::kOnBeforeRedirectEvent, request, &extra_info_spec);
1357   if (listeners.empty())
1358     return;
1359 
1360   std::unique_ptr<WebRequestEventDetails> event_details(
1361       CreateEventDetails(*request, extra_info_spec));
1362   event_details->SetResponseHeaders(*request, request->response_headers.get());
1363   event_details->SetResponseSource(*request);
1364   event_details->SetString(keys::kRedirectUrlKey, new_location.spec());
1365 
1366   DispatchEvent(browser_context, request, listeners, std::move(event_details));
1367 }
1368 
OnResponseStarted(content::BrowserContext * browser_context,const WebRequestInfo * request,int net_error)1369 void ExtensionWebRequestEventRouter::OnResponseStarted(
1370     content::BrowserContext* browser_context,
1371     const WebRequestInfo* request,
1372     int net_error) {
1373   DCHECK_NE(net::ERR_IO_PENDING, net_error);
1374 
1375   if (ShouldHideEvent(browser_context, *request))
1376     return;
1377 
1378   // OnResponseStarted is even triggered, when the request was cancelled.
1379   if (net_error != net::OK)
1380     return;
1381 
1382   int extra_info_spec = 0;
1383   RawListeners listeners =
1384       GetMatchingListeners(browser_context, keys::kOnResponseStartedEvent,
1385                            request, &extra_info_spec);
1386   if (listeners.empty())
1387     return;
1388 
1389   std::unique_ptr<WebRequestEventDetails> event_details(
1390       CreateEventDetails(*request, extra_info_spec));
1391   event_details->SetResponseHeaders(*request, request->response_headers.get());
1392   event_details->SetResponseSource(*request);
1393 
1394   DispatchEvent(browser_context, request, listeners, std::move(event_details));
1395 }
1396 
OnCompleted(content::BrowserContext * browser_context,const WebRequestInfo * request,int net_error)1397 void ExtensionWebRequestEventRouter::OnCompleted(
1398     content::BrowserContext* browser_context,
1399     const WebRequestInfo* request,
1400     int net_error) {
1401   // We hide events from the system context as well as sensitive requests.
1402   // However, if the request first became sensitive after redirecting we have
1403   // already signaled it and thus we have to signal the end of it. This is
1404   // risk-free because the handler cannot modify the request now.
1405   if (!browser_context ||
1406       (WebRequestPermissions::HideRequest(
1407            PermissionHelper::Get(browser_context), *request) &&
1408        !WasSignaled(*request))) {
1409     return;
1410   }
1411 
1412   request_time_tracker_->LogRequestEndTime(request->id, base::TimeTicks::Now());
1413 
1414   // See comment in OnErrorOccurred regarding net::ERR_WS_UPGRADE.
1415   DCHECK(net_error == net::OK || net_error == net::ERR_WS_UPGRADE);
1416 
1417   DCHECK(!GetAndSetSignaled(request->id, kOnCompleted));
1418 
1419   ClearPendingCallbacks(*request);
1420 
1421   int extra_info_spec = 0;
1422   RawListeners listeners = GetMatchingListeners(
1423       browser_context, keys::kOnCompletedEvent, request, &extra_info_spec);
1424   if (listeners.empty())
1425     return;
1426 
1427   std::unique_ptr<WebRequestEventDetails> event_details(
1428       CreateEventDetails(*request, extra_info_spec));
1429   event_details->SetResponseHeaders(*request, request->response_headers.get());
1430   event_details->SetResponseSource(*request);
1431 
1432   DispatchEvent(browser_context, request, listeners, std::move(event_details));
1433 }
1434 
OnErrorOccurred(content::BrowserContext * browser_context,const WebRequestInfo * request,bool started,int net_error)1435 void ExtensionWebRequestEventRouter::OnErrorOccurred(
1436     content::BrowserContext* browser_context,
1437     const WebRequestInfo* request,
1438     bool started,
1439     int net_error) {
1440   // When WebSocket handshake request finishes, the request is cancelled with an
1441   // ERR_WS_UPGRADE code (see WebSocketStreamRequestImpl::PerformUpgrade).
1442   // WebRequest API reports this as a completed request.
1443   if (net_error == net::ERR_WS_UPGRADE) {
1444     OnCompleted(browser_context, request, net_error);
1445     return;
1446   }
1447 
1448   ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get();
1449   if (!client) {
1450     // |client| could be NULL during shutdown.
1451     return;
1452   }
1453   // We hide events from the system context as well as sensitive requests.
1454   // However, if the request first became sensitive after redirecting we have
1455   // already signaled it and thus we have to signal the end of it. This is
1456   // risk-free because the handler cannot modify the request now.
1457   if (!browser_context ||
1458       (WebRequestPermissions::HideRequest(
1459            PermissionHelper::Get(browser_context), *request) &&
1460        !WasSignaled(*request))) {
1461     return;
1462   }
1463 
1464   request_time_tracker_->LogRequestEndTime(request->id, base::TimeTicks::Now());
1465 
1466   DCHECK_NE(net::OK, net_error);
1467   DCHECK_NE(net::ERR_IO_PENDING, net_error);
1468 
1469   DCHECK(!GetAndSetSignaled(request->id, kOnErrorOccurred));
1470 
1471   ClearPendingCallbacks(*request);
1472 
1473   int extra_info_spec = 0;
1474   RawListeners listeners = GetMatchingListeners(
1475       browser_context, web_request::OnErrorOccurred::kEventName, request,
1476       &extra_info_spec);
1477   if (listeners.empty())
1478     return;
1479 
1480   std::unique_ptr<WebRequestEventDetails> event_details(
1481       CreateEventDetails(*request, extra_info_spec));
1482   if (started)
1483     event_details->SetResponseSource(*request);
1484   else
1485     event_details->SetBoolean(keys::kFromCache, request->response_from_cache);
1486   event_details->SetString(keys::kErrorKey, net::ErrorToString(net_error));
1487 
1488   DispatchEvent(browser_context, request, listeners, std::move(event_details));
1489 }
1490 
OnRequestWillBeDestroyed(content::BrowserContext * browser_context,const WebRequestInfo * request)1491 void ExtensionWebRequestEventRouter::OnRequestWillBeDestroyed(
1492     content::BrowserContext* browser_context,
1493     const WebRequestInfo* request) {
1494   ClearPendingCallbacks(*request);
1495   signaled_requests_.erase(request->id);
1496   request_time_tracker_->LogRequestEndTime(request->id, base::TimeTicks::Now());
1497 }
1498 
ClearPendingCallbacks(const WebRequestInfo & request)1499 void ExtensionWebRequestEventRouter::ClearPendingCallbacks(
1500     const WebRequestInfo& request) {
1501   blocked_requests_.erase(request.id);
1502 }
1503 
DispatchEvent(content::BrowserContext * browser_context,const WebRequestInfo * request,const RawListeners & listeners,std::unique_ptr<WebRequestEventDetails> event_details)1504 bool ExtensionWebRequestEventRouter::DispatchEvent(
1505     content::BrowserContext* browser_context,
1506     const WebRequestInfo* request,
1507     const RawListeners& listeners,
1508     std::unique_ptr<WebRequestEventDetails> event_details) {
1509   // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
1510   // pairs into a single message sent to a list of sub_event_names.
1511   int num_handlers_blocking = 0;
1512 
1513   std::unique_ptr<ListenerIDs> listeners_to_dispatch(new ListenerIDs);
1514   listeners_to_dispatch->reserve(listeners.size());
1515   for (EventListener* listener : listeners) {
1516     listeners_to_dispatch->push_back(listener->id);
1517     if (listener->extra_info_spec &
1518         (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) {
1519       listener->blocked_requests.insert(request->id);
1520       ++num_handlers_blocking;
1521     }
1522   }
1523 
1524   DispatchEventToListeners(browser_context, std::move(listeners_to_dispatch),
1525                            std::move(event_details));
1526 
1527   if (num_handlers_blocking > 0) {
1528     BlockedRequest& blocked_request = blocked_requests_[request->id];
1529     blocked_request.request = request;
1530     blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
1531     blocked_request.num_handlers_blocking += num_handlers_blocking;
1532     blocked_request.blocking_time = base::Time::Now();
1533     return true;
1534   }
1535 
1536   return false;
1537 }
1538 
DispatchEventToListeners(content::BrowserContext * browser_context,std::unique_ptr<ListenerIDs> listener_ids,std::unique_ptr<WebRequestEventDetails> event_details)1539 void ExtensionWebRequestEventRouter::DispatchEventToListeners(
1540     content::BrowserContext* browser_context,
1541     std::unique_ptr<ListenerIDs> listener_ids,
1542     std::unique_ptr<WebRequestEventDetails> event_details) {
1543   DCHECK_CURRENTLY_ON(BrowserThread::UI);
1544   DCHECK(!listener_ids->empty());
1545   DCHECK(event_details.get());
1546 
1547   std::string event_name =
1548       EventRouter::GetBaseEventName((*listener_ids)[0].sub_event_name);
1549   DCHECK(IsWebRequestEvent(event_name));
1550 
1551   Listeners& event_listeners = listeners_[browser_context][event_name];
1552   content::BrowserContext* cross_browser_context =
1553       GetCrossBrowserContext(browser_context);
1554   Listeners* cross_event_listeners =
1555       cross_browser_context ? &listeners_[cross_browser_context][event_name]
1556                             : nullptr;
1557 
1558   std::unique_ptr<WebRequestEventDetails> event_details_filtered_copy;
1559 
1560   for (const EventListener::ID& id : *listener_ids) {
1561     // It's possible that the listener is no longer present. Check to make sure
1562     // it's still there.
1563     const EventListener* listener =
1564         FindEventListenerInContainer(id, event_listeners);
1565     bool crosses_incognito = false;
1566     if (!listener && cross_event_listeners) {
1567       listener = FindEventListenerInContainer(id, *cross_event_listeners);
1568       crosses_incognito = true;
1569     }
1570     if (!listener)
1571       continue;
1572 
1573     auto* rph = content::RenderProcessHost::FromID(id.render_process_id);
1574     if (!rph)
1575       continue;
1576 
1577     // Filter out the optional keys that this listener didn't request.
1578     std::unique_ptr<base::ListValue> args_filtered(new base::ListValue);
1579 
1580     // In Public Sessions we want to restrict access to security or privacy
1581     // sensitive data. Data is filtered for *all* listeners, not only extensions
1582     // which are force-installed by policy. Whitelisted extensions are exempt
1583     // from this filtering.
1584     WebRequestEventDetails* custom_event_details = event_details.get();
1585     if (ArePublicSessionRestrictionsEnabled() &&
1586         !extensions::IsWhitelistedForPublicSession(listener->id.extension_id)) {
1587       if (!event_details_filtered_copy) {
1588         event_details_filtered_copy =
1589             event_details->CreatePublicSessionCopy();
1590       }
1591       custom_event_details = event_details_filtered_copy.get();
1592     }
1593     args_filtered->Append(custom_event_details->GetFilteredDict(
1594         listener->extra_info_spec, PermissionHelper::Get(browser_context),
1595         listener->id.extension_id, crosses_incognito));
1596 
1597     EventRouter::DispatchEventToSender(
1598         rph, browser_context, listener->id.extension_id,
1599         listener->histogram_value, listener->id.sub_event_name,
1600         listener->id.render_process_id, listener->id.worker_thread_id,
1601         listener->id.service_worker_version_id, std::move(args_filtered),
1602         EventFilteringInfo());
1603   }
1604 }
1605 
OnEventHandled(content::BrowserContext * browser_context,const std::string & extension_id,const std::string & event_name,const std::string & sub_event_name,uint64_t request_id,int render_process_id,int web_view_instance_id,int worker_thread_id,int64_t service_worker_version_id,EventResponse * response)1606 void ExtensionWebRequestEventRouter::OnEventHandled(
1607     content::BrowserContext* browser_context,
1608     const std::string& extension_id,
1609     const std::string& event_name,
1610     const std::string& sub_event_name,
1611     uint64_t request_id,
1612     int render_process_id,
1613     int web_view_instance_id,
1614     int worker_thread_id,
1615     int64_t service_worker_version_id,
1616     EventResponse* response) {
1617   Listeners& listeners = listeners_[browser_context][event_name];
1618   EventListener::ID id(browser_context, extension_id, sub_event_name,
1619                        render_process_id, web_view_instance_id,
1620                        worker_thread_id, service_worker_version_id);
1621   EventListener* listener = FindEventListenerInContainer(id, listeners);
1622 
1623   // This might happen, for example, if the extension has been unloaded.
1624   if (!listener)
1625     return;
1626 
1627   listener->blocked_requests.erase(request_id);
1628   DecrementBlockCount(browser_context, extension_id, event_name, request_id,
1629                       response, listener->extra_info_spec);
1630 }
1631 
AddEventListener(content::BrowserContext * browser_context,const std::string & extension_id,const std::string & extension_name,events::HistogramValue histogram_value,const std::string & event_name,const std::string & sub_event_name,const RequestFilter & filter,int extra_info_spec,int render_process_id,int web_view_instance_id,int worker_thread_id,int64_t service_worker_version_id)1632 bool ExtensionWebRequestEventRouter::AddEventListener(
1633     content::BrowserContext* browser_context,
1634     const std::string& extension_id,
1635     const std::string& extension_name,
1636     events::HistogramValue histogram_value,
1637     const std::string& event_name,
1638     const std::string& sub_event_name,
1639     const RequestFilter& filter,
1640     int extra_info_spec,
1641     int render_process_id,
1642     int web_view_instance_id,
1643     int worker_thread_id,
1644     int64_t service_worker_version_id) {
1645   if (!IsWebRequestEvent(event_name))
1646     return false;
1647 
1648   if (event_name != EventRouter::GetBaseEventName(sub_event_name))
1649     return false;
1650 
1651   EventListener::ID id(browser_context, extension_id, sub_event_name,
1652                        render_process_id, web_view_instance_id,
1653                        worker_thread_id, service_worker_version_id);
1654   if (FindEventListener(id) != nullptr) {
1655     // This is likely an abuse of the API by a malicious extension.
1656     return false;
1657   }
1658 
1659   std::unique_ptr<EventListener> listener(new EventListener(id));
1660   listener->extension_name = extension_name;
1661   listener->histogram_value = histogram_value;
1662   listener->filter = filter;
1663   listener->extra_info_spec = extra_info_spec;
1664   if (web_view_instance_id) {
1665     base::RecordAction(
1666         base::UserMetricsAction("WebView.WebRequest.AddListener"));
1667   }
1668 
1669   RecordAddEventListenerUMAs(extra_info_spec);
1670 
1671   listeners_[browser_context][event_name].push_back(std::move(listener));
1672 
1673   if (extra_info_spec & ExtraInfoSpec::EXTRA_HEADERS)
1674     IncrementExtraHeadersListenerCount(browser_context);
1675 
1676   return true;
1677 }
1678 
GetListenerCountForTesting(content::BrowserContext * browser_context,const std::string & event_name)1679 size_t ExtensionWebRequestEventRouter::GetListenerCountForTesting(
1680     content::BrowserContext* browser_context,
1681     const std::string& event_name) {
1682   return listeners_[browser_context][event_name].size();
1683 }
1684 
1685 ExtensionWebRequestEventRouter::EventListener*
FindEventListener(const EventListener::ID & id)1686 ExtensionWebRequestEventRouter::FindEventListener(const EventListener::ID& id) {
1687   DCHECK_CURRENTLY_ON(BrowserThread::UI);
1688   std::string event_name = EventRouter::GetBaseEventName(id.sub_event_name);
1689   Listeners& listeners = listeners_[id.browser_context][event_name];
1690   return FindEventListenerInContainer(id, listeners);
1691 }
1692 
1693 ExtensionWebRequestEventRouter::EventListener*
FindEventListenerInContainer(const EventListener::ID & id,Listeners & listeners)1694 ExtensionWebRequestEventRouter::FindEventListenerInContainer(
1695     const EventListener::ID& id,
1696     Listeners& listeners) {
1697   for (auto it = listeners.begin(); it != listeners.end(); ++it) {
1698     if ((*it)->id == id) {
1699       return it->get();
1700     }
1701   }
1702   return nullptr;
1703 }
1704 
RemoveEventListener(const EventListener::ID & id,bool strict)1705 void ExtensionWebRequestEventRouter::RemoveEventListener(
1706     const EventListener::ID& id,
1707     bool strict) {
1708   DCHECK_CURRENTLY_ON(BrowserThread::UI);
1709 
1710   std::string event_name = EventRouter::GetBaseEventName(id.sub_event_name);
1711   Listeners& listeners = listeners_[id.browser_context][event_name];
1712   for (auto it = listeners.begin(); it != listeners.end(); ++it) {
1713     std::unique_ptr<EventListener>& listener = *it;
1714 
1715     // There are two places that call this method: RemoveWebViewEventListeners
1716     // and OnListenerRemoved. The latter can't use operator== because it doesn't
1717     // have the render_process_id. This shouldn't be a problem, because
1718     // OnListenerRemoved is only called for web_view_instance_id == 0.
1719     bool matches =
1720         strict ? listener->id == id : listener->id.LooselyMatches(id);
1721     if (matches) {
1722       // Unblock any request that this event listener may have been blocking.
1723       for (uint64_t blocked_request_id : listener->blocked_requests) {
1724         DecrementBlockCount(
1725             listener->id.browser_context, listener->id.extension_id, event_name,
1726             blocked_request_id, nullptr, 0 /* extra_info_spec */);
1727       }
1728 
1729       if (listener->extra_info_spec & ExtraInfoSpec::EXTRA_HEADERS)
1730         DecrementExtraHeadersListenerCount(listener->id.browser_context);
1731 
1732       listeners.erase(it);
1733       helpers::ClearCacheOnNavigation();
1734       return;
1735     }
1736   }
1737 }
1738 
RemoveWebViewEventListeners(content::BrowserContext * browser_context,int render_process_id,int web_view_instance_id)1739 void ExtensionWebRequestEventRouter::RemoveWebViewEventListeners(
1740     content::BrowserContext* browser_context,
1741     int render_process_id,
1742     int web_view_instance_id) {
1743   DCHECK_CURRENTLY_ON(BrowserThread::UI);
1744 
1745   // Iterate over all listeners of all WebRequest events to delete
1746   // any listeners that belong to the provided <webview>.
1747   ListenerMapForBrowserContext& map_for_browser_context =
1748       listeners_[browser_context];
1749   for (const auto& event_iter : map_for_browser_context) {
1750     // Construct a listeners_to_delete vector so that we don't modify the set of
1751     // listeners as we iterate through it.
1752     std::vector<EventListener::ID> listeners_to_delete;
1753     const Listeners& listeners = event_iter.second;
1754     for (const auto& listener : listeners) {
1755       if (listener->id.render_process_id == render_process_id &&
1756           listener->id.web_view_instance_id == web_view_instance_id) {
1757         listeners_to_delete.push_back(listener->id);
1758       }
1759     }
1760     // Remove the listeners selected for deletion.
1761     for (const auto& listener_id : listeners_to_delete)
1762       RemoveEventListener(listener_id, true /* strict */);
1763   }
1764 }
1765 
OnOTRBrowserContextCreated(content::BrowserContext * original_browser_context,content::BrowserContext * otr_browser_context)1766 void ExtensionWebRequestEventRouter::OnOTRBrowserContextCreated(
1767     content::BrowserContext* original_browser_context,
1768     content::BrowserContext* otr_browser_context) {
1769   cross_browser_context_map_[original_browser_context] =
1770       std::make_pair(false, otr_browser_context);
1771   cross_browser_context_map_[otr_browser_context] =
1772       std::make_pair(true, original_browser_context);
1773 }
1774 
OnOTRBrowserContextDestroyed(content::BrowserContext * original_browser_context,content::BrowserContext * otr_browser_context)1775 void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
1776     content::BrowserContext* original_browser_context,
1777     content::BrowserContext* otr_browser_context) {
1778   cross_browser_context_map_.erase(otr_browser_context);
1779   cross_browser_context_map_.erase(original_browser_context);
1780 }
1781 
AddCallbackForPageLoad(const base::Closure & callback)1782 void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
1783     const base::Closure& callback) {
1784   callbacks_for_page_load_.push_back(callback);
1785 }
1786 
HasExtraHeadersListenerForRequest(content::BrowserContext * browser_context,const WebRequestInfo * request)1787 bool ExtensionWebRequestEventRouter::HasExtraHeadersListenerForRequest(
1788     content::BrowserContext* browser_context,
1789     const WebRequestInfo* request) {
1790   DCHECK(request);
1791   if (ShouldHideEvent(browser_context, *request))
1792     return false;
1793 
1794   int extra_info_spec = 0;
1795   for (const char* name : kWebRequestEvents) {
1796     GetMatchingListeners(browser_context, name, request, &extra_info_spec);
1797     if (extra_info_spec & ExtraInfoSpec::EXTRA_HEADERS)
1798       return true;
1799   }
1800 
1801   // Check declarative net request API rulesets.
1802   return declarative_net_request::RulesMonitorService::Get(browser_context)
1803       ->ruleset_manager()
1804       ->HasExtraHeadersMatcherForRequest(
1805           *request, IsIncognitoBrowserContext(browser_context));
1806 }
1807 
HasAnyExtraHeadersListener(content::BrowserContext * browser_context)1808 bool ExtensionWebRequestEventRouter::HasAnyExtraHeadersListener(
1809     content::BrowserContext* browser_context) {
1810   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
1811   if (HasAnyExtraHeadersListenerImpl(browser_context))
1812     return true;
1813 
1814   content::BrowserContext* cross_browser_context =
1815       GetCrossBrowserContext(browser_context);
1816   if (cross_browser_context)
1817     return HasAnyExtraHeadersListenerImpl(cross_browser_context);
1818 
1819   return false;
1820 }
1821 
IncrementExtraHeadersListenerCount(content::BrowserContext * browser_context)1822 void ExtensionWebRequestEventRouter::IncrementExtraHeadersListenerCount(
1823     content::BrowserContext* browser_context) {
1824   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
1825 
1826   // Try inserting the |browser_context| key, assuming it is not there. Note:
1827   // emplace returns a pair consisting of an iterator to the inserted element,
1828   // or the already-existing element if no insertion happened, and a bool
1829   // denoting whether the insertion took place.
1830   auto result = extra_headers_listener_count_.emplace(browser_context, 1);
1831 
1832   // If the insert failed, increment the existing value.
1833   if (!result.second) {
1834     // We only keep values greater than 0 in the map.
1835     DCHECK_GT(result.first->second, 0);
1836     result.first->second++;
1837     return;
1838   }
1839 }
1840 
DecrementExtraHeadersListenerCount(content::BrowserContext * browser_context)1841 void ExtensionWebRequestEventRouter::DecrementExtraHeadersListenerCount(
1842     content::BrowserContext* browser_context) {
1843   auto it = extra_headers_listener_count_.find(browser_context);
1844   DCHECK(it != extra_headers_listener_count_.end());
1845   it->second--;
1846   if (it->second > 0)
1847     return;
1848 
1849   DCHECK_EQ(0, it->second);
1850   extra_headers_listener_count_.erase(it);
1851 }
1852 
HasAnyExtraHeadersListenerImpl(content::BrowserContext * browser_context)1853 bool ExtensionWebRequestEventRouter::HasAnyExtraHeadersListenerImpl(
1854     content::BrowserContext* browser_context) {
1855   return base::Contains(extra_headers_listener_count_, browser_context);
1856 }
1857 
IsPageLoad(const WebRequestInfo & request) const1858 bool ExtensionWebRequestEventRouter::IsPageLoad(
1859     const WebRequestInfo& request) const {
1860   return request.web_request_type == WebRequestResourceType::MAIN_FRAME;
1861 }
1862 
NotifyPageLoad()1863 void ExtensionWebRequestEventRouter::NotifyPageLoad() {
1864   for (const auto& callback : callbacks_for_page_load_)
1865     callback.Run();
1866   callbacks_for_page_load_.clear();
1867 }
1868 
GetCrossBrowserContext(content::BrowserContext * browser_context) const1869 content::BrowserContext* ExtensionWebRequestEventRouter::GetCrossBrowserContext(
1870     content::BrowserContext* browser_context) const {
1871   auto cross_browser_context = cross_browser_context_map_.find(browser_context);
1872   if (cross_browser_context == cross_browser_context_map_.end())
1873     return NULL;
1874   return cross_browser_context->second.second;
1875 }
1876 
IsIncognitoBrowserContext(content::BrowserContext * browser_context) const1877 bool ExtensionWebRequestEventRouter::IsIncognitoBrowserContext(
1878     content::BrowserContext* browser_context) const {
1879   auto cross_browser_context = cross_browser_context_map_.find(browser_context);
1880   if (cross_browser_context == cross_browser_context_map_.end())
1881     return false;
1882   return cross_browser_context->second.first;
1883 }
1884 
WasSignaled(const WebRequestInfo & request) const1885 bool ExtensionWebRequestEventRouter::WasSignaled(
1886     const WebRequestInfo& request) const {
1887   auto flag = signaled_requests_.find(request.id);
1888   return flag != signaled_requests_.end() && flag->second != 0;
1889 }
1890 
GetMatchingListenersImpl(content::BrowserContext * browser_context,const WebRequestInfo * request,bool crosses_incognito,const std::string & event_name,bool is_request_from_extension,int * extra_info_spec,RawListeners * matching_listeners)1891 void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
1892     content::BrowserContext* browser_context,
1893     const WebRequestInfo* request,
1894     bool crosses_incognito,
1895     const std::string& event_name,
1896     bool is_request_from_extension,
1897     int* extra_info_spec,
1898     RawListeners* matching_listeners) {
1899   std::string web_request_event_name(event_name);
1900   if (request->is_web_view) {
1901     web_request_event_name.replace(
1902         0, sizeof(kWebRequestEventPrefix) - 1, webview::kWebViewEventPrefix);
1903   }
1904 
1905   Listeners& listeners = listeners_[browser_context][web_request_event_name];
1906   for (std::unique_ptr<EventListener>& listener : listeners) {
1907     if (!content::RenderProcessHost::FromID(listener->id.render_process_id)) {
1908       // The IPC sender has been deleted. This listener will be removed soon
1909       // via a call to RemoveEventListener. For now, just skip it.
1910       continue;
1911     }
1912 
1913     if (request->is_web_view) {
1914       // If this is a navigation request, then we can skip this check. IDs will
1915       // be -1 and the request is trusted.
1916       if (!request->is_navigation_request &&
1917           (listener->id.render_process_id !=
1918            request->web_view_embedder_process_id)) {
1919         continue;
1920       }
1921 
1922       if (listener->id.web_view_instance_id != request->web_view_instance_id)
1923         continue;
1924     }
1925 
1926     // Filter requests from other extensions / apps. This does not work for
1927     // content scripts, or extension pages in non-extension processes.
1928     if (is_request_from_extension &&
1929         listener->id.render_process_id != request->render_process_id) {
1930       continue;
1931     }
1932 
1933     if (!listener->filter.urls.is_empty() &&
1934         !listener->filter.urls.MatchesURL(request->url)) {
1935       continue;
1936     }
1937 
1938     // Check if the tab id and window id match, if they were set in the
1939     // listener params.
1940     if ((listener->filter.tab_id != -1 &&
1941          request->frame_data.tab_id != listener->filter.tab_id) ||
1942         (listener->filter.window_id != -1 &&
1943          request->frame_data.window_id != listener->filter.window_id)) {
1944       continue;
1945     }
1946 
1947     const std::vector<WebRequestResourceType>& types = listener->filter.types;
1948     if (!types.empty() && !base::Contains(types, request->web_request_type)) {
1949       continue;
1950     }
1951 
1952     if (!request->is_web_view) {
1953       PermissionsData::PageAccess access =
1954           WebRequestPermissions::CanExtensionAccessURL(
1955               PermissionHelper::Get(browser_context), listener->id.extension_id,
1956               request->url, request->frame_data.tab_id, crosses_incognito,
1957               WebRequestPermissions::
1958                   REQUIRE_HOST_PERMISSION_FOR_URL_AND_INITIATOR,
1959               request->initiator, request->web_request_type);
1960 
1961       if (access != PermissionsData::PageAccess::kAllowed) {
1962         if (access == PermissionsData::PageAccess::kWithheld) {
1963           DCHECK(ExtensionsAPIClient::Get());
1964           ExtensionsAPIClient::Get()->NotifyWebRequestWithheld(
1965               request->render_process_id, request->frame_id,
1966               listener->id.extension_id);
1967         }
1968         continue;
1969       }
1970     }
1971 
1972     bool blocking_listener =
1973         (listener->extra_info_spec &
1974          (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) != 0;
1975 
1976     // We do not want to notify extensions about XHR requests that are
1977     // triggered by themselves. This is a workaround to prevent deadlocks
1978     // in case of synchronous XHR requests that block the extension renderer
1979     // and therefore prevent the extension from processing the request
1980     // handler. This is only a problem for blocking listeners.
1981     // http://crbug.com/105656
1982     bool synchronous_xhr_from_extension =
1983         !request->is_async && is_request_from_extension &&
1984         request->web_request_type == WebRequestResourceType::XHR;
1985 
1986     // Only send webRequest events for URLs the extension has access to.
1987     if (blocking_listener && synchronous_xhr_from_extension)
1988       continue;
1989 
1990     matching_listeners->push_back(listener.get());
1991     *extra_info_spec |= listener->extra_info_spec;
1992   }
1993 }
1994 
1995 ExtensionWebRequestEventRouter::RawListeners
GetMatchingListeners(content::BrowserContext * browser_context,const std::string & event_name,const WebRequestInfo * request,int * extra_info_spec)1996 ExtensionWebRequestEventRouter::GetMatchingListeners(
1997     content::BrowserContext* browser_context,
1998     const std::string& event_name,
1999     const WebRequestInfo* request,
2000     int* extra_info_spec) {
2001   // TODO(mpcomplete): handle browser_context == NULL (should collect all
2002   // listeners).
2003   *extra_info_spec = 0;
2004 
2005   bool is_request_from_extension =
2006       IsRequestFromExtension(*request, browser_context);
2007 
2008   RawListeners matching_listeners;
2009   GetMatchingListenersImpl(browser_context, request, false, event_name,
2010                            is_request_from_extension, extra_info_spec,
2011                            &matching_listeners);
2012   content::BrowserContext* cross_browser_context =
2013       GetCrossBrowserContext(browser_context);
2014   if (cross_browser_context) {
2015     GetMatchingListenersImpl(cross_browser_context, request, true, event_name,
2016                              is_request_from_extension, extra_info_spec,
2017                              &matching_listeners);
2018   }
2019 
2020   return matching_listeners;
2021 }
2022 
2023 namespace {
2024 
CalculateDelta(content::BrowserContext * browser_context,ExtensionWebRequestEventRouter::BlockedRequest * blocked_request,ExtensionWebRequestEventRouter::EventResponse * response,int extra_info_spec)2025 helpers::EventResponseDelta CalculateDelta(
2026     content::BrowserContext* browser_context,
2027     ExtensionWebRequestEventRouter::BlockedRequest* blocked_request,
2028     ExtensionWebRequestEventRouter::EventResponse* response,
2029     int extra_info_spec) {
2030   switch (blocked_request->event) {
2031     case ExtensionWebRequestEventRouter::kOnBeforeRequest:
2032       return helpers::CalculateOnBeforeRequestDelta(
2033           response->extension_id, response->extension_install_time,
2034           response->cancel, response->new_url);
2035     case ExtensionWebRequestEventRouter::kOnBeforeSendHeaders: {
2036       net::HttpRequestHeaders* old_headers = blocked_request->request_headers;
2037       net::HttpRequestHeaders* new_headers = response->request_headers.get();
2038       return helpers::CalculateOnBeforeSendHeadersDelta(
2039           browser_context, response->extension_id,
2040           response->extension_install_time, response->cancel, old_headers,
2041           new_headers, extra_info_spec);
2042     }
2043     case ExtensionWebRequestEventRouter::kOnHeadersReceived: {
2044       const net::HttpResponseHeaders* old_headers =
2045           blocked_request->original_response_headers.get();
2046       helpers::ResponseHeaders* new_headers =
2047           response->response_headers.get();
2048       return helpers::CalculateOnHeadersReceivedDelta(
2049           response->extension_id, response->extension_install_time,
2050           response->cancel, blocked_request->request->url, response->new_url,
2051           old_headers, new_headers, extra_info_spec);
2052     }
2053     case ExtensionWebRequestEventRouter::kOnAuthRequired:
2054       return helpers::CalculateOnAuthRequiredDelta(
2055           response->extension_id, response->extension_install_time,
2056           response->cancel, response->auth_credentials);
2057     default:
2058       NOTREACHED();
2059       return helpers::EventResponseDelta("", base::Time());
2060   }
2061 }
2062 
SerializeResponseHeaders(const helpers::ResponseHeaders & headers)2063 std::unique_ptr<base::Value> SerializeResponseHeaders(
2064     const helpers::ResponseHeaders& headers) {
2065   auto serialized_headers = std::make_unique<base::ListValue>();
2066   for (const auto& it : headers) {
2067     serialized_headers->Append(
2068         helpers::CreateHeaderDictionary(it.first, it.second));
2069   }
2070   return std::move(serialized_headers);
2071 }
2072 
2073 // Convert a RequestCookieModifications/ResponseCookieModifications object to a
2074 // base::ListValue which summarizes the changes made.  This is templated since
2075 // the two types (request/response) are different but contain essentially the
2076 // same fields.
2077 template <typename CookieType>
SummarizeCookieModifications(const std::vector<CookieType> & modifications)2078 std::unique_ptr<base::ListValue> SummarizeCookieModifications(
2079     const std::vector<CookieType>& modifications) {
2080   auto cookie_modifications = std::make_unique<base::ListValue>();
2081   for (const CookieType& mod : modifications) {
2082     auto summary = std::make_unique<base::DictionaryValue>();
2083     switch (mod.type) {
2084       case helpers::ADD:
2085         summary->SetString(activity_log::kCookieModificationTypeKey,
2086                            activity_log::kCookieModificationAdd);
2087         break;
2088       case helpers::EDIT:
2089         summary->SetString(activity_log::kCookieModificationTypeKey,
2090                            activity_log::kCookieModificationEdit);
2091         break;
2092       case helpers::REMOVE:
2093         summary->SetString(activity_log::kCookieModificationTypeKey,
2094                            activity_log::kCookieModificationRemove);
2095         break;
2096     }
2097     if (mod.filter) {
2098       if (mod.filter->name) {
2099         summary->SetString(activity_log::kCookieFilterNameKey,
2100                            *mod.modification->name);
2101       }
2102       if (mod.filter->domain) {
2103         summary->SetString(activity_log::kCookieFilterDomainKey,
2104                            *mod.modification->name);
2105       }
2106     }
2107     if (mod.modification) {
2108       if (mod.modification->name) {
2109         summary->SetString(activity_log::kCookieModDomainKey,
2110                            *mod.modification->name);
2111       }
2112       if (mod.modification->domain) {
2113         summary->SetString(activity_log::kCookieModDomainKey,
2114                            *mod.modification->name);
2115       }
2116     }
2117     cookie_modifications->Append(std::move(summary));
2118   }
2119   return cookie_modifications;
2120 }
2121 
2122 // Converts an EventResponseDelta object to a dictionary value suitable for the
2123 // activity log.
SummarizeResponseDelta(const std::string & event_name,const helpers::EventResponseDelta & delta)2124 std::unique_ptr<base::DictionaryValue> SummarizeResponseDelta(
2125     const std::string& event_name,
2126     const helpers::EventResponseDelta& delta) {
2127   std::unique_ptr<base::DictionaryValue> details(new base::DictionaryValue());
2128   if (delta.cancel)
2129     details->SetBoolean(activity_log::kCancelKey, true);
2130   if (!delta.new_url.is_empty())
2131     details->SetString(activity_log::kNewUrlKey, delta.new_url.spec());
2132 
2133   std::unique_ptr<base::ListValue> modified_headers(new base::ListValue());
2134   net::HttpRequestHeaders::Iterator iter(delta.modified_request_headers);
2135   while (iter.GetNext()) {
2136     modified_headers->Append(
2137         helpers::CreateHeaderDictionary(iter.name(), iter.value()));
2138   }
2139   if (!modified_headers->empty()) {
2140     details->Set(activity_log::kModifiedRequestHeadersKey,
2141                  std::move(modified_headers));
2142   }
2143 
2144   std::unique_ptr<base::ListValue> deleted_headers(new base::ListValue());
2145   deleted_headers->AppendStrings(delta.deleted_request_headers);
2146   if (!deleted_headers->empty()) {
2147     details->Set(activity_log::kDeletedRequestHeadersKey,
2148                  std::move(deleted_headers));
2149   }
2150 
2151   if (!delta.added_response_headers.empty()) {
2152     details->Set(activity_log::kAddedRequestHeadersKey,
2153                  SerializeResponseHeaders(delta.added_response_headers));
2154   }
2155   if (!delta.deleted_response_headers.empty()) {
2156     details->Set(activity_log::kDeletedResponseHeadersKey,
2157                  SerializeResponseHeaders(delta.deleted_response_headers));
2158   }
2159   if (delta.auth_credentials.has_value()) {
2160     details->SetString(
2161         activity_log::kAuthCredentialsKey,
2162         base::UTF16ToUTF8(delta.auth_credentials->username()) + ":*");
2163   }
2164 
2165   if (!delta.response_cookie_modifications.empty()) {
2166     details->Set(
2167         activity_log::kResponseCookieModificationsKey,
2168         SummarizeCookieModifications(delta.response_cookie_modifications));
2169   }
2170 
2171   return details;
2172 }
2173 
2174 }  // namespace
2175 
DecrementBlockCount(content::BrowserContext * browser_context,const std::string & extension_id,const std::string & event_name,uint64_t request_id,EventResponse * response,int extra_info_spec)2176 void ExtensionWebRequestEventRouter::DecrementBlockCount(
2177     content::BrowserContext* browser_context,
2178     const std::string& extension_id,
2179     const std::string& event_name,
2180     uint64_t request_id,
2181     EventResponse* response,
2182     int extra_info_spec) {
2183   std::unique_ptr<EventResponse> response_scoped(response);
2184 
2185   // It's possible that this request was deleted, or cancelled by a previous
2186   // event handler or handled by Declarative Net Request API. If so, ignore this
2187   // response.
2188   auto it = blocked_requests_.find(request_id);
2189   if (it == blocked_requests_.end())
2190     return;
2191 
2192   BlockedRequest& blocked_request = it->second;
2193 
2194   // Ensure that the response is for the event we are blocked on.
2195   DCHECK_EQ(blocked_request.event, GetEventTypeFromEventName(event_name));
2196 
2197   int num_handlers_blocking = --blocked_request.num_handlers_blocking;
2198   CHECK_GE(num_handlers_blocking, 0);
2199 
2200   if (response) {
2201     helpers::EventResponseDelta delta = CalculateDelta(
2202         browser_context, &blocked_request, response, extra_info_spec);
2203 
2204     activity_monitor::OnWebRequestApiUsed(
2205         static_cast<content::BrowserContext*>(browser_context), extension_id,
2206         blocked_request.request->url, blocked_request.is_incognito, event_name,
2207         SummarizeResponseDelta(event_name, delta));
2208 
2209     blocked_request.response_deltas.push_back(std::move(delta));
2210   }
2211 
2212   if (num_handlers_blocking == 0)
2213     ExecuteDeltas(browser_context, blocked_request.request, true);
2214 }
2215 
SendMessages(content::BrowserContext * browser_context,const BlockedRequest & blocked_request)2216 void ExtensionWebRequestEventRouter::SendMessages(
2217     content::BrowserContext* browser_context,
2218     const BlockedRequest& blocked_request) {
2219   const helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
2220   for (const auto& delta : deltas) {
2221     const std::set<std::string>& messages = delta.messages_to_extension;
2222     for (const std::string& message : messages) {
2223       std::unique_ptr<WebRequestEventDetails> event_details(CreateEventDetails(
2224           *blocked_request.request, /* extra_info_spec */ 0));
2225       event_details->SetString(keys::kMessageKey, message);
2226       event_details->SetString(keys::kStageKey,
2227                                GetRequestStageAsString(blocked_request.event));
2228       SendOnMessageEventOnUI(browser_context, delta.extension_id,
2229                              blocked_request.request->is_web_view,
2230                              blocked_request.request->web_view_instance_id,
2231                              std::move(event_details));
2232     }
2233   }
2234 }
2235 
ExecuteDeltas(content::BrowserContext * browser_context,const WebRequestInfo * request,bool call_callback)2236 int ExtensionWebRequestEventRouter::ExecuteDeltas(
2237     content::BrowserContext* browser_context,
2238     const WebRequestInfo* request,
2239     bool call_callback) {
2240   BlockedRequest& blocked_request = blocked_requests_[request->id];
2241   CHECK_EQ(0, blocked_request.num_handlers_blocking);
2242   helpers::EventResponseDeltas& deltas = blocked_request.response_deltas;
2243   base::TimeDelta block_time =
2244       base::Time::Now() - blocked_request.blocking_time;
2245   request_time_tracker_->IncrementTotalBlockTime(request->id, block_time);
2246 
2247   bool request_headers_modified = false;
2248   bool response_headers_modified = false;
2249   bool credentials_set = false;
2250   // The set of request headers which were removed or set to new values.
2251   std::set<std::string> request_headers_removed;
2252   std::set<std::string> request_headers_set;
2253 
2254   deltas.sort(&helpers::InDecreasingExtensionInstallationTimeOrder);
2255 
2256   base::Optional<ExtensionId> canceled_by_extension;
2257   helpers::MergeCancelOfResponses(blocked_request.response_deltas,
2258                                   &canceled_by_extension);
2259 
2260   extension_web_request_api_helpers::IgnoredActions ignored_actions;
2261   std::vector<const DNRRequestAction*> matched_dnr_actions;
2262   if (blocked_request.event == kOnBeforeRequest) {
2263     CHECK(!blocked_request.callback.is_null());
2264     helpers::MergeOnBeforeRequestResponses(
2265         request->url, blocked_request.response_deltas, blocked_request.new_url,
2266         &ignored_actions);
2267   } else if (blocked_request.event == kOnBeforeSendHeaders) {
2268     CHECK(!blocked_request.before_send_headers_callback.is_null());
2269     helpers::MergeOnBeforeSendHeadersResponses(
2270         *request, blocked_request.response_deltas,
2271         blocked_request.request_headers, &ignored_actions,
2272         &request_headers_removed, &request_headers_set,
2273         &request_headers_modified, &matched_dnr_actions);
2274   } else if (blocked_request.event == kOnHeadersReceived) {
2275     CHECK(!blocked_request.callback.is_null());
2276     helpers::MergeOnHeadersReceivedResponses(
2277         *request, blocked_request.response_deltas,
2278         blocked_request.original_response_headers.get(),
2279         blocked_request.override_response_headers, blocked_request.new_url,
2280         &ignored_actions, &response_headers_modified, &matched_dnr_actions);
2281   } else if (blocked_request.event == kOnAuthRequired) {
2282     CHECK(blocked_request.callback.is_null());
2283     CHECK(!blocked_request.auth_callback.is_null());
2284     credentials_set = helpers::MergeOnAuthRequiredResponses(
2285         blocked_request.response_deltas, blocked_request.auth_credentials,
2286         &ignored_actions);
2287   } else {
2288     NOTREACHED();
2289   }
2290 
2291   SendMessages(browser_context, blocked_request);
2292 
2293   if (!ignored_actions.empty()) {
2294     NotifyIgnoredActionsOnUI(browser_context, request->id,
2295                              std::move(ignored_actions));
2296   }
2297 
2298   for (const DNRRequestAction* action : matched_dnr_actions)
2299     OnDNRActionMatched(browser_context, *request, *action);
2300 
2301   const bool redirected =
2302       blocked_request.new_url && !blocked_request.new_url->is_empty();
2303 
2304   if (canceled_by_extension)
2305     request_time_tracker_->SetRequestCanceled(request->id);
2306   else if (redirected)
2307     request_time_tracker_->SetRequestRedirected(request->id);
2308 
2309   // Log UMA metrics. Note: We are not necessarily concerned with the final
2310   // action taken. Instead we are interested in how frequently the different
2311   // actions are used by extensions. Hence multiple actions may be logged for a
2312   // single delta execution.
2313   if (canceled_by_extension)
2314     LogRequestAction(RequestAction::CANCEL);
2315   if (redirected)
2316     LogRequestAction(RequestAction::REDIRECT);
2317   if (request_headers_modified)
2318     LogRequestAction(RequestAction::MODIFY_REQUEST_HEADERS);
2319   if (response_headers_modified)
2320     LogRequestAction(RequestAction::MODIFY_RESPONSE_HEADERS);
2321   if (credentials_set)
2322     LogRequestAction(RequestAction::SET_AUTH_CREDENTIALS);
2323 
2324   // This triggers onErrorOccurred if canceled is true.
2325   int rv = net::OK;
2326   if (canceled_by_extension) {
2327     rv = net::ERR_BLOCKED_BY_CLIENT;
2328     RecordNetworkRequestBlocked(request->ukm_source_id,
2329                                 canceled_by_extension.value());
2330   }
2331 
2332   if (!blocked_request.callback.is_null()) {
2333     net::CompletionOnceCallback callback = std::move(blocked_request.callback);
2334     // Ensure that request is removed before callback because the callback
2335     // might trigger the next event.
2336     blocked_requests_.erase(request->id);
2337     if (call_callback)
2338       std::move(callback).Run(rv);
2339   } else if (!blocked_request.before_send_headers_callback.is_null()) {
2340     auto callback = std::move(blocked_request.before_send_headers_callback);
2341     // Ensure that request is removed before callback because the callback
2342     // might trigger the next event.
2343     blocked_requests_.erase(request->id);
2344     if (call_callback)
2345       std::move(callback).Run(request_headers_removed, request_headers_set, rv);
2346   } else if (!blocked_request.auth_callback.is_null()) {
2347     ExtensionWebRequestEventRouter::AuthRequiredResponse response;
2348     if (canceled_by_extension)
2349       response = AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
2350     else if (credentials_set)
2351       response = AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_SET_AUTH;
2352     else
2353       response = AuthRequiredResponse::AUTH_REQUIRED_RESPONSE_NO_ACTION;
2354 
2355     AuthCallback callback = std::move(blocked_request.auth_callback);
2356     blocked_requests_.erase(request->id);
2357     if (call_callback)
2358       std::move(callback).Run(response);
2359   } else {
2360     blocked_requests_.erase(request->id);
2361   }
2362   return rv;
2363 }
2364 
ProcessDeclarativeRules(content::BrowserContext * browser_context,const std::string & event_name,const WebRequestInfo * request,RequestStage request_stage,const net::HttpResponseHeaders * original_response_headers)2365 bool ExtensionWebRequestEventRouter::ProcessDeclarativeRules(
2366     content::BrowserContext* browser_context,
2367     const std::string& event_name,
2368     const WebRequestInfo* request,
2369     RequestStage request_stage,
2370     const net::HttpResponseHeaders* original_response_headers) {
2371   int rules_registry_id = request->is_web_view
2372                               ? request->web_view_rules_registry_id
2373                               : RulesRegistryService::kDefaultRulesRegistryID;
2374 
2375   RulesRegistryKey rules_key(browser_context, rules_registry_id);
2376   // If this check fails, check that the active stages are up to date in
2377   // extensions/browser/api/declarative_webrequest/request_stage.h .
2378   DCHECK(request_stage & kActiveStages);
2379 
2380   // Rules of the current |browser_context| may apply but we need to check also
2381   // whether there are applicable rules from extensions whose background page
2382   // spans from regular to incognito mode.
2383 
2384   // First parameter identifies the registry, the second indicates whether the
2385   // registry belongs to the cross browser_context.
2386   using RelevantRegistry = std::pair<WebRequestRulesRegistry*, bool>;
2387   std::vector<RelevantRegistry> relevant_registries;
2388 
2389   auto rules_key_it = rules_registries_.find(rules_key);
2390   if (rules_key_it != rules_registries_.end()) {
2391     relevant_registries.push_back(
2392         std::make_pair(rules_key_it->second.get(), false));
2393   }
2394 
2395   content::BrowserContext* cross_browser_context =
2396       GetCrossBrowserContext(browser_context);
2397   RulesRegistryKey cross_browser_context_rules_key(cross_browser_context,
2398                                                    rules_registry_id);
2399   if (cross_browser_context) {
2400     auto it = rules_registries_.find(cross_browser_context_rules_key);
2401     if (it != rules_registries_.end())
2402       relevant_registries.push_back(std::make_pair(it->second.get(), true));
2403   }
2404 
2405   for (auto it : relevant_registries) {
2406     WebRequestRulesRegistry* rules_registry = it.first;
2407     if (rules_registry->ready().is_signaled())
2408       continue;
2409 
2410     // The rules registry is still loading. Block this request until it
2411     // finishes.
2412     // This Unretained is safe because the ExtensionWebRequestEventRouter
2413     // singleton is leaked.
2414     rules_registry->ready().Post(
2415         FROM_HERE,
2416         base::BindOnce(&ExtensionWebRequestEventRouter::OnRulesRegistryReady,
2417                        base::Unretained(this), browser_context, event_name,
2418                        request->id, request_stage));
2419     BlockedRequest& blocked_request = blocked_requests_[request->id];
2420     blocked_request.num_handlers_blocking++;
2421     blocked_request.request = request;
2422     blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
2423     blocked_request.blocking_time = base::Time::Now();
2424     blocked_request.original_response_headers = original_response_headers;
2425     return true;
2426   }
2427 
2428   bool deltas_created = false;
2429   for (const auto& it : relevant_registries) {
2430     WebRequestRulesRegistry* rules_registry = it.first;
2431     helpers::EventResponseDeltas result = rules_registry->CreateDeltas(
2432         PermissionHelper::Get(browser_context),
2433         WebRequestData(request, request_stage, original_response_headers),
2434         it.second);
2435 
2436     if (!result.empty()) {
2437       helpers::EventResponseDeltas& deltas =
2438           blocked_requests_[request->id].response_deltas;
2439       deltas.insert(deltas.end(), std::make_move_iterator(result.begin()),
2440                     std::make_move_iterator(result.end()));
2441       deltas_created = true;
2442     }
2443   }
2444 
2445   return deltas_created;
2446 }
2447 
OnRulesRegistryReady(content::BrowserContext * browser_context,const std::string & event_name,uint64_t request_id,RequestStage request_stage)2448 void ExtensionWebRequestEventRouter::OnRulesRegistryReady(
2449     content::BrowserContext* browser_context,
2450     const std::string& event_name,
2451     uint64_t request_id,
2452     RequestStage request_stage) {
2453   // It's possible that this request was deleted, or cancelled by a previous
2454   // event handler. If so, ignore this response.
2455   auto it = blocked_requests_.find(request_id);
2456   if (it == blocked_requests_.end())
2457     return;
2458 
2459   BlockedRequest& blocked_request = it->second;
2460   ProcessDeclarativeRules(browser_context, event_name, blocked_request.request,
2461                           request_stage,
2462                           blocked_request.original_response_headers.get());
2463   DecrementBlockCount(browser_context, std::string(), event_name, request_id,
2464                       nullptr, 0 /* extra_info_spec */);
2465 }
2466 
GetAndSetSignaled(uint64_t request_id,EventTypes event_type)2467 bool ExtensionWebRequestEventRouter::GetAndSetSignaled(uint64_t request_id,
2468                                                        EventTypes event_type) {
2469   auto iter = signaled_requests_.find(request_id);
2470   if (iter == signaled_requests_.end()) {
2471     signaled_requests_[request_id] = event_type;
2472     return false;
2473   }
2474   bool was_signaled_before = (iter->second & event_type) != 0;
2475   iter->second |= event_type;
2476   return was_signaled_before;
2477 }
2478 
ClearSignaled(uint64_t request_id,EventTypes event_type)2479 void ExtensionWebRequestEventRouter::ClearSignaled(uint64_t request_id,
2480                                                    EventTypes event_type) {
2481   auto iter = signaled_requests_.find(request_id);
2482   if (iter == signaled_requests_.end())
2483     return;
2484   iter->second &= ~event_type;
2485 }
2486 
2487 // Special QuotaLimitHeuristic for WebRequestHandlerBehaviorChangedFunction.
2488 //
2489 // Each call of webRequest.handlerBehaviorChanged() clears the in-memory cache
2490 // of WebKit at the time of the next page load (top level navigation event).
2491 // This quota heuristic is intended to limit the number of times the cache is
2492 // cleared by an extension.
2493 //
2494 // As we want to account for the number of times the cache is really cleared
2495 // (opposed to the number of times webRequest.handlerBehaviorChanged() is
2496 // called), we cannot decide whether a call of
2497 // webRequest.handlerBehaviorChanged() should trigger a quota violation at the
2498 // time it is called. Instead we only decrement the bucket counter at the time
2499 // when the cache is cleared (when page loads happen).
2500 class ClearCacheQuotaHeuristic : public QuotaLimitHeuristic {
2501  public:
ClearCacheQuotaHeuristic(const Config & config,std::unique_ptr<BucketMapper> map)2502   ClearCacheQuotaHeuristic(const Config& config,
2503                            std::unique_ptr<BucketMapper> map)
2504       : QuotaLimitHeuristic(
2505             config,
2506             std::move(map),
2507             "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
2508         callback_registered_(false) {}
~ClearCacheQuotaHeuristic()2509   ~ClearCacheQuotaHeuristic() override {}
2510   bool Apply(Bucket* bucket, const base::TimeTicks& event_time) override;
2511 
2512  private:
2513   // Callback that is triggered by the ExtensionWebRequestEventRouter on a page
2514   // load.
2515   //
2516   // We don't need to take care of the life time of |bucket|: It is owned by the
2517   // BucketMapper of our base class in |QuotaLimitHeuristic::bucket_mapper_|. As
2518   // long as |this| exists, the respective BucketMapper and its bucket will
2519   // exist as well.
2520   void OnPageLoad(Bucket* bucket);
2521 
2522   // Flag to prevent that we register more than one call back in-between
2523   // clearing the cache.
2524   bool callback_registered_;
2525 
2526   base::WeakPtrFactory<ClearCacheQuotaHeuristic> weak_ptr_factory_{this};
2527 
2528   DISALLOW_COPY_AND_ASSIGN(ClearCacheQuotaHeuristic);
2529 };
2530 
Apply(Bucket * bucket,const base::TimeTicks & event_time)2531 bool ClearCacheQuotaHeuristic::Apply(Bucket* bucket,
2532                                      const base::TimeTicks& event_time) {
2533   if (event_time > bucket->expiration())
2534     bucket->Reset(config(), event_time);
2535 
2536   // Call bucket->DeductToken() on a new page load, this is when
2537   // webRequest.handlerBehaviorChanged() clears the cache.
2538   if (!callback_registered_) {
2539     ExtensionWebRequestEventRouter::GetInstance()->AddCallbackForPageLoad(
2540         base::Bind(&ClearCacheQuotaHeuristic::OnPageLoad,
2541                    weak_ptr_factory_.GetWeakPtr(),
2542                    bucket));
2543     callback_registered_ = true;
2544   }
2545 
2546   // We only check whether tokens are left here. Deducting a token happens in
2547   // OnPageLoad().
2548   return bucket->has_tokens();
2549 }
2550 
OnPageLoad(Bucket * bucket)2551 void ClearCacheQuotaHeuristic::OnPageLoad(Bucket* bucket) {
2552   callback_registered_ = false;
2553   bucket->DeductToken();
2554 }
2555 
2556 ExtensionFunction::ResponseAction
Run()2557 WebRequestInternalAddEventListenerFunction::Run() {
2558   // Argument 0 is the callback, which we don't use here.
2559   ExtensionWebRequestEventRouter::RequestFilter filter;
2560   base::DictionaryValue* value = NULL;
2561   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
2562   // Failure + an empty error string means a fatal error.
2563   std::string error;
2564   EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value, &error) ||
2565                               !error.empty());
2566   if (!error.empty())
2567     return RespondNow(Error(std::move(error)));
2568 
2569   int extra_info_spec = 0;
2570   if (HasOptionalArgument(2)) {
2571     base::ListValue* value = NULL;
2572     EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
2573     EXTENSION_FUNCTION_VALIDATE(ExtraInfoSpec::InitFromValue(
2574         browser_context(), *value, &extra_info_spec));
2575   }
2576 
2577   std::string event_name;
2578   EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
2579 
2580   std::string sub_event_name;
2581   EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
2582 
2583   int web_view_instance_id = 0;
2584   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(5, &web_view_instance_id));
2585 
2586   int render_process_id = source_process_id();
2587 
2588   const Extension* extension = ExtensionRegistry::Get(browser_context())
2589                                    ->enabled_extensions()
2590                                    .GetByID(extension_id_safe());
2591   std::string extension_name =
2592       extension ? extension->name() : extension_id_safe();
2593 
2594   if (!web_view_instance_id) {
2595     // We check automatically whether the extension has the 'webRequest'
2596     // permission. For blocking calls we require the additional permission
2597     // 'webRequestBlocking'.
2598     if ((extra_info_spec &
2599          (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) &&
2600         !extension->permissions_data()->HasAPIPermission(
2601             APIPermission::kWebRequestBlocking)) {
2602       return RespondNow(Error(keys::kBlockingPermissionRequired));
2603     }
2604 
2605     // We allow to subscribe to patterns that are broader than the host
2606     // permissions. E.g., we could subscribe to http://www.example.com/*
2607     // while having host permissions for http://www.example.com/foo/* and
2608     // http://www.example.com/bar/*.
2609     // For this reason we do only a coarse check here to warn the extension
2610     // developer if they do something obviously wrong.
2611     // When restrictions are enabled in Public Session, allow all URLs for
2612     // webRequests initiated by a regular extension.
2613     if (!(ArePublicSessionRestrictionsEnabled() && extension->is_extension()) &&
2614         extension->permissions_data()
2615             ->GetEffectiveHostPermissions(
2616                 PermissionsData::EffectiveHostPermissionsMode::
2617                     kIncludeTabSpecific)
2618             .is_empty() &&
2619         extension->permissions_data()
2620             ->withheld_permissions()
2621             .explicit_hosts()
2622             .is_empty()) {
2623       return RespondNow(Error(keys::kHostPermissionsRequired));
2624     }
2625   }
2626 
2627   bool success =
2628       ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
2629           browser_context(), extension_id_safe(), extension_name,
2630           GetEventHistogramValue(event_name), event_name, sub_event_name,
2631           filter, extra_info_spec, render_process_id, web_view_instance_id,
2632           worker_thread_id(), service_worker_version_id());
2633   EXTENSION_FUNCTION_VALIDATE(success);
2634 
2635   helpers::ClearCacheOnNavigation();
2636 
2637   return RespondNow(NoArguments());
2638 }
2639 
OnError(const std::string & event_name,const std::string & sub_event_name,uint64_t request_id,int render_process_id,int web_view_instance_id,std::unique_ptr<ExtensionWebRequestEventRouter::EventResponse> response)2640 void WebRequestInternalEventHandledFunction::OnError(
2641     const std::string& event_name,
2642     const std::string& sub_event_name,
2643     uint64_t request_id,
2644     int render_process_id,
2645     int web_view_instance_id,
2646     std::unique_ptr<ExtensionWebRequestEventRouter::EventResponse> response) {
2647   ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2648       browser_context(), extension_id_safe(), event_name, sub_event_name,
2649       request_id, render_process_id, web_view_instance_id, worker_thread_id(),
2650       service_worker_version_id(), response.release());
2651 }
2652 
2653 ExtensionFunction::ResponseAction
Run()2654 WebRequestInternalEventHandledFunction::Run() {
2655   std::string event_name;
2656   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
2657 
2658   std::string sub_event_name;
2659   EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
2660 
2661   std::string request_id_str;
2662   EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
2663   uint64_t request_id;
2664   EXTENSION_FUNCTION_VALIDATE(base::StringToUint64(request_id_str,
2665                                                    &request_id));
2666   int web_view_instance_id = 0;
2667   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(3, &web_view_instance_id));
2668 
2669   int render_process_id = source_process_id();
2670 
2671   std::unique_ptr<ExtensionWebRequestEventRouter::EventResponse> response;
2672   if (HasOptionalArgument(4)) {
2673     base::DictionaryValue* value = NULL;
2674     EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(4, &value));
2675 
2676     if (!value->empty()) {
2677       base::Time install_time = ExtensionPrefs::Get(browser_context())
2678                                     ->GetInstallTime(extension_id_safe());
2679       response.reset(new ExtensionWebRequestEventRouter::EventResponse(
2680           extension_id_safe(), install_time));
2681     }
2682 
2683     // In Public Session we restrict everything but "cancel" (except for
2684     // whitelisted extensions which have no such restrictions).
2685     if (ArePublicSessionRestrictionsEnabled() &&
2686         !extensions::IsWhitelistedForPublicSession(extension_id_safe()) &&
2687         (value->HasKey("redirectUrl") ||
2688          value->HasKey(keys::kAuthCredentialsKey) ||
2689          value->HasKey("requestHeaders") ||
2690          value->HasKey("responseHeaders"))) {
2691       OnError(event_name, sub_event_name, request_id, render_process_id,
2692               web_view_instance_id, std::move(response));
2693       return RespondNow(Error(keys::kInvalidPublicSessionBlockingResponse));
2694     }
2695 
2696     if (value->HasKey("cancel")) {
2697       // Don't allow cancel mixed with other keys.
2698       if (value->size() != 1) {
2699         OnError(event_name, sub_event_name, request_id, render_process_id,
2700                 web_view_instance_id, std::move(response));
2701         return RespondNow(Error(keys::kInvalidBlockingResponse));
2702       }
2703 
2704       bool cancel = false;
2705       EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
2706       response->cancel = cancel;
2707     }
2708 
2709     if (value->HasKey("redirectUrl")) {
2710       std::string new_url_str;
2711       EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
2712                                                    &new_url_str));
2713       response->new_url = GURL(new_url_str);
2714       if (!response->new_url.is_valid()) {
2715         OnError(event_name, sub_event_name, request_id, render_process_id,
2716                 web_view_instance_id, std::move(response));
2717         return RespondNow(Error(keys::kInvalidRedirectUrl, new_url_str));
2718       }
2719     }
2720 
2721     const bool has_request_headers = value->HasKey("requestHeaders");
2722     const bool has_response_headers = value->HasKey("responseHeaders");
2723     if (has_request_headers || has_response_headers) {
2724       if (has_request_headers && has_response_headers) {
2725         // Allow only one of the keys, not both.
2726         OnError(event_name, sub_event_name, request_id, render_process_id,
2727                 web_view_instance_id, std::move(response));
2728         return RespondNow(Error(keys::kInvalidHeaderKeyCombination));
2729       }
2730 
2731       base::ListValue* headers_value = NULL;
2732       std::unique_ptr<net::HttpRequestHeaders> request_headers;
2733       std::unique_ptr<helpers::ResponseHeaders> response_headers;
2734       if (has_request_headers) {
2735         request_headers.reset(new net::HttpRequestHeaders());
2736         EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kRequestHeadersKey,
2737                                                    &headers_value));
2738       } else {
2739         response_headers.reset(new helpers::ResponseHeaders());
2740         EXTENSION_FUNCTION_VALIDATE(value->GetList(keys::kResponseHeadersKey,
2741                                                    &headers_value));
2742       }
2743 
2744       for (size_t i = 0; i < headers_value->GetSize(); ++i) {
2745         base::DictionaryValue* header_value = NULL;
2746         std::string name;
2747         std::string value;
2748         EXTENSION_FUNCTION_VALIDATE(
2749             headers_value->GetDictionary(i, &header_value));
2750         if (!FromHeaderDictionary(header_value, &name, &value)) {
2751           std::string serialized_header;
2752           base::JSONWriter::Write(*header_value, &serialized_header);
2753           OnError(event_name, sub_event_name, request_id, render_process_id,
2754                   web_view_instance_id, std::move(response));
2755           return RespondNow(Error(keys::kInvalidHeader, serialized_header));
2756         }
2757         if (!net::HttpUtil::IsValidHeaderName(name)) {
2758           OnError(event_name, sub_event_name, request_id, render_process_id,
2759                   web_view_instance_id, std::move(response));
2760           return RespondNow(Error(keys::kInvalidHeaderName));
2761         }
2762         if (!net::HttpUtil::IsValidHeaderValue(value)) {
2763           OnError(event_name, sub_event_name, request_id, render_process_id,
2764                   web_view_instance_id, std::move(response));
2765           return RespondNow(Error(keys::kInvalidHeaderValue, name));
2766         }
2767         if (has_request_headers)
2768           request_headers->SetHeader(name, value);
2769         else
2770           response_headers->push_back(helpers::ResponseHeader(name, value));
2771       }
2772       if (has_request_headers)
2773         response->request_headers = std::move(request_headers);
2774       else
2775         response->response_headers = std::move(response_headers);
2776     }
2777 
2778     if (value->HasKey(keys::kAuthCredentialsKey)) {
2779       base::DictionaryValue* credentials_value = NULL;
2780       EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
2781           keys::kAuthCredentialsKey,
2782           &credentials_value));
2783       base::string16 username;
2784       base::string16 password;
2785       EXTENSION_FUNCTION_VALIDATE(
2786           credentials_value->GetString(keys::kUsernameKey, &username));
2787       EXTENSION_FUNCTION_VALIDATE(
2788           credentials_value->GetString(keys::kPasswordKey, &password));
2789       response->auth_credentials = net::AuthCredentials(username, password);
2790     }
2791   }
2792 
2793   ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
2794       browser_context(), extension_id_safe(), event_name, sub_event_name,
2795       request_id, render_process_id, web_view_instance_id, worker_thread_id(),
2796       service_worker_version_id(), response.release());
2797 
2798   return RespondNow(NoArguments());
2799 }
2800 
GetQuotaLimitHeuristics(QuotaLimitHeuristics * heuristics) const2801 void WebRequestHandlerBehaviorChangedFunction::GetQuotaLimitHeuristics(
2802     QuotaLimitHeuristics* heuristics) const {
2803   QuotaLimitHeuristic::Config config = {
2804       // See web_request.json for current value.
2805       web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
2806       base::TimeDelta::FromMinutes(10)};
2807   heuristics->push_back(std::make_unique<ClearCacheQuotaHeuristic>(
2808       config, std::make_unique<QuotaLimitHeuristic::SingletonBucketMapper>()));
2809 }
2810 
OnQuotaExceeded(std::string violation_error)2811 void WebRequestHandlerBehaviorChangedFunction::OnQuotaExceeded(
2812     std::string violation_error) {
2813   // Post warning message.
2814   WarningSet warnings;
2815   warnings.insert(
2816       Warning::CreateRepeatedCacheFlushesWarning(extension_id_safe()));
2817   WarningService::NotifyWarningsOnUI(browser_context(), warnings);
2818 
2819   // Continue gracefully.
2820   RunWithValidation()->Execute();
2821 }
2822 
2823 ExtensionFunction::ResponseAction
Run()2824 WebRequestHandlerBehaviorChangedFunction::Run() {
2825   helpers::ClearCacheOnNavigation();
2826   return RespondNow(NoArguments());
2827 }
2828 
ID(content::BrowserContext * browser_context,const std::string & extension_id,const std::string & sub_event_name,int render_process_id,int web_view_instance_id,int worker_thread_id,int64_t service_worker_version_id)2829 ExtensionWebRequestEventRouter::EventListener::ID::ID(
2830     content::BrowserContext* browser_context,
2831     const std::string& extension_id,
2832     const std::string& sub_event_name,
2833     int render_process_id,
2834     int web_view_instance_id,
2835     int worker_thread_id,
2836     int64_t service_worker_version_id)
2837     : browser_context(browser_context),
2838       extension_id(extension_id),
2839       sub_event_name(sub_event_name),
2840       render_process_id(render_process_id),
2841       web_view_instance_id(web_view_instance_id),
2842       worker_thread_id(worker_thread_id),
2843       service_worker_version_id(service_worker_version_id) {}
2844 
2845 ExtensionWebRequestEventRouter::EventListener::ID::ID(const ID& source) =
2846     default;
2847 
LooselyMatches(const ID & that) const2848 bool ExtensionWebRequestEventRouter::EventListener::ID::LooselyMatches(
2849     const ID& that) const {
2850   if (web_view_instance_id == 0 && that.web_view_instance_id == 0) {
2851     // Since EventListeners are segmented by browser_context, check that
2852     // last, as it is exceedingly unlikely to be different.
2853     return extension_id == that.extension_id &&
2854            sub_event_name == that.sub_event_name &&
2855            worker_thread_id == that.worker_thread_id &&
2856            service_worker_version_id == that.service_worker_version_id &&
2857            browser_context == that.browser_context;
2858   }
2859 
2860   return *this == that;
2861 }
2862 
operator ==(const ID & that) const2863 bool ExtensionWebRequestEventRouter::EventListener::ID::operator==(
2864     const ID& that) const {
2865   // Since EventListeners are segmented by browser_context, check that
2866   // last, as it is exceedingly unlikely to be different.
2867   return extension_id == that.extension_id &&
2868          sub_event_name == that.sub_event_name &&
2869          web_view_instance_id == that.web_view_instance_id &&
2870          render_process_id == that.render_process_id &&
2871          worker_thread_id == that.worker_thread_id &&
2872          service_worker_version_id == that.service_worker_version_id &&
2873          browser_context == that.browser_context;
2874 }
2875 
2876 }  // namespace extensions
2877