summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/net/chrome_network_delegate.cc8
-rw-r--r--chrome/browser/net/chrome_network_delegate.h7
-rw-r--r--chrome_frame/test/net/fake_external_tab.cc9
-rw-r--r--net/base/auth.cc6
-rw-r--r--net/base/auth.h23
-rw-r--r--net/base/network_delegate.cc9
-rw-r--r--net/base/network_delegate.h47
-rw-r--r--net/proxy/network_delegate_error_observer_unittest.cc13
-rw-r--r--net/url_request/url_request.cc71
-rw-r--r--net/url_request/url_request.h10
-rw-r--r--net/url_request/url_request_ftp_job.cc18
-rw-r--r--net/url_request/url_request_test_util.cc60
-rw-r--r--net/url_request/url_request_test_util.h29
-rw-r--r--net/url_request/url_request_unittest.cc262
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.