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