summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r--chrome/browser/extensions/extension_webrequest_api.cc116
-rw-r--r--chrome/browser/extensions/extension_webrequest_api.h29
-rw-r--r--chrome/browser/extensions/extension_webrequest_api_constants.cc3
-rw-r--r--chrome/browser/extensions/extension_webrequest_api_constants.h3
-rw-r--r--chrome/browser/extensions/extension_webrequest_apitest.cc11
5 files changed, 143 insertions, 19 deletions
diff --git a/chrome/browser/extensions/extension_webrequest_api.cc b/chrome/browser/extensions/extension_webrequest_api.cc
index 208554a..a225112 100644
--- a/chrome/browser/extensions/extension_webrequest_api.cc
+++ b/chrome/browser/extensions/extension_webrequest_api.cc
@@ -338,6 +338,15 @@ struct ExtensionWebRequestEventRouter::BlockedRequest {
// OnHeadersReceived.
scoped_refptr<net::HttpResponseHeaders>* override_response_headers;
+ // If non-empty, this contains the auth credentials that may be filled in.
+ // Only valid for OnAuthRequired.
+ net::AuthCredentials* auth_credentials;
+
+ // The callback to invoke for auth. If |auth_callback.is_null()| is false,
+ // |callback| must be NULL.
+ // Only valid for OnAuthRequired.
+ net::NetworkDelegate::AuthCallback auth_callback;
+
// Time the request was paused. Used for logging purposes.
base::Time blocking_time;
@@ -352,7 +361,8 @@ struct ExtensionWebRequestEventRouter::BlockedRequest {
callback(NULL),
new_url(NULL),
request_headers(NULL),
- override_response_headers(NULL) {}
+ override_response_headers(NULL),
+ auth_credentials(NULL) {}
};
bool ExtensionWebRequestEventRouter::RequestFilter::InitFromValue(
@@ -636,23 +646,28 @@ int ExtensionWebRequestEventRouter::OnHeadersReceived(
return net::OK;
}
-void ExtensionWebRequestEventRouter::OnAuthRequired(
+net::NetworkDelegate::AuthRequiredResponse
+ExtensionWebRequestEventRouter::OnAuthRequired(
void* profile,
ExtensionInfoMap* extension_info_map,
net::URLRequest* request,
- const net::AuthChallengeInfo& auth_info) {
+ const net::AuthChallengeInfo& auth_info,
+ const net::NetworkDelegate::AuthCallback& callback,
+ net::AuthCredentials* credentials) {
+ // No profile means that this is for authentication challenges in the
+ // system context. Skip in that case.
if (!profile)
- return;
+ return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
if (!HasWebRequestScheme(request->url()))
- return;
+ return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
int extra_info_spec = 0;
std::vector<const EventListener*> listeners =
GetMatchingListeners(profile, extension_info_map,
keys::kOnAuthRequired, request, &extra_info_spec);
if (listeners.empty())
- return;
+ return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
ListValue args;
DictionaryValue* dict = new DictionaryValue();
@@ -673,7 +688,14 @@ void ExtensionWebRequestEventRouter::OnAuthRequired(
}
args.Append(dict);
- DispatchEvent(profile, request, listeners, args);
+ if (DispatchEvent(profile, request, listeners, args)) {
+ blocked_requests_[request->identifier()].event = kOnAuthRequired;
+ blocked_requests_[request->identifier()].auth_callback = callback;
+ blocked_requests_[request->identifier()].auth_credentials = credentials;
+ blocked_requests_[request->identifier()].net_log = &request->net_log();
+ return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING;
+ }
+ return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
}
void ExtensionWebRequestEventRouter::OnBeforeRedirect(
@@ -1147,6 +1169,9 @@ linked_ptr<ExtensionWebRequestEventRouter::EventResponseDelta>
}
}
+ if (blocked_request->event == kOnAuthRequired)
+ result->auth_credentials.swap(response->auth_credentials);
+
return result;
}
@@ -1191,7 +1216,6 @@ void ExtensionWebRequestEventRouter::MergeOnBeforeSendHeadersResponses(
// We assume here that the deltas are sorted in decreasing extension
// precedence (i.e. decreasing extension installation time).
for (delta = deltas.begin(); delta != deltas.end(); ++delta) {
-
if ((*delta)->modified_request_headers.IsEmpty() &&
(*delta)->deleted_request_headers.empty()) {
continue;
@@ -1314,6 +1338,37 @@ void ExtensionWebRequestEventRouter::MergeOnHeadersReceivedResponses(
}
}
+bool ExtensionWebRequestEventRouter::MergeOnAuthRequiredResponses(
+ BlockedRequest* request,
+ std::list<std::string>* conflicting_extensions) const {
+ CHECK(request);
+ CHECK(request->auth_credentials);
+ bool credentials_set = false;
+
+ const EventResponseDeltas& deltas = request->response_deltas;
+ for (EventResponseDeltas::const_iterator delta = deltas.begin();
+ delta != deltas.end();
+ ++delta) {
+ if (!(*delta)->auth_credentials.get())
+ continue;
+ if (credentials_set) {
+ conflicting_extensions->push_back((*delta)->extension_id);
+ request->net_log->AddEvent(
+ net::NetLog::TYPE_CHROME_EXTENSION_IGNORED_DUE_TO_CONFLICT,
+ make_scoped_refptr(
+ new NetLogExtensionIdParameter((*delta)->extension_id)));
+ } else {
+ request->net_log->AddEvent(
+ net::NetLog::TYPE_CHROME_EXTENSION_PROVIDE_AUTH_CREDENTIALS,
+ make_scoped_refptr(
+ new NetLogExtensionIdParameter((*delta)->extension_id)));
+ *request->auth_credentials = *(*delta)->auth_credentials;
+ credentials_set = true;
+ }
+ }
+ return credentials_set;
+}
+
void ExtensionWebRequestEventRouter::DecrementBlockCount(
void* profile,
const std::string& extension_id,
@@ -1344,14 +1399,14 @@ void ExtensionWebRequestEventRouter::DecrementBlockCount(
if (num_handlers_blocking == 0) {
request_time_tracker_->IncrementTotalBlockTime(request_id, block_time);
- EventResponseDeltas::iterator i;
EventResponseDeltas& deltas = blocked_request.response_deltas;
-
bool canceled = false;
- for (i = deltas.begin(); i != deltas.end(); ++i) {
+ bool credentials_set = false;
+ for (EventResponseDeltas::const_iterator i = deltas.begin();
+ i != deltas.end(); ++i) {
if ((*i)->cancel) {
- canceled = true;
- blocked_request.net_log->AddEvent(
+ canceled = true;
+ blocked_request.net_log->AddEvent(
net::NetLog::TYPE_CHROME_EXTENSION_ABORTED_REQUEST,
make_scoped_refptr(
new NetLogExtensionIdParameter((*i)->extension_id)));
@@ -1364,7 +1419,8 @@ void ExtensionWebRequestEventRouter::DecrementBlockCount(
if (blocked_request.event == kOnBeforeRequest) {
CHECK(blocked_request.callback);
- MergeOnBeforeRequestResponses(&blocked_request, &conflicting_extensions);
+ MergeOnBeforeRequestResponses(&blocked_request,
+ &conflicting_extensions);
} else if (blocked_request.event == kOnBeforeSendHeaders) {
CHECK(blocked_request.callback);
MergeOnBeforeSendHeadersResponses(&blocked_request,
@@ -1373,6 +1429,12 @@ void ExtensionWebRequestEventRouter::DecrementBlockCount(
CHECK(blocked_request.callback);
MergeOnHeadersReceivedResponses(&blocked_request,
&conflicting_extensions);
+ } else if (blocked_request.event == kOnAuthRequired) {
+ CHECK(!blocked_request.callback);
+ CHECK(!blocked_request.auth_callback.is_null());
+ credentials_set = MergeOnAuthRequiredResponses(
+ &blocked_request,
+ &conflicting_extensions);
} else {
NOTREACHED();
}
@@ -1403,6 +1465,18 @@ void ExtensionWebRequestEventRouter::DecrementBlockCount(
// might trigger the next event.
blocked_requests_.erase(request_id);
callback->Run(rv);
+ } else if (!blocked_request.auth_callback.is_null()) {
+ net::NetworkDelegate::AuthRequiredResponse response =
+ net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION;
+ if (canceled) {
+ response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH;
+ } else if (credentials_set) {
+ response = net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH;
+ }
+ net::NetworkDelegate::AuthCallback callback =
+ blocked_request.auth_callback;
+ blocked_requests_.erase(request_id);
+ callback.Run(response);
} else {
blocked_requests_.erase(request_id);
}
@@ -1575,6 +1649,20 @@ bool WebRequestEventHandled::RunImpl() {
response_headers_string += '\n';
response->response_headers_string.swap(response_headers_string);
}
+
+ if (value->HasKey(keys::kAuthCredentialsKey)) {
+ DictionaryValue* credentials_value = NULL;
+ EXTENSION_FUNCTION_VALIDATE(value->GetDictionary(
+ keys::kAuthCredentialsKey,
+ &credentials_value));
+ response->auth_credentials.reset(new net::AuthCredentials());
+ EXTENSION_FUNCTION_VALIDATE(
+ credentials_value->GetString(keys::kUsernameKey,
+ &response->auth_credentials->username));
+ EXTENSION_FUNCTION_VALIDATE(
+ credentials_value->GetString(keys::kPasswordKey,
+ &response->auth_credentials->password));
+ }
}
ExtensionWebRequestEventRouter::GetInstance()->OnEventHandled(
diff --git a/chrome/browser/extensions/extension_webrequest_api.h b/chrome/browser/extensions/extension_webrequest_api.h
index 268a4c2..5196818 100644
--- a/chrome/browser/extensions/extension_webrequest_api.h
+++ b/chrome/browser/extensions/extension_webrequest_api.h
@@ -18,6 +18,7 @@
#include "chrome/common/extensions/url_pattern_set.h"
#include "ipc/ipc_message.h"
#include "net/base/completion_callback.h"
+#include "net/base/network_delegate.h"
#include "net/http/http_request_headers.h"
#include "webkit/glue/resource_type.h"
@@ -32,6 +33,7 @@ class StringValue;
}
namespace net {
+class AuthCredentials;
class AuthChallengeInfo;
class HostPortPair;
class HttpRequestHeaders;
@@ -104,6 +106,7 @@ class ExtensionWebRequestEventRouter {
scoped_ptr<net::HttpRequestHeaders> request_headers;
// Contains all header lines after the status line, lines are \n separated.
std::string response_headers_string;
+ scoped_ptr<net::AuthCredentials> auth_credentials;
EventResponse(const std::string& extension_id,
const base::Time& extension_install_time);
@@ -135,6 +138,9 @@ class ExtensionWebRequestEventRouter {
// Complete set of response headers that will replace the original ones.
scoped_refptr<net::HttpResponseHeaders> new_response_headers;
+ // Authentication Credentials to use.
+ scoped_ptr<net::AuthCredentials> auth_credentials;
+
EventResponseDelta(const std::string& extension_id,
const base::Time& extension_install_time);
~EventResponseDelta();
@@ -192,11 +198,18 @@ class ExtensionWebRequestEventRouter {
net::HttpResponseHeaders* original_response_headers,
scoped_refptr<net::HttpResponseHeaders>* override_response_headers);
- // Dispatches the onAuthRequired event.
- void OnAuthRequired(void* profile,
+ // Dispatches the OnAuthRequired event to any extensions whose filters match
+ // the given request. If the listener is not registered as "blocking", then
+ // AUTH_REQUIRED_RESPONSE_OK is returned. Otherwise,
+ // AUTH_REQUIRED_RESPONSE_IO_PENDING is returned and |callback| will be
+ // invoked later.
+ net::NetworkDelegate::AuthRequiredResponse OnAuthRequired(
+ void* profile,
ExtensionInfoMap* extension_info_map,
net::URLRequest* request,
- const net::AuthChallengeInfo& auth_info);
+ const net::AuthChallengeInfo& auth_info,
+ const net::NetworkDelegate::AuthCallback& callback,
+ net::AuthCredentials* credentials);
// Dispatches the onBeforeRedirect event. This is fired for HTTP(s) requests
// only.
@@ -347,6 +360,16 @@ class ExtensionWebRequestEventRouter {
BlockedRequest* request,
std::list<std::string>* conflicting_extensions) const;
+ // Merge the responses of blocked onAuthRequired handlers. The first
+ // registered listener that supplies authentication credentials in a response,
+ // if any, will have its authentication credentials used. |request| must be
+ // non-NULL, and contain |deltas| that are sorted in decreasing order of
+ // precedence.
+ // Returns whether authentication credentials are set.
+ bool MergeOnAuthRequiredResponses(
+ BlockedRequest* request,
+ std::list<std::string>* conflicting_extensions) const;
+
// A map for each profile that maps an event name to a set of extensions that
// are listening to that event.
ListenerMap listeners_;
diff --git a/chrome/browser/extensions/extension_webrequest_api_constants.cc b/chrome/browser/extensions/extension_webrequest_api_constants.cc
index 63a980a..82e5fb7 100644
--- a/chrome/browser/extensions/extension_webrequest_api_constants.cc
+++ b/chrome/browser/extensions/extension_webrequest_api_constants.cc
@@ -29,6 +29,9 @@ const char kHeaderValueKey[] = "value";
const char kIsProxyKey[] = "isProxy";
const char kSchemeKey[] = "scheme";
const char kRealmKey[] = "realm";
+const char kAuthCredentialsKey[] = "authCredentials";
+const char kUsernameKey[] = "username";
+const char kPasswordKey[] = "password";
const char kOnBeforeRedirect[] = "experimental.webRequest.onBeforeRedirect";
const char kOnBeforeRequest[] = "experimental.webRequest.onBeforeRequest";
diff --git a/chrome/browser/extensions/extension_webrequest_api_constants.h b/chrome/browser/extensions/extension_webrequest_api_constants.h
index 4e3318f..e58d17e 100644
--- a/chrome/browser/extensions/extension_webrequest_api_constants.h
+++ b/chrome/browser/extensions/extension_webrequest_api_constants.h
@@ -35,6 +35,9 @@ extern const char kHeaderValueKey[];
extern const char kIsProxyKey[];
extern const char kSchemeKey[];
extern const char kRealmKey[];
+extern const char kAuthCredentialsKey[];
+extern const char kUsernameKey[];
+extern const char kPasswordKey[];
// Events.
extern const char kOnAuthRequired[];
diff --git a/chrome/browser/extensions/extension_webrequest_apitest.cc b/chrome/browser/extensions/extension_webrequest_apitest.cc
index 5ca1208..204468b 100644
--- a/chrome/browser/extensions/extension_webrequest_apitest.cc
+++ b/chrome/browser/extensions/extension_webrequest_apitest.cc
@@ -69,10 +69,17 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestComplex) {
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
- // Needed for the auth tests.
+ ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_complex.html")) <<
+ message_;
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestAuthRequired) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+
CancelLoginDialog login_dialog_helper;
- ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_complex.html")) <<
+ ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_auth_required.html")) <<
message_;
}