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