Index: net/http/http_network_transaction_unittest.cc |
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc |
index aa18df5b1c1b825569bedd9aead111f1f06bb9fb..b9458d5c5d27e12b12e3bf93f98294a3632a342d 100644 |
--- a/net/http/http_network_transaction_unittest.cc |
+++ b/net/http/http_network_transaction_unittest.cc |
@@ -65,7 +65,6 @@ ProxyService* CreateFixedProxyService(const std::string& proxy) { |
return ProxyService::CreateFixed(proxy_config); |
} |
- |
HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { |
return new HttpNetworkSession(NULL, |
session_deps->host_resolver, |
@@ -4679,4 +4678,201 @@ TEST_F(HttpNetworkTransactionTest, FailNpnSpdyAndFallback) { |
EXPECT_EQ("hello world", response_data); |
} |
+// MockAuthHandlerCanonical is used by the ResolveCanonicalName |
+// HttpNetworkTransaction unit test below. Callers set up expectations for |
+// whether the canonical name needs to be resolved. |
+class MockAuthHandlerCanonical : public HttpAuthHandler { |
+ public: |
+ enum Resolve { |
+ RESOLVE_INIT, |
+ RESOLVE_SKIP, |
+ RESOLVE_SYNC, |
+ RESOLVE_ASYNC, |
+ RESOLVE_TESTED, |
+ }; |
+ |
+ MockAuthHandlerCanonical() : resolve_(RESOLVE_INIT), user_callback_(NULL) {} |
+ virtual ~MockAuthHandlerCanonical() {} |
+ |
+ void SetResolveExpectation(Resolve resolve) { |
+ EXPECT_EQ(RESOLVE_INIT, resolve_); |
+ resolve_ = resolve; |
+ } |
+ |
+ void ResetResolveExpectation() { |
+ EXPECT_EQ(RESOLVE_TESTED, resolve_); |
+ resolve_ = RESOLVE_INIT; |
+ } |
+ |
+ virtual bool NeedsCanonicalName() { |
+ switch (resolve_) { |
+ case RESOLVE_SYNC: |
+ case RESOLVE_ASYNC: |
+ return true; |
+ case RESOLVE_SKIP: |
+ resolve_ = RESOLVE_TESTED; |
+ return false; |
+ default: |
+ NOTREACHED(); |
+ return false; |
+ } |
+ } |
+ |
+ virtual int ResolveCanonicalName(HostResolver* host_resolver, |
+ CompletionCallback* callback, |
+ const BoundNetLog& net_log) { |
+ EXPECT_NE(RESOLVE_TESTED, resolve_); |
+ int rv = OK; |
+ switch (resolve_) { |
+ case RESOLVE_SYNC: |
+ resolve_ = RESOLVE_TESTED; |
+ break; |
+ case RESOLVE_ASYNC: |
+ EXPECT_TRUE(user_callback_ == NULL); |
+ rv = ERR_IO_PENDING; |
+ user_callback_ = callback; |
+ MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ NewRunnableMethod( |
+ this, &MockAuthHandlerCanonical::OnResolveCanonicalName)); |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ return rv; |
+ } |
+ |
+ void OnResolveCanonicalName() { |
+ EXPECT_EQ(RESOLVE_ASYNC, resolve_); |
+ EXPECT_TRUE(user_callback_ != NULL); |
+ resolve_ = RESOLVE_TESTED; |
+ CompletionCallback* callback = user_callback_; |
+ user_callback_ = NULL; |
+ callback->Run(OK); |
+ } |
+ |
+ virtual bool Init(HttpAuth::ChallengeTokenizer* challenge) { |
+ scheme_ = "mock"; |
+ score_ = 1; |
+ properties_ = 0; |
+ return true; |
+ } |
+ |
+ virtual int GenerateAuthToken(const std::wstring& username, |
+ const std::wstring& password, |
+ const HttpRequestInfo* request, |
+ const ProxyInfo* proxy, |
+ std::string* auth_token) { |
+ auth_token->assign("Mock AUTH myserver.example.com"); |
+ return OK; |
+ } |
+ |
+ virtual int GenerateDefaultAuthToken(const HttpRequestInfo* request, |
+ const ProxyInfo* proxy, |
+ std::string* auth_token) { |
+ auth_token->assign("Mock DEFAULT_AUTH myserver.example.com"); |
+ return OK; |
+ } |
+ |
+ // The Factory class simply returns the same handler each time |
+ // CreateAuthHandler is called. |
+ class Factory : public HttpAuthHandlerFactory { |
+ public: |
+ Factory() {} |
+ virtual ~Factory() {} |
+ |
+ void set_mock_handler(MockAuthHandlerCanonical* mock_handler) { |
+ mock_handler_ = mock_handler; |
+ } |
+ MockAuthHandlerCanonical* mock_handler() const { |
+ return mock_handler_.get(); |
+ } |
+ |
+ virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge, |
+ HttpAuth::Target target, |
+ const GURL& origin, |
+ scoped_refptr<HttpAuthHandler>* handler) { |
+ *handler = mock_handler_; |
+ return OK; |
+ } |
+ |
+ private: |
+ scoped_refptr<MockAuthHandlerCanonical> mock_handler_; |
+ }; |
+ |
+ private: |
+ Resolve resolve_; |
+ CompletionCallback* user_callback_; |
+}; |
+ |
+// Tests that ResolveCanonicalName is handled correctly by the |
+// HttpNetworkTransaction. |
+TEST_F(HttpNetworkTransactionTest, ResolveCanonicalName) { |
+ SessionDependencies session_deps; |
+ scoped_refptr<MockAuthHandlerCanonical> auth_handler( |
+ new MockAuthHandlerCanonical()); |
+ auth_handler->Init(NULL); |
+ MockAuthHandlerCanonical::Factory* auth_factory( |
+ new MockAuthHandlerCanonical::Factory()); |
+ auth_factory->set_mock_handler(auth_handler); |
+ session_deps.http_auth_handler_factory.reset(auth_factory); |
+ |
+ for (int i = 0; i < 2; ++i) { |
+ scoped_ptr<HttpTransaction> trans( |
+ new HttpNetworkTransaction(CreateSession(&session_deps))); |
+ |
+ // Set up expectations for this pass of the test. Many of the EXPECT calls |
+ // are contained inside the MockAuthHandlerCanonical codebase in response to |
+ // the expectations. |
+ MockAuthHandlerCanonical::Resolve resolve = (i == 0) ? |
+ MockAuthHandlerCanonical::RESOLVE_SYNC : |
+ MockAuthHandlerCanonical::RESOLVE_ASYNC; |
+ auth_handler->SetResolveExpectation(resolve); |
+ HttpRequestInfo request; |
+ request.method = "GET"; |
+ request.url = GURL("http://myserver/"); |
+ request.load_flags = 0; |
+ |
+ MockWrite data_writes1[] = { |
+ MockWrite("GET / HTTP/1.1\r\n" |
+ "Host: myserver\r\n" |
+ "Connection: keep-alive\r\n\r\n"), |
+ }; |
+ |
+ MockRead data_reads1[] = { |
+ MockRead("HTTP/1.1 401 Unauthorized\r\n"), |
+ MockRead("WWW-Authenticate: Mock myserver.example.com\r\n"), |
+ MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), |
+ MockRead("Content-Length: 14\r\n\r\n"), |
+ MockRead("Unauthorized\r\n"), |
+ }; |
+ |
+ StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), |
+ data_writes1, arraysize(data_writes1)); |
+ session_deps.socket_factory.AddSocketDataProvider(&data1); |
+ |
+ TestCompletionCallback callback1; |
+ |
+ int rv = trans->Start(&request, &callback1, NULL); |
+ EXPECT_EQ(ERR_IO_PENDING, rv); |
+ |
+ rv = callback1.WaitForResult(); |
+ EXPECT_EQ(OK, rv); |
+ |
+ const HttpResponseInfo* response = trans->GetResponseInfo(); |
+ EXPECT_FALSE(response == NULL); |
+ |
+ // The password prompt is set after the canonical name is resolved. |
+ // If it isn't present or is incorrect, it indicates that the scheme |
+ // did not complete correctly. |
+ EXPECT_FALSE(response->auth_challenge.get() == NULL); |
+ |
+ EXPECT_EQ(L"myserver:80", response->auth_challenge->host_and_port); |
+ EXPECT_EQ(L"", response->auth_challenge->realm); |
+ EXPECT_EQ(L"mock", response->auth_challenge->scheme); |
+ auth_handler->ResetResolveExpectation(); |
+ } |
+} |
+ |
} // namespace net |