summaryrefslogtreecommitdiffstats
path: root/extensions
diff options
context:
space:
mode:
authorrob <rob@robwu.nl>2016-01-12 12:48:40 -0800
committerCommit bot <commit-bot@chromium.org>2016-01-12 20:49:55 +0000
commit3eb7a397449be2eda5f8ad5ad4436ad8377563c6 (patch)
tree7cf31f34acbac26151e9f9b913bff7184a5be329 /extensions
parent9f255ecca2d40b0c2172052d873d9d7e7646441f (diff)
downloadchromium_src-3eb7a397449be2eda5f8ad5ad4436ad8377563c6.zip
chromium_src-3eb7a397449be2eda5f8ad5ad4436ad8377563c6.tar.gz
chromium_src-3eb7a397449be2eda5f8ad5ad4436ad8377563c6.tar.bz2
WebRequest API cleanup
Cleanup changes: - Moved the event dictionary generation logic to a new class (WebRequestEventDetails), to deduplicate logic and make it easier to manipulate the event details. - Remove some unused aliases, forward-declarations and includes. - Fixed a few typos. - Moved ExtraInfoSpec to web_request_api_helpers. - Remove ExtractRequestInfoDetails. - Solved TODOs from https://codereview.chromium.org/1413853005/ - Avoid unnecessary copying of event details (request body and headers, response headers). Previously these dictionaries were always copied and removed later, which is wasteful. Visible changes: - When a request has no response headers, the status code defaults to -1 (from URLRequestJob) instead of a dummy value of 200. This affects the webRequest.onResponseStarted and webRequest.onCompleted events for file: and ftp: requests. The new behavior is consistent with the webRequest.onBeforeRedirect event (which also reports -1 for unknown statuses). - requestBody is only included if set in extraInfoSpec (bug 542719). BUG=432875,542719 TEST=./browser_tests --gtest_filter=ExtensionWebRequestApiTest.* ./unit_tests --gtest_filter=ExtensionWebRequestTest.* Review URL: https://codereview.chromium.org/1577673002 Cr-Commit-Position: refs/heads/master@{#368979}
Diffstat (limited to 'extensions')
-rw-r--r--extensions/browser/api/web_request/web_request_api.cc489
-rw-r--r--extensions/browser/api/web_request/web_request_api.h39
-rw-r--r--extensions/browser/api/web_request/web_request_api_helpers.cc27
-rw-r--r--extensions/browser/api/web_request/web_request_api_helpers.h15
-rw-r--r--extensions/browser/api/web_request/web_request_event_details.cc199
-rw-r--r--extensions/browser/api/web_request/web_request_event_details.h144
-rw-r--r--extensions/browser/api/web_request/web_request_event_router_delegate.cc3
-rw-r--r--extensions/browser/api/web_request/web_request_event_router_delegate.h10
-rw-r--r--extensions/extensions.gypi2
9 files changed, 507 insertions, 421 deletions
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index b3855a3..76db07f 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -22,25 +22,22 @@
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
-#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/user_metrics.h"
+#include "content/public/common/child_process_host.h"
#include "extensions/browser/api/activity_log/web_request_constants.h"
#include "extensions/browser/api/declarative/rules_registry_service.h"
#include "extensions/browser/api/declarative_webrequest/request_stage.h"
#include "extensions/browser/api/declarative_webrequest/webrequest_constants.h"
#include "extensions/browser/api/declarative_webrequest/webrequest_rules_registry.h"
#include "extensions/browser/api/extensions_api_client.h"
-#include "extensions/browser/api/web_request/upload_data_presenter.h"
#include "extensions/browser/api/web_request/web_request_api_constants.h"
#include "extensions/browser/api/web_request/web_request_api_helpers.h"
+#include "extensions/browser/api/web_request/web_request_event_details.h"
#include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
#include "extensions/browser/api/web_request/web_request_time_tracker.h"
#include "extensions/browser/event_router.h"
-#include "extensions/browser/extension_api_frame_id_map.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
@@ -63,20 +60,14 @@
#include "extensions/strings/grit/extensions_strings.h"
#include "net/base/auth.h"
#include "net/base/net_errors.h"
-#include "net/base/upload_data_stream.h"
-#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/url_request/url_request.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
-using base::DictionaryValue;
-using base::ListValue;
-using base::StringValue;
-using content::BrowserMessageFilter;
using content::BrowserThread;
using content::ResourceRequestInfo;
-using content::ResourceType;
+using extension_web_request_api_helpers::ExtraInfoSpec;
namespace activity_log = activity_log_web_request_constants;
namespace helpers = extension_web_request_api_helpers;
@@ -200,86 +191,6 @@ bool GetWebViewInfo(const net::URLRequest* request,
render_process_host_id, routing_id, web_view_info);
}
-void ExtractRequestInfoDetails(const net::URLRequest* request,
- bool* is_main_frame,
- int* render_frame_id,
- int* render_process_host_id,
- int* routing_id,
- ResourceType* resource_type) {
- const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
- if (!info)
- return;
-
- *render_frame_id = info->GetRenderFrameID();
- *is_main_frame = info->IsMainFrame();
- *render_process_host_id = info->GetChildID();
- *routing_id = info->GetRouteID();
-
- // Restrict the resource type to the values we care about.
- if (helpers::IsRelevantResourceType(info->GetResourceType()))
- *resource_type = info->GetResourceType();
- else
- *resource_type = content::RESOURCE_TYPE_LAST_TYPE;
-}
-
-// Extracts a pair of IDs to identify the RenderFrameHost. These IDs are used to
-// get the frame ID and parent frame ID from ExtensionApiFrameIdMap, and then
-// stored in |dict| by DispatchEventToListeners or SendOnMessageEventOnUI.
-void ExtractRenderFrameInfo(base::DictionaryValue* dict,
- int* render_process_id,
- int* render_frame_id) {
- if (!dict->GetInteger(keys::kFrameIdKey, render_frame_id) ||
- !dict->GetInteger(keys::kProcessIdKey, render_process_id)) {
- *render_process_id = -1;
- *render_frame_id = -1;
- }
- // kFrameIdKey will be overwritten later, so it's not removed here.
- dict->Remove(keys::kProcessIdKey, nullptr);
-}
-
-// Extracts the body from |request| and writes the data into |out|.
-void ExtractRequestInfoBody(const net::URLRequest* request,
- base::DictionaryValue* out) {
- const net::UploadDataStream* upload_data = request->get_upload();
- if (!upload_data ||
- (request->method() != "POST" && request->method() != "PUT")) {
- return; // Need to exit without "out->Set(keys::kRequestBodyKey, ...);" .
- }
-
- base::DictionaryValue* request_body = new base::DictionaryValue();
- out->Set(keys::kRequestBodyKey, request_body);
-
- // Get the data presenters, ordered by how specific they are.
- ParsedDataPresenter parsed_data_presenter(*request);
- RawDataPresenter raw_data_presenter;
- UploadDataPresenter* const presenters[] = {
- &parsed_data_presenter, // 1: any parseable forms? (Specific to forms.)
- &raw_data_presenter // 2: any data at all? (Non-specific.)
- };
- // Keys for the results of the corresponding presenters.
- static const char* const kKeys[] = {
- keys::kRequestBodyFormDataKey,
- keys::kRequestBodyRawKey
- };
-
- const std::vector<scoped_ptr<net::UploadElementReader>>* readers =
- upload_data->GetElementReaders();
- bool some_succeeded = false;
- if (readers) {
- for (size_t i = 0; i < arraysize(presenters); ++i) {
- for (const auto& reader : *readers)
- presenters[i]->FeedNext(*reader);
- if (presenters[i]->Succeeded()) {
- request_body->Set(kKeys[i], presenters[i]->Result().release());
- some_succeeded = true;
- break;
- }
- }
- }
- if (!some_succeeded)
- request_body->SetString(keys::kRequestBodyErrorKey, "Unknown error.");
-}
-
// Converts a HttpHeaders dictionary to a |name|, |value| pair. Returns
// true if successful.
bool FromHeaderDictionary(const base::DictionaryValue* header_value,
@@ -310,43 +221,6 @@ bool FromHeaderDictionary(const base::DictionaryValue* header_value,
return true;
}
-// Creates a list of HttpHeaders (see the extension API JSON). If |headers| is
-// NULL, the list is empty. Ownership is passed to the caller.
-base::ListValue* GetResponseHeadersList(
- const net::HttpResponseHeaders* headers) {
- base::ListValue* headers_value = new base::ListValue();
- if (headers) {
- void* iter = NULL;
- std::string name;
- std::string value;
- while (headers->EnumerateHeaderLines(&iter, &name, &value))
- headers_value->Append(helpers::CreateHeaderDictionary(name, value));
- }
- return headers_value;
-}
-
-base::ListValue* GetRequestHeadersList(const net::HttpRequestHeaders& headers) {
- base::ListValue* headers_value = new base::ListValue();
- for (net::HttpRequestHeaders::Iterator it(headers); it.GetNext(); )
- headers_value->Append(
- helpers::CreateHeaderDictionary(it.name(), it.value()));
- return headers_value;
-}
-
-// Creates a base::StringValue with the status line of |headers|. If |headers|
-// is NULL, an empty string is returned. Ownership is passed to the caller.
-base::StringValue* GetStatusLine(net::HttpResponseHeaders* headers) {
- return new base::StringValue(
- headers ? headers->GetStatusLine() : std::string());
-}
-
-// Returns the response code from the response headers, or 200 by default.
-// |headers| may be NULL, e.g. UrlRequestFileJobs do not send headers, so
-// simulate their behavior.
-int GetResponseCodeWithDefault(net::HttpResponseHeaders* headers) {
- return headers ? headers->response_code() : 200;
-}
-
// Sends an event to subscribers of chrome.declarativeWebRequest.onMessage or
// to subscribers of webview.onMessage if the action is being operated upon
// a <webview> guest renderer.
@@ -354,13 +228,13 @@ int GetResponseCodeWithDefault(net::HttpResponseHeaders* headers) {
// |is_web_view_guest| indicates whether the action is for a <webview>.
// |web_view_info| is a struct containing information about the <webview>
// embedder.
-// |event_argument| is passed to the event listener.
+// |event_details| is passed to the event listener.
void SendOnMessageEventOnUI(
void* browser_context_id,
const std::string& extension_id,
bool is_web_view_guest,
const WebViewRendererState::WebViewInfo& web_view_info,
- scoped_ptr<base::DictionaryValue> event_argument) {
+ scoped_ptr<WebRequestEventDetails> event_details) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::BrowserContext* browser_context =
@@ -369,17 +243,8 @@ void SendOnMessageEventOnUI(
return;
scoped_ptr<base::ListValue> event_args(new base::ListValue);
- int render_process_host_id = -1;
- int render_frame_id = -1;
- ExtractRenderFrameInfo(event_argument.get(), &render_process_host_id,
- &render_frame_id);
- content::RenderFrameHost* rfh =
- content::RenderFrameHost::FromID(render_process_host_id, render_frame_id);
- event_argument->SetInteger(keys::kFrameIdKey,
- ExtensionApiFrameIdMap::GetFrameId(rfh));
- event_argument->SetInteger(keys::kParentFrameIdKey,
- ExtensionApiFrameIdMap::GetParentFrameId(rfh));
- event_args->Append(event_argument.release());
+ event_details->DetermineFrameIdOnUI();
+ event_args->Append(event_details->GetAndClearDict());
EventRouter* event_router = EventRouter::Get(browser_context);
@@ -662,7 +527,7 @@ bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
return false;
for (size_t i = 0; i < types_value->GetSize(); ++i) {
std::string type_str;
- ResourceType type;
+ content::ResourceType type;
if (!types_value->GetString(i, &type_str) ||
!helpers::ParseResourceType(type_str, &type)) {
return false;
@@ -682,36 +547,6 @@ bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
return true;
}
-// static
-bool ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
- const base::ListValue& value, int* extra_info_spec) {
- *extra_info_spec = 0;
- for (size_t i = 0; i < value.GetSize(); ++i) {
- std::string str;
- if (!value.GetString(i, &str))
- return false;
-
- if (str == "requestHeaders")
- *extra_info_spec |= REQUEST_HEADERS;
- else if (str == "responseHeaders")
- *extra_info_spec |= RESPONSE_HEADERS;
- else if (str == "blocking")
- *extra_info_spec |= BLOCKING;
- else if (str == "asyncBlocking")
- *extra_info_spec |= ASYNC_BLOCKING;
- else if (str == "requestBody")
- *extra_info_spec |= REQUEST_BODY;
- else
- return false;
-
- // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
- if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
- return false;
- }
- return true;
-}
-
-
ExtensionWebRequestEventRouter::EventResponse::EventResponse(
const std::string& extension_id, const base::Time& extension_install_time)
: extension_id(extension_id),
@@ -758,34 +593,18 @@ void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
rules_registries_.erase(key);
}
-void ExtensionWebRequestEventRouter::ExtractRequestInfo(
+scoped_ptr<WebRequestEventDetails>
+ExtensionWebRequestEventRouter::CreateEventDetails(
const net::URLRequest* request,
- base::DictionaryValue* out) {
- bool is_main_frame = false;
- int render_frame_id = -1;
- int render_process_host_id = -1;
- int routing_id = -1;
- ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
- ExtractRequestInfoDetails(request, &is_main_frame, &render_frame_id,
- &render_process_host_id, &routing_id,
- &resource_type);
-
- out->SetString(keys::kRequestIdKey,
- base::Uint64ToString(request->identifier()));
- out->SetString(keys::kUrlKey, request->url().spec());
- out->SetString(keys::kMethodKey, request->method());
- // Note: This (frameId, processId) pair is removed by ExtractRenderFrameInfo,
- // and finally restored in DispatchEventToListeners or SendOnMessageEventOnUI.
- // TODO(robwu): This is ugly. Create a proper data structure to separate these
- // two IDs from the dictionary, so that kFrameIdKey has only one meaning.
- out->SetInteger(keys::kFrameIdKey, render_frame_id);
- out->SetInteger(keys::kProcessIdKey, render_process_host_id);
- out->SetString(keys::kTypeKey, helpers::ResourceTypeToString(resource_type));
- out->SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
+ int extra_info_spec) {
+ scoped_ptr<WebRequestEventDetails> event_details(
+ new WebRequestEventDetails(request, extra_info_spec));
+
if (web_request_event_router_delegate_) {
web_request_event_router_delegate_->ExtractExtraRequestDetails(
- request, out);
+ request, event_details.get());
}
+ return event_details;
}
int ExtensionWebRequestEventRouter::OnBeforeRequest(
@@ -819,15 +638,12 @@ int ExtensionWebRequestEventRouter::OnBeforeRequest(
web_request::OnBeforeRequest::kEventName, request, &extra_info_spec);
if (!listeners.empty() &&
!GetAndSetSignaled(request->identifier(), kOnBeforeRequest)) {
- base::ListValue args;
- base::DictionaryValue* dict = new base::DictionaryValue();
- ExtractRequestInfo(request, dict);
- if (extra_info_spec & ExtraInfoSpec::REQUEST_BODY)
- ExtractRequestInfoBody(request, dict);
- args.Append(dict);
-
- initialize_blocked_requests |=
- DispatchEvent(browser_context, request, listeners, args);
+ scoped_ptr<WebRequestEventDetails> event_details(
+ CreateEventDetails(request, extra_info_spec));
+ event_details->SetRequestBody(request);
+
+ initialize_blocked_requests |= DispatchEvent(
+ browser_context, request, listeners, std::move(event_details));
}
if (!initialize_blocked_requests)
@@ -871,15 +687,12 @@ int ExtensionWebRequestEventRouter::OnBeforeSendHeaders(
request, &extra_info_spec);
if (!listeners.empty() &&
!GetAndSetSignaled(request->identifier(), kOnBeforeSendHeaders)) {
- base::ListValue args;
- base::DictionaryValue* dict = new base::DictionaryValue();
- ExtractRequestInfo(request, dict);
- if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
- dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(*headers));
- args.Append(dict);
-
- initialize_blocked_requests |=
- DispatchEvent(browser_context, request, listeners, args);
+ scoped_ptr<WebRequestEventDetails> event_details(
+ CreateEventDetails(request, extra_info_spec));
+ event_details->SetRequestHeaders(*headers);
+
+ initialize_blocked_requests |= DispatchEvent(
+ browser_context, request, listeners, std::move(event_details));
}
if (!initialize_blocked_requests)
@@ -922,14 +735,11 @@ void ExtensionWebRequestEventRouter::OnSendHeaders(
if (listeners.empty())
return;
- base::ListValue args;
- base::DictionaryValue* dict = new base::DictionaryValue();
- ExtractRequestInfo(request, dict);
- if (extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS)
- dict->Set(keys::kRequestHeadersKey, GetRequestHeadersList(headers));
- args.Append(dict);
+ scoped_ptr<WebRequestEventDetails> event_details(
+ CreateEventDetails(request, extra_info_spec));
+ event_details->SetRequestHeaders(headers);
- DispatchEvent(browser_context, request, listeners, args);
+ DispatchEvent(browser_context, request, listeners, std::move(event_details));
}
int ExtensionWebRequestEventRouter::OnHeadersReceived(
@@ -956,21 +766,12 @@ int ExtensionWebRequestEventRouter::OnHeadersReceived(
if (!listeners.empty() &&
!GetAndSetSignaled(request->identifier(), kOnHeadersReceived)) {
- base::ListValue args;
- base::DictionaryValue* dict = new base::DictionaryValue();
- ExtractRequestInfo(request, dict);
- dict->SetString(keys::kStatusLineKey,
- original_response_headers->GetStatusLine());
- dict->SetInteger(keys::kStatusCodeKey,
- original_response_headers->response_code());
- if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
- dict->Set(keys::kResponseHeadersKey,
- GetResponseHeadersList(original_response_headers));
- }
- args.Append(dict);
+ scoped_ptr<WebRequestEventDetails> event_details(
+ CreateEventDetails(request, extra_info_spec));
+ event_details->SetResponseHeaders(request, original_response_headers);
- initialize_blocked_requests |=
- DispatchEvent(browser_context, request, listeners, args);
+ initialize_blocked_requests |= DispatchEvent(
+ browser_context, request, listeners, std::move(event_details));
}
if (!initialize_blocked_requests)
@@ -1017,30 +818,13 @@ ExtensionWebRequestEventRouter::OnAuthRequired(
if (listeners.empty())
return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
- base::ListValue args;
- base::DictionaryValue* dict = new base::DictionaryValue();
- ExtractRequestInfo(request, dict);
- dict->SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
- if (!auth_info.scheme.empty())
- dict->SetString(keys::kSchemeKey, auth_info.scheme);
- if (!auth_info.realm.empty())
- dict->SetString(keys::kRealmKey, auth_info.realm);
- base::DictionaryValue* challenger = new base::DictionaryValue();
- challenger->SetString(keys::kHostKey, auth_info.challenger.host());
- challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
- dict->Set(keys::kChallengerKey, challenger);
- dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
- if (request->response_headers()) {
- dict->SetInteger(keys::kStatusCodeKey,
- request->response_headers()->response_code());
- }
- if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
- dict->Set(keys::kResponseHeadersKey,
- GetResponseHeadersList(request->response_headers()));
- }
- args.Append(dict);
+ scoped_ptr<WebRequestEventDetails> event_details(
+ CreateEventDetails(request, extra_info_spec));
+ event_details->SetResponseHeaders(request, request->response_headers());
+ event_details->SetAuthInfo(auth_info);
- if (DispatchEvent(browser_context, request, listeners, args)) {
+ if (DispatchEvent(browser_context, request, listeners,
+ std::move(event_details))) {
BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
blocked_request.event = kOnAuthRequired;
blocked_request.is_incognito |= IsIncognitoBrowserContext(browser_context);
@@ -1076,26 +860,13 @@ void ExtensionWebRequestEventRouter::OnBeforeRedirect(
if (listeners.empty())
return;
- int http_status_code = request->GetResponseCode();
-
- std::string response_ip = request->GetSocketAddress().host();
-
- base::ListValue args;
- base::DictionaryValue* dict = new base::DictionaryValue();
- ExtractRequestInfo(request, dict);
- dict->SetString(keys::kRedirectUrlKey, new_location.spec());
- dict->SetInteger(keys::kStatusCodeKey, http_status_code);
- if (!response_ip.empty())
- dict->SetString(keys::kIpKey, response_ip);
- dict->SetBoolean(keys::kFromCache, request->was_cached());
- dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
- if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
- dict->Set(keys::kResponseHeadersKey,
- GetResponseHeadersList(request->response_headers()));
- }
- args.Append(dict);
+ scoped_ptr<WebRequestEventDetails> event_details(
+ CreateEventDetails(request, extra_info_spec));
+ event_details->SetResponseHeaders(request, request->response_headers());
+ event_details->SetResponseSource(request);
+ event_details->SetString(keys::kRedirectUrlKey, new_location.spec());
- DispatchEvent(browser_context, request, listeners, args);
+ DispatchEvent(browser_context, request, listeners, std::move(event_details));
}
void ExtensionWebRequestEventRouter::OnResponseStarted(
@@ -1116,24 +887,12 @@ void ExtensionWebRequestEventRouter::OnResponseStarted(
if (listeners.empty())
return;
- std::string response_ip = request->GetSocketAddress().host();
-
- base::ListValue args;
- base::DictionaryValue* dict = new base::DictionaryValue();
- ExtractRequestInfo(request, dict);
- if (!response_ip.empty())
- dict->SetString(keys::kIpKey, response_ip);
- dict->SetBoolean(keys::kFromCache, request->was_cached());
- dict->SetInteger(keys::kStatusCodeKey,
- GetResponseCodeWithDefault(request->response_headers()));
- dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
- if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
- dict->Set(keys::kResponseHeadersKey,
- GetResponseHeadersList(request->response_headers()));
- }
- args.Append(dict);
+ scoped_ptr<WebRequestEventDetails> event_details(
+ CreateEventDetails(request, extra_info_spec));
+ event_details->SetResponseHeaders(request, request->response_headers());
+ event_details->SetResponseSource(request);
- DispatchEvent(browser_context, request, listeners, args);
+ DispatchEvent(browser_context, request, listeners, std::move(event_details));
}
void ExtensionWebRequestEventRouter::OnCompleted(
@@ -1166,24 +925,12 @@ void ExtensionWebRequestEventRouter::OnCompleted(
if (listeners.empty())
return;
- std::string response_ip = request->GetSocketAddress().host();
-
- base::ListValue args;
- base::DictionaryValue* dict = new base::DictionaryValue();
- ExtractRequestInfo(request, dict);
- dict->SetInteger(keys::kStatusCodeKey,
- GetResponseCodeWithDefault(request->response_headers()));
- if (!response_ip.empty())
- dict->SetString(keys::kIpKey, response_ip);
- dict->SetBoolean(keys::kFromCache, request->was_cached());
- dict->Set(keys::kStatusLineKey, GetStatusLine(request->response_headers()));
- if (extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) {
- dict->Set(keys::kResponseHeadersKey,
- GetResponseHeadersList(request->response_headers()));
- }
- args.Append(dict);
+ scoped_ptr<WebRequestEventDetails> event_details(
+ CreateEventDetails(request, extra_info_spec));
+ event_details->SetResponseHeaders(request, request->response_headers());
+ event_details->SetResponseSource(request);
- DispatchEvent(browser_context, request, listeners, args);
+ DispatchEvent(browser_context, request, listeners, std::move(event_details));
}
void ExtensionWebRequestEventRouter::OnErrorOccurred(
@@ -1218,20 +965,16 @@ void ExtensionWebRequestEventRouter::OnErrorOccurred(
if (listeners.empty())
return;
- base::ListValue args;
- base::DictionaryValue* dict = new base::DictionaryValue();
- ExtractRequestInfo(request, dict);
- if (started) {
- std::string response_ip = request->GetSocketAddress().host();
- if (!response_ip.empty())
- dict->SetString(keys::kIpKey, response_ip);
- }
- dict->SetBoolean(keys::kFromCache, request->was_cached());
- dict->SetString(keys::kErrorKey,
- net::ErrorToString(request->status().error()));
- args.Append(dict);
+ scoped_ptr<WebRequestEventDetails> event_details(
+ CreateEventDetails(request, extra_info_spec));
+ if (started)
+ event_details->SetResponseSource(request);
+ else
+ event_details->SetBoolean(keys::kFromCache, request->was_cached());
+ event_details->SetString(keys::kErrorKey,
+ net::ErrorToString(request->status().error()));
- DispatchEvent(browser_context, request, listeners, args);
+ DispatchEvent(browser_context, request, listeners, std::move(event_details));
}
void ExtensionWebRequestEventRouter::OnURLRequestDestroyed(
@@ -1254,7 +997,7 @@ bool ExtensionWebRequestEventRouter::DispatchEvent(
void* browser_context,
net::URLRequest* request,
const std::vector<const EventListener*>& listeners,
- const base::ListValue& args) {
+ scoped_ptr<WebRequestEventDetails> event_details) {
// TODO(mpcomplete): Consider consolidating common (extension_id,json_args)
// pairs into a single message sent to a list of sub_event_names.
int num_handlers_blocking = 0;
@@ -1281,21 +1024,9 @@ bool ExtensionWebRequestEventRouter::DispatchEvent(
}
}
- // TODO(robwu): Avoid unnecessary copy, by changing |args| to be a
- // scoped_ptr<base::DictionaryValue> and transferring the ownership.
- const base::DictionaryValue* dict = nullptr;
- CHECK(args.GetDictionary(0, &dict) && dict);
- base::DictionaryValue* args_copy = dict->DeepCopy();
-
- int render_process_host_id = -1;
- int render_frame_id = -1;
- ExtractRenderFrameInfo(args_copy, &render_process_host_id, &render_frame_id);
-
- ExtensionApiFrameIdMap::Get()->GetFrameIdOnIO(
- render_process_host_id, render_frame_id,
- base::Bind(&ExtensionWebRequestEventRouter::DispatchEventToListeners,
- AsWeakPtr(), browser_context,
- base::Passed(&listeners_to_dispatch), base::Owned(args_copy)));
+ event_details.release()->DetermineFrameIdOnIO(base::Bind(
+ &ExtensionWebRequestEventRouter::DispatchEventToListeners, AsWeakPtr(),
+ browser_context, base::Passed(&listeners_to_dispatch)));
if (num_handlers_blocking > 0) {
BlockedRequest& blocked_request = blocked_requests_[request->identifier()];
@@ -1312,16 +1043,11 @@ bool ExtensionWebRequestEventRouter::DispatchEvent(
void ExtensionWebRequestEventRouter::DispatchEventToListeners(
void* browser_context,
scoped_ptr<std::vector<EventListener>> listeners,
- base::DictionaryValue* dict,
- int extension_api_frame_id,
- int extension_api_parent_frame_id) {
+ scoped_ptr<WebRequestEventDetails> event_details) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(listeners.get());
DCHECK_GT(listeners->size(), 0UL);
- DCHECK(dict);
-
- dict->SetInteger(keys::kFrameIdKey, extension_api_frame_id);
- dict->SetInteger(keys::kParentFrameIdKey, extension_api_parent_frame_id);
+ DCHECK(event_details.get());
std::string event_name =
EventRouter::GetBaseEventName((*listeners)[0].sub_event_name);
@@ -1348,11 +1074,8 @@ void ExtensionWebRequestEventRouter::DispatchEventToListeners(
// Filter out the optional keys that this listener didn't request.
scoped_ptr<base::ListValue> args_filtered(new base::ListValue);
- args_filtered->Append(dict->DeepCopy());
- if (!(listener->extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS))
- dict->Remove(keys::kRequestHeadersKey, nullptr);
- if (!(listener->extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS))
- dict->Remove(keys::kResponseHeadersKey, nullptr);
+ args_filtered->Append(
+ event_details->GetFilteredDict(listener->extra_info_spec));
EventRouter::DispatchEventToSender(
listener->ipc_sender.get(), browser_context, listener->extension_id,
@@ -1514,17 +1237,11 @@ void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
bool ExtensionWebRequestEventRouter::IsPageLoad(
const net::URLRequest* request) const {
- bool is_main_frame = false;
- int render_frame_id = -1;
- int render_process_host_id = -1;
- int routing_id = -1;
- ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
-
- ExtractRequestInfoDetails(request, &is_main_frame, &render_frame_id,
- &render_process_host_id, &routing_id,
- &resource_type);
+ const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
+ if (!info)
+ return false;
- return resource_type == content::RESOURCE_TYPE_MAIN_FRAME;
+ return info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME;
}
void ExtensionWebRequestEventRouter::NotifyPageLoad() {
@@ -1567,7 +1284,7 @@ void ExtensionWebRequestEventRouter::GetMatchingListenersImpl(
const GURL& url,
int render_process_host_id,
int routing_id,
- ResourceType resource_type,
+ content::ResourceType resource_type,
bool is_async_request,
bool is_request_from_extension,
int* extra_info_spec,
@@ -1661,24 +1378,24 @@ ExtensionWebRequestEventRouter::GetMatchingListeners(
// listeners).
*extra_info_spec = 0;
- bool is_main_frame = false;
- int render_frame_id = -1;
- int render_process_host_id = -1;
- int routing_id = -1;
- ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
const GURL& url = request->url();
-
- ExtractRequestInfoDetails(request, &is_main_frame, &render_frame_id,
- &render_process_host_id, &routing_id,
- &resource_type);
-
+ int render_process_host_id = content::ChildProcessHost::kInvalidUniqueID;
+ int routing_id = MSG_ROUTING_NONE;
+ content::ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
+ // We are conservative here and assume requests are asynchronous in case
+ // we don't have an info object. We don't want to risk a deadlock.
+ bool is_async_request = false;
bool is_request_from_extension =
IsRequestFromExtension(request, extension_info_map);
const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
- // We are conservative here and assume requests are asynchronous in case
- // we don't have an info object. We don't want to risk a deadlock.
- bool is_async_request = !info || info->IsAsync();
+ if (info) {
+ is_async_request = info->IsAsync();
+ if (helpers::IsRelevantResourceType(info->GetResourceType()))
+ resource_type = info->GetResourceType();
+ render_process_host_id = info->GetChildID();
+ routing_id = info->GetRouteID();
+ }
EventListeners matching_listeners;
GetMatchingListenersImpl(
@@ -1951,20 +1668,20 @@ void ExtensionWebRequestEventRouter::SendMessages(
for (const auto& delta : deltas) {
const std::set<std::string>& messages = delta->messages_to_extension;
for (const std::string& message : messages) {
- scoped_ptr<base::DictionaryValue> argument(new base::DictionaryValue);
- ExtractRequestInfo(blocked_request.request, argument.get());
+ scoped_ptr<WebRequestEventDetails> event_details(
+ CreateEventDetails(blocked_request.request, /* extra_info_spec */ 0));
WebViewRendererState::WebViewInfo web_view_info;
bool is_web_view_guest = GetWebViewInfo(blocked_request.request,
&web_view_info);
- argument->SetString(keys::kMessageKey, message);
- argument->SetString(keys::kStageKey,
- GetRequestStageAsString(blocked_request.event));
+ event_details->SetString(keys::kMessageKey, message);
+ event_details->SetString(keys::kStageKey,
+ GetRequestStageAsString(blocked_request.event));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&SendOnMessageEventOnUI, browser_context,
delta->extension_id, is_web_view_guest, web_view_info,
- base::Passed(&argument)));
+ base::Passed(&event_details)));
}
}
}
@@ -2294,8 +2011,7 @@ bool WebRequestInternalAddEventListenerFunction::RunSync() {
base::ListValue* value = NULL;
EXTENSION_FUNCTION_VALIDATE(args_->GetList(2, &value));
EXTENSION_FUNCTION_VALIDATE(
- ExtensionWebRequestEventRouter::ExtraInfoSpec::InitFromValue(
- *value, &extra_info_spec));
+ ExtraInfoSpec::InitFromValue(*value, &extra_info_spec));
}
std::string event_name;
@@ -2320,8 +2036,7 @@ bool WebRequestInternalAddEventListenerFunction::RunSync() {
// permission. For blocking calls we require the additional permission
// 'webRequestBlocking'.
if ((extra_info_spec &
- (ExtensionWebRequestEventRouter::ExtraInfoSpec::BLOCKING |
- ExtensionWebRequestEventRouter::ExtraInfoSpec::ASYNC_BLOCKING)) &&
+ (ExtraInfoSpec::BLOCKING | ExtraInfoSpec::ASYNC_BLOCKING)) &&
!extension->permissions_data()->HasAPIPermission(
APIPermission::kWebRequestBlocking)) {
error_ = keys::kBlockingPermissionRequired;
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h
index 191005d..805d11b 100644
--- a/extensions/browser/api/web_request/web_request_api.h
+++ b/extensions/browser/api/web_request/web_request_api.h
@@ -57,6 +57,7 @@ class URLRequest;
namespace extensions {
class InfoMap;
+class WebRequestEventDetails;
class WebRequestRulesRegistry;
class WebRequestEventRouterDelegate;
@@ -127,22 +128,6 @@ class ExtensionWebRequestEventRouter
int window_id;
};
- // Internal representation of the extraInfoSpec parameter on webRequest
- // events, used to specify extra information to be included with network
- // events.
- struct ExtraInfoSpec {
- enum Flags {
- REQUEST_HEADERS = 1<<0,
- RESPONSE_HEADERS = 1<<1,
- BLOCKING = 1<<2,
- ASYNC_BLOCKING = 1<<3,
- REQUEST_BODY = 1<<4,
- };
-
- static bool InitFromValue(const base::ListValue& value,
- int* extra_info_spec);
- };
-
// Contains an extension's response to a blocking event.
struct EventResponse {
EventResponse(const std::string& extension_id,
@@ -336,18 +321,15 @@ class ExtensionWebRequestEventRouter
// destroyed safely.
void ClearPendingCallbacks(const net::URLRequest* request);
- bool DispatchEvent(
- void* browser_context,
- net::URLRequest* request,
- const std::vector<const EventListener*>& listeners,
- const base::ListValue& args);
+ bool DispatchEvent(void* browser_context,
+ net::URLRequest* request,
+ const std::vector<const EventListener*>& listeners,
+ scoped_ptr<WebRequestEventDetails> event_details);
void DispatchEventToListeners(
void* browser_context,
scoped_ptr<std::vector<EventListener>> listeners,
- base::DictionaryValue* dict,
- int extension_api_frame_id,
- int extension_api_parent_frame_id);
+ scoped_ptr<WebRequestEventDetails> event_details);
// Returns a list of event listeners that care about the given event, based
// on their filter parameters. |extra_info_spec| will contain the combined
@@ -434,11 +416,10 @@ class ExtensionWebRequestEventRouter
uint64_t request_id,
extensions::RequestStage request_stage);
- // Extracts from |request| information for the keys requestId, url, method,
- // frameId, tabId, type, and timeStamp and writes these into |out| to be
- // passed on to extensions.
- void ExtractRequestInfo(const net::URLRequest* request,
- base::DictionaryValue* out);
+ // Returns event details for a given request.
+ scoped_ptr<WebRequestEventDetails> CreateEventDetails(
+ const net::URLRequest* request,
+ int extra_info_spec);
// Sets the flag that |event_type| has been signaled for |request_id|.
// Returns the value of the flag before setting it.
diff --git a/extensions/browser/api/web_request/web_request_api_helpers.cc b/extensions/browser/api/web_request/web_request_api_helpers.cc
index fd21d2c..6f86bf4 100644
--- a/extensions/browser/api/web_request/web_request_api_helpers.cc
+++ b/extensions/browser/api/web_request/web_request_api_helpers.cc
@@ -137,6 +137,33 @@ bool NullableEquals(const std::string* a, const std::string* b) {
} // namespace
+bool ExtraInfoSpec::InitFromValue(const base::ListValue& value,
+ int* extra_info_spec) {
+ *extra_info_spec = 0;
+ for (size_t i = 0; i < value.GetSize(); ++i) {
+ std::string str;
+ if (!value.GetString(i, &str))
+ return false;
+
+ if (str == "requestHeaders")
+ *extra_info_spec |= REQUEST_HEADERS;
+ else if (str == "responseHeaders")
+ *extra_info_spec |= RESPONSE_HEADERS;
+ else if (str == "blocking")
+ *extra_info_spec |= BLOCKING;
+ else if (str == "asyncBlocking")
+ *extra_info_spec |= ASYNC_BLOCKING;
+ else if (str == "requestBody")
+ *extra_info_spec |= REQUEST_BODY;
+ else
+ return false;
+ }
+ // BLOCKING and ASYNC_BLOCKING are mutually exclusive.
+ if ((*extra_info_spec & BLOCKING) && (*extra_info_spec & ASYNC_BLOCKING))
+ return false;
+ return true;
+}
+
RequestCookie::RequestCookie() {}
RequestCookie::~RequestCookie() {}
diff --git a/extensions/browser/api/web_request/web_request_api_helpers.h b/extensions/browser/api/web_request/web_request_api_helpers.h
index e6cd1c0e..a867fee 100644
--- a/extensions/browser/api/web_request/web_request_api_helpers.h
+++ b/extensions/browser/api/web_request/web_request_api_helpers.h
@@ -46,6 +46,21 @@ namespace extension_web_request_api_helpers {
typedef std::pair<std::string, std::string> ResponseHeader;
typedef std::vector<ResponseHeader> ResponseHeaders;
+// Internal representation of the extraInfoSpec parameter on webRequest
+// events, used to specify extra information to be included with network
+// events.
+struct ExtraInfoSpec {
+ enum Flags {
+ REQUEST_HEADERS = 1 << 0,
+ RESPONSE_HEADERS = 1 << 1,
+ BLOCKING = 1 << 2,
+ ASYNC_BLOCKING = 1 << 3,
+ REQUEST_BODY = 1 << 4,
+ };
+
+ static bool InitFromValue(const base::ListValue& value, int* extra_info_spec);
+};
+
// Data container for RequestCookies as defined in the declarative WebRequest
// API definition.
struct RequestCookie {
diff --git a/extensions/browser/api/web_request/web_request_event_details.cc b/extensions/browser/api/web_request/web_request_event_details.cc
new file mode 100644
index 0000000..958faea
--- /dev/null
+++ b/extensions/browser/api/web_request/web_request_event_details.cc
@@ -0,0 +1,199 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/browser/api/web_request/web_request_event_details.h"
+
+#include "base/callback.h"
+#include "base/strings/string_number_conversions.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/common/child_process_host.h"
+#include "extensions/browser/api/web_request/upload_data_presenter.h"
+#include "extensions/browser/api/web_request/web_request_api_constants.h"
+#include "extensions/browser/api/web_request/web_request_api_helpers.h"
+#include "extensions/browser/extension_api_frame_id_map.h"
+#include "ipc/ipc_message.h"
+#include "net/base/auth.h"
+#include "net/base/upload_data_stream.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/url_request/url_request.h"
+
+using extension_web_request_api_helpers::ExtraInfoSpec;
+
+namespace helpers = extension_web_request_api_helpers;
+namespace keys = extension_web_request_api_constants;
+
+namespace extensions {
+
+WebRequestEventDetails::WebRequestEventDetails(const net::URLRequest* request,
+ int extra_info_spec)
+ : extra_info_spec_(extra_info_spec),
+ render_process_id_(content::ChildProcessHost::kInvalidUniqueID),
+ render_frame_id_(MSG_ROUTING_NONE) {
+ content::ResourceType resource_type = content::RESOURCE_TYPE_LAST_TYPE;
+ const content::ResourceRequestInfo* info =
+ content::ResourceRequestInfo::ForRequest(request);
+ if (info) {
+ render_process_id_ = info->GetChildID();
+ render_frame_id_ = info->GetRenderFrameID();
+ resource_type = info->GetResourceType();
+ }
+
+ dict_.SetString(keys::kMethodKey, request->method());
+ dict_.SetString(keys::kRequestIdKey,
+ base::Uint64ToString(request->identifier()));
+ dict_.SetDouble(keys::kTimeStampKey, base::Time::Now().ToDoubleT() * 1000);
+ dict_.SetString(keys::kTypeKey, helpers::ResourceTypeToString(resource_type));
+ dict_.SetString(keys::kUrlKey, request->url().spec());
+}
+
+WebRequestEventDetails::~WebRequestEventDetails() {}
+
+void WebRequestEventDetails::SetRequestBody(const net::URLRequest* request) {
+ if (!(extra_info_spec_ & ExtraInfoSpec::REQUEST_BODY))
+ return;
+
+ const net::UploadDataStream* upload_data = request->get_upload();
+ if (!upload_data ||
+ (request->method() != "POST" && request->method() != "PUT"))
+ return;
+
+ base::DictionaryValue* request_body = new base::DictionaryValue();
+ request_body_.reset(request_body);
+
+ // Get the data presenters, ordered by how specific they are.
+ ParsedDataPresenter parsed_data_presenter(*request);
+ RawDataPresenter raw_data_presenter;
+ UploadDataPresenter* const presenters[] = {
+ &parsed_data_presenter, // 1: any parseable forms? (Specific to forms.)
+ &raw_data_presenter // 2: any data at all? (Non-specific.)
+ };
+ // Keys for the results of the corresponding presenters.
+ static const char* const kKeys[] = {keys::kRequestBodyFormDataKey,
+ keys::kRequestBodyRawKey};
+
+ const std::vector<scoped_ptr<net::UploadElementReader>>* readers =
+ upload_data->GetElementReaders();
+ bool some_succeeded = false;
+ if (readers) {
+ for (size_t i = 0; i < arraysize(presenters); ++i) {
+ for (const auto& reader : *readers)
+ presenters[i]->FeedNext(*reader);
+ if (presenters[i]->Succeeded()) {
+ request_body->Set(kKeys[i], presenters[i]->Result());
+ some_succeeded = true;
+ break;
+ }
+ }
+ }
+ if (!some_succeeded)
+ request_body->SetString(keys::kRequestBodyErrorKey, "Unknown error.");
+}
+
+void WebRequestEventDetails::SetRequestHeaders(
+ const net::HttpRequestHeaders& request_headers) {
+ if (!(extra_info_spec_ & ExtraInfoSpec::REQUEST_HEADERS))
+ return;
+
+ base::ListValue* headers = new base::ListValue();
+ for (net::HttpRequestHeaders::Iterator it(request_headers); it.GetNext();)
+ headers->Append(helpers::CreateHeaderDictionary(it.name(), it.value()));
+ request_headers_.reset(headers);
+}
+
+void WebRequestEventDetails::SetAuthInfo(
+ const net::AuthChallengeInfo& auth_info) {
+ dict_.SetBoolean(keys::kIsProxyKey, auth_info.is_proxy);
+ if (!auth_info.scheme.empty())
+ dict_.SetString(keys::kSchemeKey, auth_info.scheme);
+ if (!auth_info.realm.empty())
+ dict_.SetString(keys::kRealmKey, auth_info.realm);
+ base::DictionaryValue* challenger = new base::DictionaryValue();
+ challenger->SetString(keys::kHostKey, auth_info.challenger.host());
+ challenger->SetInteger(keys::kPortKey, auth_info.challenger.port());
+ dict_.Set(keys::kChallengerKey, challenger);
+}
+
+void WebRequestEventDetails::SetResponseHeaders(
+ const net::URLRequest* request,
+ const net::HttpResponseHeaders* response_headers) {
+ if (!response_headers) {
+ // Not all URLRequestJobs specify response headers. E.g. URLRequestFTPJob,
+ // URLRequestFileJob and some redirects.
+ dict_.SetInteger(keys::kStatusCodeKey, request->GetResponseCode());
+ dict_.SetString(keys::kStatusLineKey, "");
+ } else {
+ dict_.SetInteger(keys::kStatusCodeKey, response_headers->response_code());
+ dict_.SetString(keys::kStatusLineKey, response_headers->GetStatusLine());
+ }
+
+ if (extra_info_spec_ & ExtraInfoSpec::RESPONSE_HEADERS) {
+ base::ListValue* headers = new base::ListValue();
+ if (response_headers) {
+ void* iter = nullptr;
+ std::string name;
+ std::string value;
+ while (response_headers->EnumerateHeaderLines(&iter, &name, &value))
+ headers->Append(helpers::CreateHeaderDictionary(name, value));
+ }
+ response_headers_.reset(headers);
+ }
+}
+
+void WebRequestEventDetails::SetResponseSource(const net::URLRequest* request) {
+ dict_.SetBoolean(keys::kFromCache, request->was_cached());
+ const std::string response_ip = request->GetSocketAddress().host();
+ if (!response_ip.empty())
+ dict_.SetString(keys::kIpKey, response_ip);
+}
+
+void WebRequestEventDetails::DetermineFrameIdOnUI() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ content::RenderFrameHost* rfh =
+ content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
+ dict_.SetInteger(keys::kFrameIdKey, ExtensionApiFrameIdMap::GetFrameId(rfh));
+ dict_.SetInteger(keys::kParentFrameIdKey,
+ ExtensionApiFrameIdMap::GetParentFrameId(rfh));
+}
+
+void WebRequestEventDetails::DetermineFrameIdOnIO(
+ const DeterminedFrameIdCallback& callback) {
+ scoped_ptr<WebRequestEventDetails> self(this);
+ ExtensionApiFrameIdMap::Get()->GetFrameIdOnIO(
+ render_process_id_, render_frame_id_,
+ base::Bind(&WebRequestEventDetails::OnDeterminedFrameId,
+ base::Unretained(this), base::Passed(&self), callback));
+}
+
+scoped_ptr<base::DictionaryValue> WebRequestEventDetails::GetFilteredDict(
+ int extra_info_spec) const {
+ scoped_ptr<base::DictionaryValue> result = dict_.CreateDeepCopy();
+ if ((extra_info_spec & ExtraInfoSpec::REQUEST_BODY) && request_body_)
+ result->Set(keys::kRequestBodyKey, request_body_->CreateDeepCopy());
+ if ((extra_info_spec & ExtraInfoSpec::REQUEST_HEADERS) && request_headers_)
+ result->Set(keys::kRequestHeadersKey, request_headers_->CreateDeepCopy());
+ if ((extra_info_spec & ExtraInfoSpec::RESPONSE_HEADERS) && response_headers_)
+ result->Set(keys::kResponseHeadersKey, response_headers_->CreateDeepCopy());
+ return result;
+}
+
+scoped_ptr<base::DictionaryValue> WebRequestEventDetails::GetAndClearDict() {
+ scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
+ dict_.Swap(result.get());
+ return result;
+}
+
+void WebRequestEventDetails::OnDeterminedFrameId(
+ scoped_ptr<WebRequestEventDetails> self,
+ const DeterminedFrameIdCallback& callback,
+ int extension_api_frame_id,
+ int extension_api_parent_frame_id) {
+ dict_.SetInteger(keys::kFrameIdKey, extension_api_frame_id);
+ dict_.SetInteger(keys::kParentFrameIdKey, extension_api_parent_frame_id);
+ callback.Run(std::move(self));
+}
+
+} // namespace extensions
diff --git a/extensions/browser/api/web_request/web_request_event_details.h b/extensions/browser/api/web_request/web_request_event_details.h
new file mode 100644
index 0000000..91e29bf
--- /dev/null
+++ b/extensions/browser/api/web_request/web_request_event_details.h
@@ -0,0 +1,144 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_WEB_REQUEST_WEB_REQUEST_EVENT_DETAILS_H_
+#define EXTENSIONS_BROWSER_API_WEB_REQUEST_WEB_REQUEST_EVENT_DETAILS_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+namespace net {
+class AuthChallengeInfo;
+class HttpRequestHeaders;
+class HttpResponseHeaders;
+class URLRequest;
+}
+
+namespace extensions {
+
+// This helper class is used to construct the details for a webRequest event
+// dictionary. Some keys are present on every event, others are only relevant
+// for a few events. And some keys must only be added to the event details if
+// requested at the registration of the event listener (in ExtraInfoSpec).
+// This class provides setters that are aware of these rules.
+//
+// Not all keys are managed by this class. Keys that do not require a special
+// treatment can be set using the generic SetBoolean / SetInteger / SetString
+// methods (e.g. to set "error", "message", "redirectUrl", "stage" or "tabId").
+//
+// This class should be constructed on the IO thread. It can safely be used on
+// other threads, as long as there is no concurrent access.
+class WebRequestEventDetails {
+ public:
+ using DeterminedFrameIdCallback =
+ base::Callback<void(scoped_ptr<WebRequestEventDetails>)>;
+
+ // Create a WebRequestEventDetails with the following keys:
+ // - method
+ // - requestId
+ // - tabId
+ // - timeStamp
+ // - type
+ // - url
+ WebRequestEventDetails(const net::URLRequest* request, int extra_info_spec);
+ ~WebRequestEventDetails();
+
+ // Sets the following key:
+ // - requestBody (on demand)
+ void SetRequestBody(const net::URLRequest* request);
+
+ // Sets the following key:
+ // - requestHeaders (on demand)
+ void SetRequestHeaders(const net::HttpRequestHeaders& request_headers);
+
+ // Sets the following keys:
+ // - challenger
+ // - isProxy
+ // - realm
+ // - scheme
+ void SetAuthInfo(const net::AuthChallengeInfo& auth_info);
+
+ // Sets the following keys:
+ // - responseHeaders (on demand)
+ // - statusCode
+ // - statusLine
+ void SetResponseHeaders(const net::URLRequest* request,
+ const net::HttpResponseHeaders* response_headers);
+
+ // Sets the following key:
+ // - fromCache
+ // - ip
+ void SetResponseSource(const net::URLRequest* request);
+
+ void SetBoolean(const std::string& key, bool value) {
+ dict_.SetBoolean(key, value);
+ }
+
+ void SetInteger(const std::string& key, int value) {
+ dict_.SetInteger(key, value);
+ }
+
+ void SetString(const std::string& key, const std::string& value) {
+ dict_.SetString(key, value);
+ }
+
+ // Sets the following keys using information from constructor.
+ // - frameId
+ // - parentFrameId
+ // This must be called from the UI thread.
+ void DetermineFrameIdOnUI();
+
+ // Sets the following keys using information from constructor.
+ // - frameId
+ // - parentFrameId
+ //
+ // This method is more expensive than DetermineFrameIdOnUI because it may
+ // involve thread hops, so prefer using DetermineFrameIdOnUI() when possible.
+ // The callback is called as soon as these IDs are determined, which can be
+ // synchronous or asynchronous.
+ //
+ // The caller must not use or delete this WebRequestEventDetails instance
+ // after calling this method. Ownership of this instance is transferred to
+ // |callback|.
+ void DetermineFrameIdOnIO(const DeterminedFrameIdCallback& callback);
+
+ // Create an event dictionary that contains all required keys, and also the
+ // extra keys as specified by the |extra_info_spec| filter.
+ // This can be called from any thread.
+ scoped_ptr<base::DictionaryValue> GetFilteredDict(int extra_info_spec) const;
+
+ // Get the internal dictionary, unfiltered. After this call, the internal
+ // dictionary is empty.
+ scoped_ptr<base::DictionaryValue> GetAndClearDict();
+
+ private:
+ void OnDeterminedFrameId(scoped_ptr<WebRequestEventDetails> self,
+ const DeterminedFrameIdCallback& callback,
+ int extension_api_frame_id,
+ int extension_api_parent_frame_id);
+
+ // The details that are always included in a webRequest event object.
+ base::DictionaryValue dict_;
+
+ // Extra event details: Only included when |extra_info_spec_| matches.
+ scoped_ptr<base::DictionaryValue> request_body_;
+ scoped_ptr<base::ListValue> request_headers_;
+ scoped_ptr<base::ListValue> response_headers_;
+
+ int extra_info_spec_;
+
+ // Used to determine the frameId and parentFrameId.
+ int render_process_id_;
+ int render_frame_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebRequestEventDetails);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_BROWSER_API_WEB_REQUEST_WEB_REQUEST_EVENT_DETAILS_H_
diff --git a/extensions/browser/api/web_request/web_request_event_router_delegate.cc b/extensions/browser/api/web_request/web_request_event_router_delegate.cc
index 794e582..97fd3de 100644
--- a/extensions/browser/api/web_request/web_request_event_router_delegate.cc
+++ b/extensions/browser/api/web_request/web_request_event_router_delegate.cc
@@ -5,6 +5,7 @@
#include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
#include "extensions/browser/api/web_request/web_request_api_constants.h"
+#include "extensions/browser/api/web_request/web_request_event_details.h"
namespace keys = extension_web_request_api_constants;
@@ -17,7 +18,7 @@ WebRequestEventRouterDelegate::~WebRequestEventRouterDelegate() {
}
void WebRequestEventRouterDelegate::ExtractExtraRequestDetails(
const net::URLRequest* request,
- base::DictionaryValue* out) {
+ WebRequestEventDetails* out) {
out->SetInteger(keys::kTabIdKey, -1);
}
diff --git a/extensions/browser/api/web_request/web_request_event_router_delegate.h b/extensions/browser/api/web_request/web_request_event_router_delegate.h
index 1bacf6e..35f3dbb 100644
--- a/extensions/browser/api/web_request/web_request_event_router_delegate.h
+++ b/extensions/browser/api/web_request/web_request_event_router_delegate.h
@@ -8,13 +8,13 @@
#include <string>
#include "base/macros.h"
-#include "base/values.h"
+#include "base/memory/scoped_ptr.h"
class GURL;
namespace base {
class DictionaryValue;
-} // namspace base
+} // namespace base
namespace content {
class BrowserContext;
@@ -22,10 +22,12 @@ class BrowserContext;
namespace net {
class URLRequest;
-} // namspace net
+} // namespace net
namespace extensions {
+class WebRequestEventDetails;
+
// A delegate class of WebRequestApi that are not a part of chrome.
class WebRequestEventRouterDelegate {
public:
@@ -35,7 +37,7 @@ class WebRequestEventRouterDelegate {
// Looks up the tab and window ID for a given request.
// Called on the IO thread.
virtual void ExtractExtraRequestDetails(const net::URLRequest* request,
- base::DictionaryValue* out);
+ WebRequestEventDetails* out);
// Called to check extra parameters (e.g., tab_id, windown_id) when filtering
// event listeners.
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi
index b49e007..1900afd 100644
--- a/extensions/extensions.gypi
+++ b/extensions/extensions.gypi
@@ -498,6 +498,8 @@
'browser/api/web_request/web_request_api_constants.h',
'browser/api/web_request/web_request_api_helpers.cc',
'browser/api/web_request/web_request_api_helpers.h',
+ 'browser/api/web_request/web_request_event_details.cc',
+ 'browser/api/web_request/web_request_event_details.h',
'browser/api/web_request/web_request_event_router_delegate.cc',
'browser/api/web_request/web_request_event_router_delegate.h',
'browser/api/web_request/web_request_permissions.cc',