diff options
-rw-r--r-- | chrome/browser/net/chrome_network_delegate.cc | 8 | ||||
-rw-r--r-- | chrome/browser/net/chrome_network_delegate.h | 7 | ||||
-rw-r--r-- | chrome_frame/test/net/fake_external_tab.cc | 9 | ||||
-rw-r--r-- | net/base/auth.cc | 6 | ||||
-rw-r--r-- | net/base/auth.h | 23 | ||||
-rw-r--r-- | net/base/network_delegate.cc | 9 | ||||
-rw-r--r-- | net/base/network_delegate.h | 47 | ||||
-rw-r--r-- | net/proxy/network_delegate_error_observer_unittest.cc | 13 | ||||
-rw-r--r-- | net/url_request/url_request.cc | 71 | ||||
-rw-r--r-- | net/url_request/url_request.h | 10 | ||||
-rw-r--r-- | net/url_request/url_request_ftp_job.cc | 18 | ||||
-rw-r--r-- | net/url_request/url_request_test_util.cc | 60 | ||||
-rw-r--r-- | net/url_request/url_request_test_util.h | 29 | ||||
-rw-r--r-- | net/url_request/url_request_unittest.cc | 262 |
14 files changed, 490 insertions, 82 deletions
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc index 721ff38..cb486a8 100644 --- a/chrome/browser/net/chrome_network_delegate.cc +++ b/chrome/browser/net/chrome_network_delegate.cc @@ -160,9 +160,13 @@ void ChromeNetworkDelegate::OnPACScriptError(int line_number, event_router_.get(), profile_, line_number, error); } -void ChromeNetworkDelegate::OnAuthRequired( +net::NetworkDelegate::AuthRequiredResponse +ChromeNetworkDelegate::OnAuthRequired( net::URLRequest* request, - const net::AuthChallengeInfo& auth_info) { + const net::AuthChallengeInfo& auth_info, + const AuthCallback& callback, + net::AuthCredentials* credentials) { ExtensionWebRequestEventRouter::GetInstance()->OnAuthRequired( profile_, extension_info_map_.get(), request, auth_info); + return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION; } diff --git a/chrome/browser/net/chrome_network_delegate.h b/chrome/browser/net/chrome_network_delegate.h index 1a76935..3d0baaa 100644 --- a/chrome/browser/net/chrome_network_delegate.h +++ b/chrome/browser/net/chrome_network_delegate.h @@ -63,8 +63,11 @@ class ChromeNetworkDelegate : public net::NetworkDelegate { virtual void OnURLRequestDestroyed(net::URLRequest* request) OVERRIDE; virtual void OnPACScriptError(int line_number, const string16& error) OVERRIDE; - virtual void OnAuthRequired(net::URLRequest* request, - const net::AuthChallengeInfo& auth_info) OVERRIDE; + virtual net::NetworkDelegate::AuthRequiredResponse OnAuthRequired( + net::URLRequest* request, + const net::AuthChallengeInfo& auth_info, + const AuthCallback& callback, + net::AuthCredentials* credentials) OVERRIDE; scoped_refptr<ExtensionEventRouterForwarder> event_router_; void* profile_; diff --git a/chrome_frame/test/net/fake_external_tab.cc b/chrome_frame/test/net/fake_external_tab.cc index 626c549..04b39ba 100644 --- a/chrome_frame/test/net/fake_external_tab.cc +++ b/chrome_frame/test/net/fake_external_tab.cc @@ -522,6 +522,15 @@ void FilterDisabledTests() { // Not supported in ChromeFrame as we use IE's network stack. "URLRequestTest.NetworkDelegateProxyError", + + // URLRequestAutomationJob needs to support NeedsAuth. + // http://crbug.com/98446 + "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredSyncNoAction", + "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredSyncSetAuth", + "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredSyncCancel", + "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredAsyncNoAction", + "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredAsyncSetAuth", + "URLRequestTestHTTP.NetworkDelegateOnAuthRequiredAsyncCancel", }; std::string filter("-"); // All following filters will be negative. diff --git a/net/base/auth.cc b/net/base/auth.cc index f60c8ed..104400f 100644 --- a/net/base/auth.cc +++ b/net/base/auth.cc @@ -25,4 +25,10 @@ AuthData::AuthData() : state(AUTH_STATE_NEED_AUTH) { AuthData::~AuthData() { } +AuthCredentials::AuthCredentials() { +} + +AuthCredentials::~AuthCredentials() { +} + } // namespace net diff --git a/net/base/auth.h b/net/base/auth.h index 51f8db9..386adad 100644 --- a/net/base/auth.h +++ b/net/base/auth.h @@ -43,6 +43,26 @@ class NET_EXPORT AuthChallengeInfo : ~AuthChallengeInfo(); }; +// Authentication Credentials for an authentication credentials. +class NET_EXPORT AuthCredentials { + public: + AuthCredentials(); + ~AuthCredentials(); + + // The username to provide, possibly empty. This should be ASCII only to + // minimize compatibility problems, but arbitrary UTF-16 strings are allowed + // and will be attempted. + string16 username; + + // The password to provide, possibly empty. This should be ASCII only to + // minimize compatibility problems, but arbitrary UTF-16 strings are allowed + // and will be attempted. + string16 password; + + // Intentionally allowing the implicit copy constructor and assignment + // operators. +}; + // Authentication structures enum AuthState { AUTH_STATE_DONT_NEED_AUTH, @@ -54,8 +74,7 @@ enum AuthState { class AuthData : public base::RefCountedThreadSafe<AuthData> { public: AuthState state; // whether we need, have, or gave up on authentication. - string16 username; // the username supplied to us for auth. - string16 password; // the password supplied to us for auth. + AuthCredentials credentials; // The credentials to use for auth. // We wouldn't instantiate this class if we didn't need authentication. AuthData(); diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc index cb9c06d..c0644f1 100644 --- a/net/base/network_delegate.cc +++ b/net/base/network_delegate.cc @@ -69,10 +69,13 @@ void NetworkDelegate::NotifyPACScriptError(int line_number, OnPACScriptError(line_number, error); } -void NetworkDelegate::NotifyAuthRequired(URLRequest* request, - const AuthChallengeInfo& auth_info) { +NetworkDelegate::AuthRequiredResponse NetworkDelegate::NotifyAuthRequired( + URLRequest* request, + const AuthChallengeInfo& auth_info, + const AuthCallback& callback, + AuthCredentials* credentials) { DCHECK(CalledOnValidThread()); - OnAuthRequired(request, auth_info); + return OnAuthRequired(request, auth_info, callback, credentials); } } // namespace net diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h index 3478cb1..66cd131 100644 --- a/net/base/network_delegate.h +++ b/net/base/network_delegate.h @@ -6,8 +6,10 @@ #define NET_BASE_NETWORK_DELEGATE_H_ #pragma once +#include "base/callback.h" #include "base/string16.h" #include "base/threading/non_thread_safe.h" +#include "net/base/auth.h" #include "net/base/completion_callback.h" class GURL; @@ -24,7 +26,6 @@ namespace net { // NOTE: It is not okay to add any compile-time dependencies on symbols outside // of net/base here, because we have a net_base library. Forward declarations // are ok. -class AuthChallengeInfo; class HostPortPair; class HttpRequestHeaders; class URLRequest; @@ -32,6 +33,17 @@ class URLRequestJob; class NetworkDelegate : public base::NonThreadSafe { public: + // AuthRequiredResponse indicates how a NetworkDelegate handles an + // OnAuthRequired call. It's placed in this file to prevent url_request.h + // from having to include network_delegate.h. + enum AuthRequiredResponse { + AUTH_REQUIRED_RESPONSE_NO_ACTION, + AUTH_REQUIRED_RESPONSE_SET_AUTH, + AUTH_REQUIRED_RESPONSE_CANCEL_AUTH, + AUTH_REQUIRED_RESPONSE_IO_PENDING, + }; + typedef base::Callback<void(AuthRequiredResponse)> AuthCallback; + virtual ~NetworkDelegate() {} // Notification interface called by the network stack. Note that these @@ -53,8 +65,10 @@ class NetworkDelegate : public base::NonThreadSafe { void NotifyCompleted(URLRequest* request); void NotifyURLRequestDestroyed(URLRequest* request); void NotifyPACScriptError(int line_number, const string16& error); - void NotifyAuthRequired(URLRequest* request, - const AuthChallengeInfo& auth_info); + AuthRequiredResponse NotifyAuthRequired(URLRequest* request, + const AuthChallengeInfo& auth_info, + const AuthCallback& callback, + AuthCredentials* credentials); private: // This is the interface for subclasses of NetworkDelegate to implement. This @@ -72,7 +86,7 @@ class NetworkDelegate : public base::NonThreadSafe { // Called right before the HTTP headers are sent. Allows the delegate to // read/write |headers| before they get sent out. |callback| and |headers| are - // valid only until OnHttpTransactionDestroyed is called for this request. + // valid only until OnURLRequestDestroyed is called for this request. // Returns a net status code. virtual int OnBeforeSendHeaders(URLRequest* request, OldCompletionCallback* callback, @@ -103,9 +117,28 @@ class NetworkDelegate : public base::NonThreadSafe { // Corresponds to ProxyResolverJSBindings::OnError. virtual void OnPACScriptError(int line_number, const string16& error) = 0; - // Corresponds to URLRequest::Delegate::OnAuthRequired. - virtual void OnAuthRequired(URLRequest* reqest, - const AuthChallengeInfo& auth_info) = 0; + // Called when a request receives an authentication challenge + // specified by |auth_info|, and is unable to respond using cached + // credentials. |callback| and |credentials| must be non-NULL, and must + // be valid until OnURLRequestDestroyed is called for |request|. + // + // The following return values are allowed: + // - AUTH_REQUIRED_RESPONSE_NO_ACTION: |auth_info| is observed, but + // no action is being taken on it. + // - AUTH_REQUIRED_RESPONSE_SET_AUTH: |credentials| is filled in with + // a username and password, which should be used in a response to + // |auth_info|. + // - AUTH_REQUIRED_RESPONSE_CANCEL_AUTH: The authentication challenge + // should not be attempted. + // - AUTH_REQUIRED_RESPONSE_IO_PENDING: The action will be decided + // asynchronously. |callback| will be invoked when the decision is made, + // and one of the other AuthRequiredResponse values will be passed in with + // the same semantics as described above. + virtual AuthRequiredResponse OnAuthRequired( + URLRequest* request, + const AuthChallengeInfo& auth_info, + const AuthCallback& callback, + AuthCredentials* credentials) = 0; }; } // namespace net diff --git a/net/proxy/network_delegate_error_observer_unittest.cc b/net/proxy/network_delegate_error_observer_unittest.cc index 7a98870..35703d9 100644 --- a/net/proxy/network_delegate_error_observer_unittest.cc +++ b/net/proxy/network_delegate_error_observer_unittest.cc @@ -28,12 +28,12 @@ class TestNetworkDelegate : public net::NetworkDelegate { virtual int OnBeforeURLRequest(URLRequest* request, OldCompletionCallback* callback, GURL* new_url) OVERRIDE { - return net::OK; + return OK; } virtual int OnBeforeSendHeaders(URLRequest* request, OldCompletionCallback* callback, HttpRequestHeaders* headers) OVERRIDE { - return net::OK; + return OK; } virtual void OnSendHeaders(URLRequest* request, const HttpRequestHeaders& headers) OVERRIDE {} @@ -49,8 +49,13 @@ class TestNetworkDelegate : public net::NetworkDelegate { const string16& error) OVERRIDE { got_pac_error_ = true; } - virtual void OnAuthRequired(URLRequest* request, - const AuthChallengeInfo& auth_info) OVERRIDE {} + virtual AuthRequiredResponse OnAuthRequired( + URLRequest* request, + const AuthChallengeInfo& auth_info, + const AuthCallback& callback, + AuthCredentials* credentials) OVERRIDE { + return AUTH_REQUIRED_RESPONSE_NO_ACTION; + } bool got_pac_error_; }; diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index 41d2362..acc085e 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc @@ -4,11 +4,14 @@ #include "net/url_request/url_request.h" +#include "base/bind.h" +#include "base/callback.h" #include "base/compiler_specific.h" #include "base/memory/singleton.h" #include "base/message_loop.h" #include "base/metrics/stats_counters.h" #include "base/synchronization/lock.h" +#include "net/base/auth.h" #include "net/base/host_port_pair.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" @@ -430,8 +433,7 @@ void URLRequest::BeforeRequestComplete(int error) { DCHECK(!job_); DCHECK_NE(ERR_IO_PENDING, error); - if (blocked_on_delegate_) - SetUnblockedOnDelegate(); + SetUnblockedOnDelegate(); if (error != OK) { net_log_.AddEvent(NetLog::TYPE_CANCELLED, make_scoped_refptr(new NetLogStringParameter("source", "delegate"))); @@ -766,20 +768,57 @@ void URLRequest::SetUserData(const void* key, UserData* data) { } void URLRequest::NotifyAuthRequired(AuthChallengeInfo* auth_info) { - // TODO(battre): We could simulate a redirection there as follows: - // if (context_ && context_->network_delegate()) { - // // We simulate a redirection. - // context_->network_delegate()->NotifyBeforeRedirect(this, url()); - //} - // This fixes URLRequestTestHTTP.BasicAuth but not - // URLRequestTestHTTP.BasicAuthWithCookies. In both cases we observe a - // call sequence of OnBeforeSendHeaders -> OnSendHeaders -> - // OnBeforeSendHeaders. - if (context_ && context_->network_delegate()) - context_->network_delegate()->NotifyAuthRequired(this, *auth_info); + NetworkDelegate::AuthRequiredResponse rv = + NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION; + auth_info_ = auth_info; + if (context_ && context_->network_delegate()) { + rv = context_->network_delegate()->NotifyAuthRequired( + this, + *auth_info, + base::Bind(&URLRequest::NotifyAuthRequiredComplete, + base::Unretained(this)), + &auth_credentials_); + } - if (delegate_) - delegate_->OnAuthRequired(this, auth_info); + if (rv == NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING) { + SetBlockedOnDelegate(); + } else { + NotifyAuthRequiredComplete(rv); + } +} + +void URLRequest::NotifyAuthRequiredComplete( + NetworkDelegate::AuthRequiredResponse result) { + SetUnblockedOnDelegate(); + + // NotifyAuthRequired may be called multiple times, such as + // when an authentication attempt fails. Clear out the data + // so it can be reset on another round. + AuthCredentials credentials = auth_credentials_; + auth_credentials_ = AuthCredentials(); + scoped_refptr<AuthChallengeInfo> auth_info; + auth_info.swap(auth_info_); + + switch (result) { + case NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION: + // Defer to the URLRequest::Delegate, since the NetworkDelegate + // didn't take an action. + if (delegate_) + delegate_->OnAuthRequired(this, auth_info.get()); + break; + + case NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH: + SetAuth(credentials.username, credentials.password); + break; + + case NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH: + CancelAuth(); + break; + + case NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING: + NOTREACHED(); + break; + } } void URLRequest::NotifyCertificateRequested( @@ -837,6 +876,8 @@ void URLRequest::SetBlockedOnDelegate() { } void URLRequest::SetUnblockedOnDelegate() { + if (!blocked_on_delegate_) + return; blocked_on_delegate_ = false; load_state_param_.clear(); net_log_.EndEvent(NetLog::TYPE_URL_REQUEST_BLOCKED_ON_DELEGATE, NULL); diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h index 1888ba0..a66c012 100644 --- a/net/url_request/url_request.h +++ b/net/url_request/url_request.h @@ -17,10 +17,12 @@ #include "base/string16.h" #include "base/threading/non_thread_safe.h" #include "googleurl/src/gurl.h" +#include "net/base/auth.h" #include "net/base/completion_callback.h" #include "net/base/load_states.h" #include "net/base/net_export.h" #include "net/base/net_log.h" +#include "net/base/network_delegate.h" #include "net/base/request_priority.h" #include "net/http/http_request_headers.h" #include "net/http/http_response_info.h" @@ -716,6 +718,7 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe) { // |delegate_| is not NULL. See URLRequest::Delegate for the meaning // of these functions. void NotifyAuthRequired(AuthChallengeInfo* auth_info); + void NotifyAuthRequiredComplete(NetworkDelegate::AuthRequiredResponse result); void NotifyCertificateRequested(SSLCertRequestInfo* cert_request_info); void NotifySSLCertificateError(const SSLInfo& ssl_info, bool is_hsts_host); @@ -808,6 +811,13 @@ class NET_EXPORT URLRequest : NON_EXPORTED_BASE(public base::NonThreadSafe) { // TODO(battre): Remove this. http://crbug.com/89049 bool has_notified_completion_; + // Authentication data used by the NetworkDelegate for this request, + // if one is present. |auth_credentials_| may be filled in when calling + // |NotifyAuthRequired| on the NetworkDelegate. |auth_info_| holds + // the authentication challenge being handled by |NotifyAuthRequired|. + AuthCredentials auth_credentials_; + scoped_refptr<AuthChallengeInfo> auth_info_; + DISALLOW_COPY_AND_ASSIGN(URLRequest); }; diff --git a/net/url_request/url_request_ftp_job.cc b/net/url_request/url_request_ftp_job.cc index 1f04548..b14d88d 100644 --- a/net/url_request/url_request_ftp_job.cc +++ b/net/url_request/url_request_ftp_job.cc @@ -106,9 +106,10 @@ void URLRequestFtpJob::OnStartCompleted(int result) { } else if (transaction_->GetResponseInfo()->needs_auth) { GURL origin = request_->url().GetOrigin(); if (server_auth_ && server_auth_->state == AUTH_STATE_HAVE_AUTH) { - request_->context()->ftp_auth_cache()->Remove(origin, - server_auth_->username, - server_auth_->password); + request_->context()->ftp_auth_cache()->Remove( + origin, + server_auth_->credentials.username, + server_auth_->credentials.password); } else if (!server_auth_) { server_auth_ = new AuthData(); } @@ -119,7 +120,8 @@ void URLRequestFtpJob::OnStartCompleted(int result) { if (cached_auth) { // Retry using cached auth data. - SetAuth(cached_auth->username, cached_auth->password); + SetAuth(cached_auth->username, + cached_auth->password); } else { // Prompt for a username/password. NotifyHeadersComplete(); @@ -149,8 +151,8 @@ void URLRequestFtpJob::RestartTransactionWithAuth() { // be notifying our consumer asynchronously via OnStartCompleted. SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); - int rv = transaction_->RestartWithAuth(server_auth_->username, - server_auth_->password, + int rv = transaction_->RestartWithAuth(server_auth_->credentials.username, + server_auth_->credentials.password, &start_callback_); if (rv == ERR_IO_PENDING) return; @@ -205,8 +207,8 @@ void URLRequestFtpJob::SetAuth(const string16& username, const string16& password) { DCHECK(NeedsAuth()); server_auth_->state = AUTH_STATE_HAVE_AUTH; - server_auth_->username = username; - server_auth_->password = password; + server_auth_->credentials.username = username; + server_auth_->credentials.password = password; request_->context()->ftp_auth_cache()->Add(request_->url().GetOrigin(), username, password); diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc index 259af7c..6d4f167 100644 --- a/net/url_request/url_request_test_util.cc +++ b/net/url_request/url_request_test_util.cc @@ -21,12 +21,13 @@ namespace { const int kStageBeforeURLRequest = 1 << 0; const int kStageBeforeSendHeaders = 1 << 1; const int kStageSendHeaders = 1 << 2; -const int kStageBeforeRedirect = 1 << 3; -const int kStageResponseStarted = 1 << 4; -const int kStageCompletedSuccess = 1 << 5; -const int kStageCompletedError = 1 << 6; -const int kStageURLRequestDestroyed = 1 << 7; -const int kStageDestruction = 1 << 8; +const int kStageAuthRequired = 1 << 3; +const int kStageBeforeRedirect = 1 << 4; +const int kStageResponseStarted = 1 << 5; +const int kStageCompletedSuccess = 1 << 6; +const int kStageCompletedError = 1 << 7; +const int kStageURLRequestDestroyed = 1 << 8; +const int kStageDestruction = 1 << 9; } // namespace @@ -166,6 +167,7 @@ TestDelegate::TestDelegate() received_data_before_response_(false), request_failed_(false), have_certificate_errors_(false), + auth_required_(false), buf_(new net::IOBuffer(kBufferSize)) { } @@ -185,6 +187,7 @@ void TestDelegate::OnReceivedRedirect(net::URLRequest* request, void TestDelegate::OnAuthRequired(net::URLRequest* request, net::AuthChallengeInfo* auth_info) { + auth_required_ = true; if (!username_.empty() || !password_.empty()) { request->SetAuth(username_, password_); } else { @@ -325,21 +328,21 @@ void TestNetworkDelegate::InitRequestStatesIfNew(int request_id) { } } - int TestNetworkDelegate::OnBeforeURLRequest( net::URLRequest* request, net::OldCompletionCallback* callback, GURL* new_url ) { int req_id = request->identifier(); - event_order_[req_id] += "OnBeforeURLRequest\n"; InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnBeforeURLRequest\n"; EXPECT_TRUE(next_states_[req_id] & kStageBeforeURLRequest) << event_order_[req_id]; next_states_[req_id] = kStageBeforeSendHeaders | kStageResponseStarted | // data: URLs do not trigger sending headers kStageBeforeRedirect | // a delegate can trigger a redirection - kStageCompletedError; // request canceled by delegate + kStageCompletedError | // request canceled by delegate + kStageAuthRequired; // Auth can come next for FTP requests created_requests_++; return net::OK; } @@ -349,8 +352,8 @@ int TestNetworkDelegate::OnBeforeSendHeaders( net::OldCompletionCallback* callback, net::HttpRequestHeaders* headers) { int req_id = request->identifier(); - event_order_[req_id] += "OnBeforeSendHeaders\n"; InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnBeforeSendHeaders\n"; EXPECT_TRUE(next_states_[req_id] & kStageBeforeSendHeaders) << event_order_[req_id]; next_states_[req_id] = @@ -364,13 +367,14 @@ void TestNetworkDelegate::OnSendHeaders( net::URLRequest* request, const net::HttpRequestHeaders& headers) { int req_id = request->identifier(); - event_order_[req_id] += "OnSendHeaders\n"; InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnSendHeaders\n"; EXPECT_TRUE(next_states_[req_id] & kStageSendHeaders) << event_order_[req_id]; next_states_[req_id] = kStageBeforeRedirect | kStageResponseStarted | + kStageAuthRequired | kStageCompletedError; // e.g. proxy resolution problem // Basic authentication sends a second request from the URLRequestHttpJob @@ -381,8 +385,8 @@ void TestNetworkDelegate::OnSendHeaders( void TestNetworkDelegate::OnBeforeRedirect(net::URLRequest* request, const GURL& new_location) { int req_id = request->identifier(); - event_order_[req_id] += "OnBeforeRedirect\n"; InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnBeforeRedirect\n"; EXPECT_TRUE(next_states_[req_id] & kStageBeforeRedirect) << event_order_[req_id]; next_states_[req_id] = @@ -398,8 +402,8 @@ void TestNetworkDelegate::OnBeforeRedirect(net::URLRequest* request, void TestNetworkDelegate::OnResponseStarted(net::URLRequest* request) { int req_id = request->identifier(); - event_order_[req_id] += "OnResponseStarted\n"; InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnResponseStarted\n"; EXPECT_TRUE(next_states_[req_id] & kStageResponseStarted) << event_order_[req_id]; next_states_[req_id] = kStageCompletedSuccess | kStageCompletedError; @@ -415,8 +419,8 @@ void TestNetworkDelegate::OnRawBytesRead(const net::URLRequest& request, void TestNetworkDelegate::OnCompleted(net::URLRequest* request) { int req_id = request->identifier(); - event_order_[req_id] += "OnCompleted\n"; InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnCompleted\n"; // Expect "Success -> (next_states_ & kStageCompletedSuccess)" // is logically identical to // Expect "!(Success) || (next_states_ & kStageCompletedSuccess)" @@ -437,27 +441,31 @@ void TestNetworkDelegate::OnCompleted(net::URLRequest* request) { void TestNetworkDelegate::OnURLRequestDestroyed( net::URLRequest* request) { int req_id = request->identifier(); - event_order_[req_id] += "OnURLRequestDestroyed\n"; InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnURLRequestDestroyed\n"; EXPECT_TRUE(next_states_[req_id] & kStageURLRequestDestroyed) << event_order_[req_id]; next_states_[req_id] = kStageDestruction; destroyed_requests_++; } -void TestNetworkDelegate::OnHttpTransactionDestroyed(uint64 request_id) { -} - -net::URLRequestJob* TestNetworkDelegate::OnMaybeCreateURLRequestJob( - net::URLRequest* request) { - return NULL; -} - void TestNetworkDelegate::OnPACScriptError(int line_number, const string16& error) { } -void TestNetworkDelegate::OnAuthRequired( - net::URLRequest* reqest, - const net::AuthChallengeInfo& auth_info) { +net::NetworkDelegate::AuthRequiredResponse TestNetworkDelegate::OnAuthRequired( + net::URLRequest* request, + const net::AuthChallengeInfo& auth_info, + const AuthCallback& callback, + net::AuthCredentials* credentials) { + int req_id = request->identifier(); + InitRequestStatesIfNew(req_id); + event_order_[req_id] += "OnAuthRequired\n"; + EXPECT_TRUE(next_states_[req_id] & kStageAuthRequired) << + event_order_[req_id]; + next_states_[req_id] = kStageBeforeSendHeaders | + kStageResponseStarted | // data: URLs do not trigger sending headers + kStageBeforeRedirect | // a delegate can trigger a redirection + kStageCompletedError; // request canceled by delegate + return net::NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION; } diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h index 85d2a9b..3446b59 100644 --- a/net/url_request/url_request_test_util.h +++ b/net/url_request/url_request_test_util.h @@ -11,6 +11,7 @@ #include <sstream> #include <string> +#include "base/compiler_specific.h" #include "base/path_service.h" #include "base/process_util.h" #include "base/string_util.h" @@ -122,6 +123,7 @@ class TestDelegate : public net::URLRequest::Delegate { } bool request_failed() const { return request_failed_; } bool have_certificate_errors() const { return have_certificate_errors_; } + bool auth_required_called() const { return auth_required_; } // net::URLRequest::Delegate: virtual void OnReceivedRedirect(net::URLRequest* request, const GURL& new_url, @@ -168,6 +170,7 @@ class TestDelegate : public net::URLRequest::Delegate { bool received_data_before_response_; bool request_failed_; bool have_certificate_errors_; + bool auth_required_; std::string data_received_; // our read buffer @@ -196,19 +199,21 @@ class TestNetworkDelegate : public net::NetworkDelegate { net::OldCompletionCallback* callback, net::HttpRequestHeaders* headers); virtual void OnSendHeaders(net::URLRequest* request, - const net::HttpRequestHeaders& headers); + const net::HttpRequestHeaders& headers) OVERRIDE; virtual void OnBeforeRedirect(net::URLRequest* request, - const GURL& new_location); - virtual void OnResponseStarted(net::URLRequest* request); - virtual void OnRawBytesRead(const net::URLRequest& request, int bytes_read); - virtual void OnCompleted(net::URLRequest* request); - virtual void OnURLRequestDestroyed(net::URLRequest* request); - virtual void OnHttpTransactionDestroyed(uint64 request_id); - virtual net::URLRequestJob* OnMaybeCreateURLRequestJob( - net::URLRequest* request); - virtual void OnPACScriptError(int line_number, const string16& error); - virtual void OnAuthRequired(net::URLRequest* request, - const net::AuthChallengeInfo& auth_info); + const GURL& new_location) OVERRIDE; + virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE; + virtual void OnRawBytesRead(const net::URLRequest& request, + int bytes_read) OVERRIDE; + virtual void OnCompleted(net::URLRequest* request) OVERRIDE; + virtual void OnURLRequestDestroyed(net::URLRequest* request) OVERRIDE; + virtual void OnPACScriptError(int line_number, + const string16& error) OVERRIDE; + virtual net::NetworkDelegate::AuthRequiredResponse OnAuthRequired( + net::URLRequest* request, + const net::AuthChallengeInfo& auth_info, + const AuthCallback& callback, + net::AuthCredentials* credentials) OVERRIDE; void InitRequestStatesIfNew(int request_id); diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index bcff3a0..2645861 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc @@ -128,11 +128,21 @@ class BlockingNetworkDelegate : public TestNetworkDelegate { BlockingNetworkDelegate() : retval_(net::ERR_IO_PENDING), callback_retval_(net::OK), + auth_retval_(NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING), + auth_callback_retval_( + NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION), ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {} void set_retval(int retval) { retval_ = retval; } void set_callback_retval(int retval) { callback_retval_ = retval; } void set_redirect_url(const GURL& url) { redirect_url_ = url; } + void set_auth_retval(NetworkDelegate::AuthRequiredResponse retval) { + auth_retval_ = retval; } + void set_auth_callback_retval(NetworkDelegate::AuthRequiredResponse retval) { + auth_callback_retval_ = retval; } + void set_auth_credentials(const AuthCredentials& auth_credentials) { + auth_credentials_ = auth_credentials; + } private: // TestNetworkDelegate: @@ -159,13 +169,51 @@ class BlockingNetworkDelegate : public TestNetworkDelegate { return net::ERR_IO_PENDING; } + virtual NetworkDelegate::AuthRequiredResponse OnAuthRequired( + URLRequest* request, + const AuthChallengeInfo& auth_info, + const AuthCallback& callback, + AuthCredentials* credentials) OVERRIDE { + TestNetworkDelegate::OnAuthRequired(request, auth_info, callback, + credentials); + switch (auth_retval_) { + case NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION: + break; + case NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH: + *credentials = auth_credentials_; + case NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH: + break; + case NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING: + MessageLoop::current()->PostTask( + FROM_HERE, + method_factory_.NewRunnableMethod( + &BlockingNetworkDelegate::DoAuthCallback, + callback, credentials)); + break; + } + return auth_retval_; + } + void DoCallback(net::OldCompletionCallback* callback) { callback->Run(callback_retval_); } + void DoAuthCallback(const AuthCallback& callback, + AuthCredentials* credentials) { + if (auth_callback_retval_ == + NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH) { + *credentials = auth_credentials_; + } + callback.Run(auth_callback_retval_); + } + + int retval_; int callback_retval_; GURL redirect_url_; + NetworkDelegate::AuthRequiredResponse auth_retval_; + NetworkDelegate::AuthRequiredResponse auth_callback_retval_; + AuthCredentials auth_credentials_; ScopedRunnableMethodFactory<BlockingNetworkDelegate> method_factory_; }; @@ -480,7 +528,6 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequestPost) { headers.SetHeader(HttpRequestHeaders::kContentLength, base::UintToString(arraysize(kData) - 1)); r.SetExtraRequestHeaders(headers); - r.Start(); MessageLoop::current()->Run(); @@ -497,6 +544,219 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequestPost) { EXPECT_EQ(1, network_delegate.destroyed_requests()); } +// Tests that the network delegate can synchronously complete OnAuthRequired +// by taking no action. This indicates that the NetworkDelegate does not want to +// handle the challenge, and is passing the buck along to the +// URLRequest::Delegate. +TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncNoAction) { + ASSERT_TRUE(test_server_.Start()); + + TestDelegate d; + BlockingNetworkDelegate network_delegate; + network_delegate.set_auth_retval( + NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION); + + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext(true)); + context->set_network_delegate(&network_delegate); + context->Init(); + + d.set_username(kUser); + d.set_password(kSecret); + + { + GURL url(test_server_.GetURL("auth-basic")); + TestURLRequest r(url, &d); + r.set_context(context); + r.Start(); + MessageLoop::current()->Run(); + + EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status()); + EXPECT_EQ(0, r.status().error()); + EXPECT_EQ(200, r.GetResponseCode()); + EXPECT_TRUE(d.auth_required_called()); + EXPECT_EQ(1, network_delegate.created_requests()); + EXPECT_EQ(0, network_delegate.destroyed_requests()); + } + EXPECT_EQ(1, network_delegate.destroyed_requests()); +} + +// Tests that the network delegate can synchronously complete OnAuthRequired +// by setting credentials. +TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncSetAuth) { + ASSERT_TRUE(test_server_.Start()); + + TestDelegate d; + BlockingNetworkDelegate network_delegate; + network_delegate.set_auth_retval( + NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH); + + AuthCredentials auth_credentials; + auth_credentials.username = kUser; + auth_credentials.password = kSecret; + network_delegate.set_auth_credentials(auth_credentials); + + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext(true)); + context->set_network_delegate(&network_delegate); + context->Init(); + + { + GURL url(test_server_.GetURL("auth-basic")); + TestURLRequest r(url, &d); + r.set_context(context); + r.Start(); + MessageLoop::current()->Run(); + + EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status()); + EXPECT_EQ(0, r.status().error()); + EXPECT_EQ(200, r.GetResponseCode()); + EXPECT_FALSE(d.auth_required_called()); + EXPECT_EQ(1, network_delegate.created_requests()); + EXPECT_EQ(0, network_delegate.destroyed_requests()); + } + EXPECT_EQ(1, network_delegate.destroyed_requests()); +} + +// Tests that the network delegate can synchronously complete OnAuthRequired +// by cancelling authentication. +TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredSyncCancel) { + ASSERT_TRUE(test_server_.Start()); + + TestDelegate d; + BlockingNetworkDelegate network_delegate; + network_delegate.set_auth_retval( + NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH); + + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext(true)); + context->set_network_delegate(&network_delegate); + context->Init(); + + { + GURL url(test_server_.GetURL("auth-basic")); + TestURLRequest r(url, &d); + r.set_context(context); + r.Start(); + MessageLoop::current()->Run(); + + EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status()); + EXPECT_EQ(OK, r.status().error()); + EXPECT_EQ(401, r.GetResponseCode()); + EXPECT_FALSE(d.auth_required_called()); + EXPECT_EQ(1, network_delegate.created_requests()); + EXPECT_EQ(0, network_delegate.destroyed_requests()); + } + EXPECT_EQ(1, network_delegate.destroyed_requests()); +} + +// Tests that the network delegate can asynchronously complete OnAuthRequired +// by taking no action. This indicates that the NetworkDelegate does not want +// to handle the challenge, and is passing the buck along to the +// URLRequest::Delegate. +TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredAsyncNoAction) { + ASSERT_TRUE(test_server_.Start()); + + TestDelegate d; + BlockingNetworkDelegate network_delegate; + network_delegate.set_auth_retval( + NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING); + network_delegate.set_auth_callback_retval( + NetworkDelegate::AUTH_REQUIRED_RESPONSE_NO_ACTION); + + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext(true)); + context->set_network_delegate(&network_delegate); + context->Init(); + + d.set_username(kUser); + d.set_password(kSecret); + + { + GURL url(test_server_.GetURL("auth-basic")); + TestURLRequest r(url, &d); + r.set_context(context); + r.Start(); + MessageLoop::current()->Run(); + + EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status()); + EXPECT_EQ(0, r.status().error()); + EXPECT_EQ(200, r.GetResponseCode()); + EXPECT_TRUE(d.auth_required_called()); + EXPECT_EQ(1, network_delegate.created_requests()); + EXPECT_EQ(0, network_delegate.destroyed_requests()); + } + EXPECT_EQ(1, network_delegate.destroyed_requests()); +} + +// Tests that the network delegate can asynchronously complete OnAuthRequired +// by setting credentials. +TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredAsyncSetAuth) { + ASSERT_TRUE(test_server_.Start()); + + TestDelegate d; + BlockingNetworkDelegate network_delegate; + network_delegate.set_auth_retval( + NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING); + network_delegate.set_auth_callback_retval( + NetworkDelegate::AUTH_REQUIRED_RESPONSE_SET_AUTH); + + AuthCredentials auth_credentials; + auth_credentials.username = kUser; + auth_credentials.password = kSecret; + network_delegate.set_auth_credentials(auth_credentials); + + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext(true)); + context->set_network_delegate(&network_delegate); + context->Init(); + + { + GURL url(test_server_.GetURL("auth-basic")); + TestURLRequest r(url, &d); + r.set_context(context); + r.Start(); + MessageLoop::current()->Run(); + + EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status()); + EXPECT_EQ(0, r.status().error()); + + EXPECT_EQ(200, r.GetResponseCode()); + EXPECT_FALSE(d.auth_required_called()); + EXPECT_EQ(1, network_delegate.created_requests()); + EXPECT_EQ(0, network_delegate.destroyed_requests()); + } + EXPECT_EQ(1, network_delegate.destroyed_requests()); +} + +// Tests that the network delegate can asynchronously complete OnAuthRequired +// by cancelling authentication. +TEST_F(URLRequestTestHTTP, NetworkDelegateOnAuthRequiredAsyncCancel) { + ASSERT_TRUE(test_server_.Start()); + + TestDelegate d; + BlockingNetworkDelegate network_delegate; + network_delegate.set_auth_retval( + NetworkDelegate::AUTH_REQUIRED_RESPONSE_IO_PENDING); + network_delegate.set_auth_callback_retval( + NetworkDelegate::AUTH_REQUIRED_RESPONSE_CANCEL_AUTH); + + scoped_refptr<TestURLRequestContext> context(new TestURLRequestContext(true)); + context->set_network_delegate(&network_delegate); + context->Init(); + + { + GURL url(test_server_.GetURL("auth-basic")); + TestURLRequest r(url, &d); + r.set_context(context); + r.Start(); + MessageLoop::current()->Run(); + + EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status()); + EXPECT_EQ(OK, r.status().error()); + EXPECT_EQ(401, r.GetResponseCode()); + EXPECT_FALSE(d.auth_required_called()); + EXPECT_EQ(1, network_delegate.created_requests()); + EXPECT_EQ(0, network_delegate.destroyed_requests()); + } + EXPECT_EQ(1, network_delegate.destroyed_requests()); +} + // In this unit test, we're using the HTTPTestServer as a proxy server and // issuing a CONNECT request with the magic host name "www.server-auth.com". // The HTTPTestServer will return a 401 response, which we should balk at. |