diff options
Diffstat (limited to 'chrome/browser/extensions')
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_; } |