172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// found in the LICENSE file.
472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/extensions/extension_webrequest_api.h"
672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <algorithm>
872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/json/json_writer.h"
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/metrics/histogram.h"
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/string_number_conversions.h"
1272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/values.h"
13dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/extensions/extension_event_router_forwarder.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/extensions/extension_tab_id_map.h"
1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/extensions/extension_webrequest_api_constants.h"
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/profiles/profile.h"
1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/common/extensions/extension.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/extensions/extension_error_utils.h"
1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/common/extensions/extension_extent.h"
2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/common/extensions/url_pattern.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/url_constants.h"
22dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/renderer_host/resource_dispatcher_host.h"
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/renderer_host/resource_dispatcher_host_request_info.h"
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/base/net_errors.h"
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/url_request/url_request.h"
2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "googleurl/src/gurl.h"
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsennamespace keys = extension_webrequest_api_constants;
3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsennamespace {
3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// List of all the webRequest events.
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic const char* const kWebRequestEvents[] = {
3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  keys::kOnBeforeRedirect,
3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  keys::kOnBeforeRequest,
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  keys::kOnBeforeSendHeaders,
3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  keys::kOnCompleted,
3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  keys::kOnErrorOccurred,
4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  keys::kOnHeadersReceived,
4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  keys::kOnRequestSent
4272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen};
4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic const char* kResourceTypeStrings[] = {
4572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "main_frame",
4672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "sub_frame",
4772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "stylesheet",
4872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "script",
4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "image",
5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "object",
5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  "other",
5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen};
5372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic ResourceType::Type kResourceTypeValues[] = {
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceType::MAIN_FRAME,
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceType::SUB_FRAME,
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceType::STYLESHEET,
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceType::SCRIPT,
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceType::IMAGE,
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceType::OBJECT,
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceType::LAST_TYPE,  // represents "other"
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen};
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenCOMPILE_ASSERT(
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    arraysize(kResourceTypeStrings) == arraysize(kResourceTypeValues),
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    keep_resource_types_in_sync);
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define ARRAYEND(array) (array + arraysize(array))
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
7072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic bool IsWebRequestEvent(const std::string& event_name) {
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return std::find(kWebRequestEvents, ARRAYEND(kWebRequestEvents),
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                   event_name) != ARRAYEND(kWebRequestEvents);
7372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
7472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic const char* ResourceTypeToString(ResourceType::Type type) {
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceType::Type* iter =
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::find(kResourceTypeValues, ARRAYEND(kResourceTypeValues), type);
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (iter == ARRAYEND(kResourceTypeValues))
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return "other";
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return kResourceTypeStrings[iter - kResourceTypeValues];
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic bool ParseResourceType(const std::string& type_str,
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              ResourceType::Type* type) {
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const char** iter =
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::find(kResourceTypeStrings, ARRAYEND(kResourceTypeStrings), type_str);
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (iter == ARRAYEND(kResourceTypeStrings))
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  *type = kResourceTypeValues[iter - kResourceTypeStrings];
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic void ExtractRequestInfo(net::URLRequest* request,
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                               int* tab_id,
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                               int* window_id,
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                               ResourceType::Type* resource_type) {
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!request->GetUserData(NULL))
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceDispatcherHostRequestInfo* info =
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ResourceDispatcherHost::InfoForRequest(request);
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ExtensionTabIdMap::GetInstance()->GetTabAndWindowId(
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      info->child_id(), info->route_id(), tab_id, window_id);
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Restrict the resource type to the values we care about.
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceType::Type* iter =
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      std::find(kResourceTypeValues, ARRAYEND(kResourceTypeValues),
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                info->resource_type());
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  *resource_type = (iter != ARRAYEND(kResourceTypeValues)) ?
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *iter : ResourceType::LAST_TYPE;
11272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
11372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstatic void AddEventListenerOnIOThread(
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProfileId profile_id,
11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& extension_id,
11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& event_name,
11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& sub_event_name,
11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const ExtensionWebRequestEventRouter::RequestFilter& filter,
12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int extra_info_spec) {
12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ExtensionWebRequestEventRouter::GetInstance()->AddEventListener(
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      profile_id, extension_id, event_name, sub_event_name, filter,
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      extra_info_spec);
12472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic void EventHandledOnIOThread(
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProfileId profile_id,
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& extension_id,
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& event_name,
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& sub_event_name,
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    uint64 request_id,
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool cancel,
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const GURL& new_url) {
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      profile_id, extension_id, event_name, sub_event_name, request_id,
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      cancel, new_url);
13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}  // namespace
14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Internal representation of the webRequest.RequestFilter type, used to
14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// filter what network events an extension cares about.
14372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstruct ExtensionWebRequestEventRouter::RequestFilter {
14472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ExtensionExtent urls;
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<ResourceType::Type> types;
14672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int tab_id;
14772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int window_id;
14872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  RequestFilter() : tab_id(-1), window_id(-1) {}
15072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  bool InitFromValue(const DictionaryValue& value);
15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen};
15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Internal representation of the extraInfoSpec parameter on webRequest events,
15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// used to specify extra information to be included with network events.
15572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstruct ExtensionWebRequestEventRouter::ExtraInfoSpec {
15672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  enum Flags {
15772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    REQUEST_LINE = 1<<0,
15872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    REQUEST_HEADERS = 1<<1,
15972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    STATUS_LINE = 1<<2,
16072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    RESPONSE_HEADERS = 1<<3,
16172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    REDIRECT_REQUEST_LINE = 1<<4,
16272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    REDIRECT_REQUEST_HEADERS = 1<<5,
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BLOCKING = 1<<6,
16472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  };
16572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
16672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  static bool InitFromValue(const ListValue& value, int* extra_info_spec);
16772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen};
16872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Represents a single unique listener to an event, along with whatever filter
17072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// parameters and extra_info_spec were specified at the time the listener was
17172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// added.
17272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstruct ExtensionWebRequestEventRouter::EventListener {
17372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string extension_id;
17472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string sub_event_name;
17572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  RequestFilter filter;
17672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int extra_info_spec;
177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  mutable std::set<uint64> blocked_requests;
17872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
17972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Comparator to work with std::set.
18072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  bool operator<(const EventListener& that) const {
18172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (extension_id < that.extension_id)
18272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return true;
18372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (extension_id == that.extension_id &&
18472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        sub_event_name < that.sub_event_name)
18572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return true;
18672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
18772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
18872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen};
18972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Contains info about requests that are blocked waiting for a response from
191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// an extension.
192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstruct ExtensionWebRequestEventRouter::BlockedRequest {
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The number of event handlers that we are awaiting a response from.
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int num_handlers_blocking;
195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The callback to call when we get a response from all event handlers.
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  net::CompletionCallback* callback;
198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If non-empty, this contains the new URL that the request will redirect to.
200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GURL* new_url;
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Time the request was issued. Used for logging purposes.
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::Time request_time;
204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
205ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  BlockedRequest() : num_handlers_blocking(0), callback(NULL), new_url(NULL) {}
206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen};
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
20872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
20972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const DictionaryValue& value) {
21072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (DictionaryValue::key_iterator key = value.begin_keys();
21172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       key != value.end_keys(); ++key) {
21272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (*key == "urls") {
21372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ListValue* urls_value = NULL;
21472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!value.GetList("urls", &urls_value))
21572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return false;
21672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      for (size_t i = 0; i < urls_value->GetSize(); ++i) {
21772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        std::string url;
21872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        URLPattern pattern(URLPattern::SCHEME_ALL);
21972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        if (!urls_value->GetString(i, &url) ||
220dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            pattern.Parse(url, URLPattern::PARSE_STRICT) !=
221dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                URLPattern::PARSE_SUCCESS)
22272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          return false;
22372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        urls.AddPattern(pattern);
22472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
22572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (*key == "types") {
22672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      ListValue* types_value = NULL;
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!value.GetList("types", &types_value))
22872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return false;
22972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      for (size_t i = 0; i < types_value->GetSize(); ++i) {
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        std::string type_str;
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        ResourceType::Type type;
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (!types_value->GetString(i, &type_str) ||
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            !ParseResourceType(type_str, &type))
23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          return false;
23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        types.push_back(type);
23672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
23772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (*key == "tabId") {
23872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!value.GetInteger("tabId", &tab_id))
23972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return false;
24072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else if (*key == "windowId") {
24172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!value.GetInteger("windowId", &window_id))
24272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return false;
24372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else {
24472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;
24572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
24672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
24772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return true;
24872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
24972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
25072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const ListValue& value, int* extra_info_spec) {
25372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  *extra_info_spec = 0;
25472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (size_t i = 0; i < value.GetSize(); ++i) {
25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    std::string str;
25672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!value.GetString(i, &str))
25772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;
25872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // TODO(mpcomplete): not all of these are valid for every event.
26072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (str == "requestLine")
26172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      *extra_info_spec |= REQUEST_LINE;
26272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    else if (str == "requestHeaders")
26372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      *extra_info_spec |= REQUEST_HEADERS;
26472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    else if (str == "statusLine")
26572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      *extra_info_spec |= STATUS_LINE;
26672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    else if (str == "responseHeaders")
26772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      *extra_info_spec |= RESPONSE_HEADERS;
26872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    else if (str == "redirectRequestLine")
26972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      *extra_info_spec |= REDIRECT_REQUEST_LINE;
27072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    else if (str == "redirectRequestHeaders")
27172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      *extra_info_spec |= REDIRECT_REQUEST_HEADERS;
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    else if (str == "blocking")
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *extra_info_spec |= BLOCKING;
27472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    else
27572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;
27672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
27772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return true;
27872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
27972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
28072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
28172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionWebRequestEventRouter* ExtensionWebRequestEventRouter::GetInstance() {
28272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return Singleton<ExtensionWebRequestEventRouter>::get();
28372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
28472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
28572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter() {
28672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
28772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
28872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionWebRequestEventRouter::~ExtensionWebRequestEventRouter() {
28972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
29072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint ExtensionWebRequestEventRouter::OnBeforeRequest(
292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProfileId profile_id,
293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ExtensionEventRouterForwarder* event_router,
294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    net::URLRequest* request,
295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    net::CompletionCallback* callback,
296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    GURL* new_url) {
297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(jochen): Figure out what to do with events from the system context.
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (profile_id == Profile::kInvalidProfileId)
299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return net::OK;
300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int tab_id = -1;
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int window_id = -1;
303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceType::Type resource_type = ResourceType::LAST_TYPE;
304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ExtractRequestInfo(request, &tab_id, &window_id, &resource_type);
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<const EventListener*> listeners =
307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetMatchingListeners(profile_id, keys::kOnBeforeRequest, request->url(),
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           tab_id, window_id, resource_type);
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (listeners.empty())
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return net::OK;
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If this is an HTTP request, keep track of it. HTTP-specific events only
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // have the request ID, so we'll need to look up the URLRequest from that.
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (request->url().SchemeIs(chrome::kHttpScheme) ||
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      request->url().SchemeIs(chrome::kHttpsScheme)) {
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    http_requests_[request->identifier()] = request;
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ListValue args;
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DictionaryValue* dict = new DictionaryValue();
321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetString(keys::kRequestIdKey,
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                  base::Uint64ToString(request->identifier()));
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetString(keys::kUrlKey, request->url().spec());
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetString(keys::kMethodKey, request->method());
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetInteger(keys::kTabIdKey, tab_id);
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetString(keys::kTypeKey, ResourceTypeToString(resource_type));
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetDouble(keys::kTimeStampKey,
328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                  request->request_time().ToDoubleT() * 1000);
329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  args.Append(dict);
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (DispatchEvent(profile_id, event_router, request, callback, listeners,
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                    args)) {
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    blocked_requests_[request->identifier()].new_url = new_url;
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return net::ERR_IO_PENDING;
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return net::OK;
33772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
33872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
340dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    ProfileId profile_id,
341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ExtensionEventRouterForwarder* event_router,
342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    uint64 request_id,
343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    net::CompletionCallback* callback,
344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    net::HttpRequestHeaders* headers) {
345dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // TODO(jochen): Figure out what to do with events from the system context.
346dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (profile_id == Profile::kInvalidProfileId)
347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return net::OK;
348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  HttpRequestMap::iterator iter = http_requests_.find(request_id);
350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (iter == http_requests_.end())
351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return net::OK;
352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  net::URLRequest* request = iter->second;
354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  http_requests_.erase(iter);
355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
35672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::vector<const EventListener*> listeners =
357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetMatchingListeners(profile_id, keys::kOnBeforeSendHeaders, request);
35872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (listeners.empty())
359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return net::OK;
36072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
36172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ListValue args;
36272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DictionaryValue* dict = new DictionaryValue();
363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetString(keys::kRequestIdKey,
364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                  base::Uint64ToString(request->identifier()));
365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetString(keys::kUrlKey, request->url().spec());
366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  dict->SetDouble(keys::kTimeStampKey,
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                  request->request_time().ToDoubleT() * 1000);
368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(mpcomplete): request headers.
36972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  args.Append(dict);
37072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (DispatchEvent(profile_id, event_router, request, callback, listeners,
372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                    args))
373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return net::ERR_IO_PENDING;
374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return net::OK;
375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
378ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProfileId profile_id, net::URLRequest* request) {
379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  http_requests_.erase(request->identifier());
380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  blocked_requests_.erase(request->identifier());
381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool ExtensionWebRequestEventRouter::DispatchEvent(
384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProfileId profile_id,
385ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ExtensionEventRouterForwarder* event_router,
386ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    net::URLRequest* request,
387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    net::CompletionCallback* callback,
388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::vector<const EventListener*>& listeners,
389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const ListValue& args) {
39072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string json_args;
39172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::JSONWriter::Write(&args, false, &json_args);
39272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // pairs into a single message sent to a list of sub_event_names.
395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int num_handlers_blocking = 0;
396ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (std::vector<const EventListener*>::const_iterator it = listeners.begin();
39772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       it != listeners.end(); ++it) {
39872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    event_router->DispatchEventToExtension(
399dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        (*it)->extension_id, (*it)->sub_event_name, json_args,
400dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        profile_id, true, GURL());
401ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (callback && (*it)->extra_info_spec & ExtraInfoSpec::BLOCKING) {
402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      (*it)->blocked_requests.insert(request->identifier());
403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ++num_handlers_blocking;
404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
407ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (num_handlers_blocking > 0) {
408ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(blocked_requests_.find(request->identifier()) ==
409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          blocked_requests_.end());
410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    blocked_requests_[request->identifier()].num_handlers_blocking =
411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        num_handlers_blocking;
412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    blocked_requests_[request->identifier()].callback = callback;
413ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    blocked_requests_[request->identifier()].request_time =
414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        request->request_time();
415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
416ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
41772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
418ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return false;
420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
421ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionWebRequestEventRouter::OnEventHandled(
423ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProfileId profile_id,
424ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& extension_id,
425ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& event_name,
426ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& sub_event_name,
427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    uint64 request_id,
428ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool cancel,
429ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const GURL& new_url) {
430ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventListener listener;
431ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  listener.extension_id = extension_id;
432ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  listener.sub_event_name = sub_event_name;
433ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
434ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The listener may have been removed (e.g. due to the process going away)
435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // before we got here.
436ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::set<EventListener>::iterator found =
437ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      listeners_[profile_id][event_name].find(listener);
438ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (found != listeners_[profile_id][event_name].end())
439ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    found->blocked_requests.erase(request_id);
440ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
441ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DecrementBlockCount(request_id, cancel, new_url);
44272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
44372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
44472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebRequestEventRouter::AddEventListener(
445ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProfileId profile_id,
44672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& extension_id,
44772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& event_name,
44872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& sub_event_name,
44972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const RequestFilter& filter,
45072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int extra_info_spec) {
45172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!IsWebRequestEvent(event_name))
45272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
45372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
45472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  EventListener listener;
45572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  listener.extension_id = extension_id;
45672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  listener.sub_event_name = sub_event_name;
45772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  listener.filter = filter;
45872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  listener.extra_info_spec = extra_info_spec;
45972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK_EQ(listeners_[profile_id][event_name].count(listener), 0u) <<
46172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      "extension=" << extension_id << " event=" << event_name;
462ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  listeners_[profile_id][event_name].insert(listener);
46372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
46472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
46572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExtensionWebRequestEventRouter::RemoveEventListener(
466ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProfileId profile_id,
46772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& extension_id,
46872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::string& sub_event_name) {
46972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  size_t slash_sep = sub_event_name.find('/');
47072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string event_name = sub_event_name.substr(0, slash_sep);
47172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
47272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!IsWebRequestEvent(event_name))
47372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return;
47472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
47572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  EventListener listener;
47672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  listener.extension_id = extension_id;
47772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  listener.sub_event_name = sub_event_name;
47872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
479ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK_EQ(listeners_[profile_id][event_name].count(listener), 1u) <<
48072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      "extension=" << extension_id << " event=" << event_name;
481ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
482ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Unblock any request that this event listener may have been blocking.
483ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::set<EventListener>::iterator found =
484ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      listeners_[profile_id][event_name].find(listener);
485ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (std::set<uint64>::iterator it = found->blocked_requests.begin();
486ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       it != found->blocked_requests.end(); ++it) {
487ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DecrementBlockCount(*it, false, GURL());
488ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
489ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
490ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  listeners_[profile_id][event_name].erase(listener);
49172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
49272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
49372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstd::vector<const ExtensionWebRequestEventRouter::EventListener*>
49472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExtensionWebRequestEventRouter::GetMatchingListeners(
495ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProfileId profile_id,
496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& event_name,
497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const GURL& url,
498ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int tab_id,
499ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int window_id,
500ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ResourceType::Type resource_type) {
501ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(mpcomplete): handle profile_id == invalid (should collect all
502ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // listeners).
50372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::vector<const EventListener*> matching_listeners;
504ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::set<EventListener>& listeners = listeners_[profile_id][event_name];
50572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (std::set<EventListener>::iterator it = listeners.begin();
50672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       it != listeners.end(); ++it) {
507ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!it->filter.urls.is_empty() && !it->filter.urls.ContainsURL(url))
508ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      continue;
509ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (it->filter.tab_id != -1 && tab_id != it->filter.tab_id)
510ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      continue;
511ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (it->filter.window_id != -1 && window_id != it->filter.window_id)
512ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      continue;
513ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!it->filter.types.empty() &&
514ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        std::find(it->filter.types.begin(), it->filter.types.end(),
515ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                  resource_type) == it->filter.types.end())
516ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      continue;
517ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
518ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    matching_listeners.push_back(&(*it));
51972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
52072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return matching_listeners;
52172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
52272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
523ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstd::vector<const ExtensionWebRequestEventRouter::EventListener*>
524ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenExtensionWebRequestEventRouter::GetMatchingListeners(
525ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ProfileId profile_id,
526ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& event_name,
527ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    net::URLRequest* request) {
528ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int tab_id = -1;
529ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int window_id = -1;
530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ResourceType::Type resource_type = ResourceType::LAST_TYPE;
531ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ExtractRequestInfo(request, &tab_id, &window_id, &resource_type);
532ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
533ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return GetMatchingListeners(
534ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      profile_id, event_name, request->url(), tab_id, window_id, resource_type);
535ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
536ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
537ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ExtensionWebRequestEventRouter::DecrementBlockCount(uint64 request_id,
538ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                         bool cancel,
539ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                         const GURL& new_url) {
540ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // It's possible that this request was deleted, or cancelled by a previous
541ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // event handler. If so, ignore this response.
542ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (blocked_requests_.find(request_id) == blocked_requests_.end())
543ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
544ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
545ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  BlockedRequest& blocked_request = blocked_requests_[request_id];
546ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int num_handlers_blocking = --blocked_request.num_handlers_blocking;
547ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK_GE(num_handlers_blocking, 0);
548ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
549ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (num_handlers_blocking == 0 || cancel || !new_url.is_empty()) {
550ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    HISTOGRAM_TIMES("Extensions.NetworkDelay",
551ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     base::Time::Now() - blocked_request.request_time);
552ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
553ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    CHECK(blocked_request.callback);
554ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!new_url.is_empty()) {
555ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      CHECK(new_url.is_valid());
556ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *blocked_request.new_url = new_url;
557ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
558ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    blocked_request.callback->Run(cancel ? net::ERR_EMPTY_RESPONSE : net::OK);
559ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    blocked_requests_.erase(request_id);
560ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
561ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
562ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
56372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool WebRequestAddEventListener::RunImpl() {
56472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Argument 0 is the callback, which we don't use here.
56572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
56672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  ExtensionWebRequestEventRouter::RequestFilter filter;
56772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (HasOptionalArgument(1)) {
56872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    DictionaryValue* value = NULL;
56972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &value));
57072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    EXTENSION_FUNCTION_VALIDATE(filter.InitFromValue(*value));
57172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
57272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
57372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int extra_info_spec = 0;
57472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (HasOptionalArgument(2)) {
57572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ListValue* value = NULL;
57672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
57772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    EXTENSION_FUNCTION_VALIDATE(
57872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
57972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            *value, &extra_info_spec));
58072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
58172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
58272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string event_name;
58372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  EXTENSION_FUNCTION_VALIDATE(args_->GetString(3, &event_name));
58472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
58572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string sub_event_name;
58672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  EXTENSION_FUNCTION_VALIDATE(args_->GetString(4, &sub_event_name));
58772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
58872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  BrowserThread::PostTask(
58972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      BrowserThread::IO, FROM_HERE,
59072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      NewRunnableFunction(
59172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          &AddEventListenerOnIOThread,
592ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          profile()->GetRuntimeId(), extension_id(),
593ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          event_name, sub_event_name, filter, extra_info_spec));
594ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
595ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return true;
596ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
597ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
598ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool WebRequestEventHandled::RunImpl() {
599ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string event_name;
600ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &event_name));
601ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
602ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string sub_event_name;
603ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXTENSION_FUNCTION_VALIDATE(args_->GetString(1, &sub_event_name));
604ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
605ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::string request_id_str;
606ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXTENSION_FUNCTION_VALIDATE(args_->GetString(2, &request_id_str));
607ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(mpcomplete): string-to-uint64?
608ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int64 request_id;
609ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EXTENSION_FUNCTION_VALIDATE(base::StringToInt64(request_id_str, &request_id));
610ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
611ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool cancel = false;
612ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GURL new_url;
613ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (HasOptionalArgument(3)) {
614ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DictionaryValue* value = NULL;
615ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(3, &value));
616ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
617ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (value->HasKey("cancel"))
618ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      EXTENSION_FUNCTION_VALIDATE(value->GetBoolean("cancel", &cancel));
619ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
620ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::string new_url_str;
621ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (value->HasKey("redirectUrl")) {
622ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      EXTENSION_FUNCTION_VALIDATE(value->GetString("redirectUrl",
623ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                   &new_url_str));
624ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      new_url = GURL(new_url_str);
625ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (!new_url.is_valid()) {
626ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        error_ = ExtensionErrorUtils::FormatErrorMessage(
627ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            keys::kInvalidRedirectUrl, new_url_str);
628ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return false;
629ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
630ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
631ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
632ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
633ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  BrowserThread::PostTask(
634ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      BrowserThread::IO, FROM_HERE,
635ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NewRunnableFunction(
636ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          &EventHandledOnIOThread,
637ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          profile()->GetRuntimeId(), extension_id(),
638ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          event_name, sub_event_name, request_id, cancel, new_url));
63972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
64072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return true;
64172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
642