diff options
author | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-09 18:08:09 +0000 |
---|---|---|
committer | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-09 18:08:09 +0000 |
commit | 07c234afb79da58678041d152d15c547077ee93a (patch) | |
tree | 953d1b51d32a6c7d4120701a4ae834898b469a08 /net | |
parent | 54ea217d2acacd72d8e0c8cd9ee0f0e5e51d1a95 (diff) | |
download | chromium_src-07c234afb79da58678041d152d15c547077ee93a.zip chromium_src-07c234afb79da58678041d152d15c547077ee93a.tar.gz chromium_src-07c234afb79da58678041d152d15c547077ee93a.tar.bz2 |
Remove SPDY 2.1 support.
BUG=121919
Review URL: http://codereview.chromium.org/10005041
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@131383 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
23 files changed, 24 insertions, 16110 deletions
diff --git a/net/base/upload_data.h b/net/base/upload_data.h index abc1c19..c9796ac 100644 --- a/net/base/upload_data.h +++ b/net/base/upload_data.h @@ -175,8 +175,6 @@ class NET_EXPORT UploadData UploadFileSmallerThanLength); FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionSpdy2Test, UploadFileSmallerThanLength); - FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionSpdy21Test, - UploadFileSmallerThanLength); FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionSpdy3Test, UploadFileSmallerThanLength); }; diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index f9ae01e..779d0e3 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -87,8 +87,6 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction private: FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionSpdy2Test, ResetStateForRestart); - FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionSpdy21Test, - ResetStateForRestart); FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionSpdy3Test, ResetStateForRestart); FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy2Test, @@ -99,14 +97,6 @@ class NET_EXPORT_PRIVATE HttpNetworkTransaction WindowUpdateOverflow); FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy2Test, FlowControlStallResume); - FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy21Test, - WindowUpdateReceived); - FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy21Test, - WindowUpdateSent); - FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy21Test, - WindowUpdateOverflow); - FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy21Test, - FlowControlStallResume); FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy3Test, WindowUpdateReceived); FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy3Test, diff --git a/net/http/http_network_transaction_spdy21_unittest.cc b/net/http/http_network_transaction_spdy21_unittest.cc deleted file mode 100644 index 23f1eb3..0000000 --- a/net/http/http_network_transaction_spdy21_unittest.cc +++ /dev/null @@ -1,9555 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/http/http_network_transaction.h" - -#include <math.h> // ceil -#include <stdarg.h> -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/file_path.h" -#include "base/file_util.h" -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram.h" -#include "base/test/test_file_util.h" -#include "base/utf_string_conversions.h" -#include "net/base/auth.h" -#include "net/base/capturing_net_log.h" -#include "net/base/completion_callback.h" -#include "net/base/host_cache.h" -#include "net/base/mock_host_resolver.h" -#include "net/base/net_log.h" -#include "net/base/net_log_unittest.h" -#include "net/base/request_priority.h" -#include "net/base/ssl_cert_request_info.h" -#include "net/base/ssl_config_service_defaults.h" -#include "net/base/ssl_info.h" -#include "net/base/test_completion_callback.h" -#include "net/base/upload_data.h" -#include "net/http/http_auth_handler_digest.h" -#include "net/http/http_auth_handler_mock.h" -#include "net/http/http_auth_handler_ntlm.h" -#include "net/http/http_basic_stream.h" -#include "net/http/http_net_log_params.h" -#include "net/http/http_network_session.h" -#include "net/http/http_network_session_peer.h" -#include "net/http/http_server_properties_impl.h" -#include "net/http/http_stream.h" -#include "net/http/http_stream_factory.h" -#include "net/http/http_transaction_unittest.h" -#include "net/proxy/proxy_config_service_fixed.h" -#include "net/proxy/proxy_resolver.h" -#include "net/proxy/proxy_service.h" -#include "net/socket/client_socket_factory.h" -#include "net/socket/mock_client_socket_pool_manager.h" -#include "net/socket/socket_test_util.h" -#include "net/socket/ssl_client_socket.h" -#include "net/spdy/spdy_framer.h" -#include "net/spdy/spdy_session.h" -#include "net/spdy/spdy_session_pool.h" -#include "net/spdy/spdy_test_util_spdy2.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -using namespace net::test_spdy2; - -//----------------------------------------------------------------------------- - -namespace { - -const string16 kBar(ASCIIToUTF16("bar")); -const string16 kBar2(ASCIIToUTF16("bar2")); -const string16 kBar3(ASCIIToUTF16("bar3")); -const string16 kBaz(ASCIIToUTF16("baz")); -const string16 kFirst(ASCIIToUTF16("first")); -const string16 kFoo(ASCIIToUTF16("foo")); -const string16 kFoo2(ASCIIToUTF16("foo2")); -const string16 kFoo3(ASCIIToUTF16("foo3")); -const string16 kFou(ASCIIToUTF16("fou")); -const string16 kSecond(ASCIIToUTF16("second")); -const string16 kTestingNTLM(ASCIIToUTF16("testing-ntlm")); -const string16 kWrongPassword(ASCIIToUTF16("wrongpassword")); - -// MakeNextProtos is a utility function that returns a vector of std::strings -// from its arguments. Don't forget to terminate the argument list with a NULL. -std::vector<std::string> MakeNextProtos(const char* a, ...) { - std::vector<std::string> ret; - ret.push_back(a); - - va_list args; - va_start(args, a); - - for (;;) { - const char* value = va_arg(args, const char*); - if (value == NULL) - break; - ret.push_back(value); - } - va_end(args); - - return ret; -} - -// SpdyNextProtos returns a vector of NPN protocol strings for negotiating -// SPDY. -std::vector<std::string> SpdyNextProtos() { - return MakeNextProtos("http/1.1", "spdy/2", "spdy/2.1", NULL); -} - -int GetIdleSocketCountInTransportSocketPool(net::HttpNetworkSession* session) { - return session->GetTransportSocketPool( - net::HttpNetworkSession::NORMAL_SOCKET_POOL)->IdleSocketCount(); -} - -int GetIdleSocketCountInSSLSocketPool(net::HttpNetworkSession* session) { - return session->GetSSLSocketPool( - net::HttpNetworkSession::NORMAL_SOCKET_POOL)->IdleSocketCount(); -} - -} // namespace - -namespace net { - -namespace { - -// Helper to manage the lifetimes of the dependencies for a -// HttpNetworkTransaction. -struct SessionDependencies { - // Default set of dependencies -- "null" proxy service. - SessionDependencies() - : host_resolver(new MockHostResolver), - cert_verifier(CertVerifier::CreateDefault()), - proxy_service(ProxyService::CreateDirect()), - ssl_config_service(new SSLConfigServiceDefaults), - http_auth_handler_factory( - HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), - net_log(NULL) {} - - // Custom proxy service dependency. - explicit SessionDependencies(ProxyService* proxy_service) - : host_resolver(new MockHostResolver), - cert_verifier(CertVerifier::CreateDefault()), - proxy_service(proxy_service), - ssl_config_service(new SSLConfigServiceDefaults), - http_auth_handler_factory( - HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), - net_log(NULL) {} - - scoped_ptr<MockHostResolverBase> host_resolver; - scoped_ptr<CertVerifier> cert_verifier; - scoped_ptr<ProxyService> proxy_service; - scoped_refptr<SSLConfigService> ssl_config_service; - MockClientSocketFactory socket_factory; - scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory; - HttpServerPropertiesImpl http_server_properties; - NetLog* net_log; -}; - -HttpNetworkSession* CreateSession(SessionDependencies* session_deps) { - net::HttpNetworkSession::Params params; - params.client_socket_factory = &session_deps->socket_factory; - params.host_resolver = session_deps->host_resolver.get(); - params.cert_verifier = session_deps->cert_verifier.get(); - params.proxy_service = session_deps->proxy_service.get(); - params.ssl_config_service = session_deps->ssl_config_service; - params.http_auth_handler_factory = - session_deps->http_auth_handler_factory.get(); - params.http_server_properties = &session_deps->http_server_properties; - params.net_log = session_deps->net_log; - return new HttpNetworkSession(params); -} - -} // namespace - -class HttpNetworkTransactionSpdy21Test : public PlatformTest { - protected: - struct SimpleGetHelperResult { - int rv; - std::string status_line; - std::string response_data; - }; - - virtual void SetUp() { - SpdySession::set_default_protocol(kProtoSPDY21); - NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); - MessageLoop::current()->RunAllPending(); - } - - virtual void TearDown() { - NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); - MessageLoop::current()->RunAllPending(); - // Empty the current queue. - MessageLoop::current()->RunAllPending(); - PlatformTest::TearDown(); - NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests(); - MessageLoop::current()->RunAllPending(); - } - - // Either |write_failure| specifies a write failure or |read_failure| - // specifies a read failure when using a reused socket. In either case, the - // failure should cause the network transaction to resend the request, and the - // other argument should be NULL. - void KeepAliveConnectionResendRequestTest(const MockWrite* write_failure, - const MockRead* read_failure); - - SimpleGetHelperResult SimpleGetHelperForData(StaticSocketDataProvider* data[], - size_t data_count) { - SimpleGetHelperResult out; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - for (size_t i = 0; i < data_count; ++i) { - session_deps.socket_factory.AddSocketDataProvider(data[i]); - } - - TestCompletionCallback callback; - - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - EXPECT_TRUE(log.bound().IsLoggingAllEvents()); - int rv = trans->Start(&request, callback.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - out.rv = callback.WaitForResult(); - if (out.rv != OK) - return out; - - const HttpResponseInfo* response = trans->GetResponseInfo(); - // Can't use ASSERT_* inside helper functions like this, so - // return an error. - if (response == NULL || response->headers == NULL) { - out.rv = ERR_UNEXPECTED; - return out; - } - out.status_line = response->headers->GetStatusLine(); - - EXPECT_EQ("192.0.2.33", response->socket_address.host()); - EXPECT_EQ(0, response->socket_address.port()); - - rv = ReadTransaction(trans.get(), &out.response_data); - EXPECT_EQ(OK, rv); - - net::CapturingNetLog::EntryList entries; - log.GetEntries(&entries); - size_t pos = ExpectLogContainsSomewhere( - entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS, - NetLog::PHASE_NONE); - ExpectLogContainsSomewhere( - entries, pos, - NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS, - NetLog::PHASE_NONE); - - CapturingNetLog::Entry entry = entries[pos]; - NetLogHttpRequestParameter* request_params = - static_cast<NetLogHttpRequestParameter*>(entry.extra_parameters.get()); - EXPECT_EQ("GET / HTTP/1.1\r\n", request_params->GetLine()); - EXPECT_EQ("Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n", - request_params->GetHeaders().ToString()); - - return out; - } - - SimpleGetHelperResult SimpleGetHelper(MockRead data_reads[], - size_t reads_count) { - StaticSocketDataProvider reads(data_reads, reads_count, NULL, 0); - StaticSocketDataProvider* data[] = { &reads }; - return SimpleGetHelperForData(data, 1); - } - - void ConnectStatusHelperWithExpectedStatus(const MockRead& status, - int expected_status); - - void ConnectStatusHelper(const MockRead& status); - - private: - SpdyTestStateHelper spdy_state_; -}; - -namespace { - -// Fill |str| with a long header list that consumes >= |size| bytes. -void FillLargeHeadersString(std::string* str, int size) { - const char* row = - "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n"; - const int sizeof_row = strlen(row); - const int num_rows = static_cast<int>( - ceil(static_cast<float>(size) / sizeof_row)); - const int sizeof_data = num_rows * sizeof_row; - DCHECK(sizeof_data >= size); - str->reserve(sizeof_data); - - for (int i = 0; i < num_rows; ++i) - str->append(row, sizeof_row); -} - -// Alternative functions that eliminate randomness and dependency on the local -// host name so that the generated NTLM messages are reproducible. -void MockGenerateRandom1(uint8* output, size_t n) { - static const uint8 bytes[] = { - 0x55, 0x29, 0x66, 0x26, 0x6b, 0x9c, 0x73, 0x54 - }; - static size_t current_byte = 0; - for (size_t i = 0; i < n; ++i) { - output[i] = bytes[current_byte++]; - current_byte %= arraysize(bytes); - } -} - -void MockGenerateRandom2(uint8* output, size_t n) { - static const uint8 bytes[] = { - 0x96, 0x79, 0x85, 0xe7, 0x49, 0x93, 0x70, 0xa1, - 0x4e, 0xe7, 0x87, 0x45, 0x31, 0x5b, 0xd3, 0x1f - }; - static size_t current_byte = 0; - for (size_t i = 0; i < n; ++i) { - output[i] = bytes[current_byte++]; - current_byte %= arraysize(bytes); - } -} - -std::string MockGetHostName() { - return "WTC-WIN7"; -} - -template<typename ParentPool> -class CaptureGroupNameSocketPool : public ParentPool { - public: - CaptureGroupNameSocketPool(HostResolver* host_resolver, - CertVerifier* cert_verifier); - - const std::string last_group_name_received() const { - return last_group_name_; - } - - virtual int RequestSocket(const std::string& group_name, - const void* socket_params, - RequestPriority priority, - ClientSocketHandle* handle, - const CompletionCallback& callback, - const BoundNetLog& net_log) { - last_group_name_ = group_name; - return ERR_IO_PENDING; - } - virtual void CancelRequest(const std::string& group_name, - ClientSocketHandle* handle) {} - virtual void ReleaseSocket(const std::string& group_name, - StreamSocket* socket, - int id) {} - virtual void CloseIdleSockets() {} - virtual int IdleSocketCount() const { - return 0; - } - virtual int IdleSocketCountInGroup(const std::string& group_name) const { - return 0; - } - virtual LoadState GetLoadState(const std::string& group_name, - const ClientSocketHandle* handle) const { - return LOAD_STATE_IDLE; - } - virtual base::TimeDelta ConnectionTimeout() const { - return base::TimeDelta(); - } - - private: - std::string last_group_name_; -}; - -typedef CaptureGroupNameSocketPool<TransportClientSocketPool> -CaptureGroupNameTransportSocketPool; -typedef CaptureGroupNameSocketPool<HttpProxyClientSocketPool> -CaptureGroupNameHttpProxySocketPool; -typedef CaptureGroupNameSocketPool<SOCKSClientSocketPool> -CaptureGroupNameSOCKSSocketPool; -typedef CaptureGroupNameSocketPool<SSLClientSocketPool> -CaptureGroupNameSSLSocketPool; - -template<typename ParentPool> -CaptureGroupNameSocketPool<ParentPool>::CaptureGroupNameSocketPool( - HostResolver* host_resolver, - CertVerifier* /* cert_verifier */) - : ParentPool(0, 0, NULL, host_resolver, NULL, NULL) {} - -template<> -CaptureGroupNameHttpProxySocketPool::CaptureGroupNameSocketPool( - HostResolver* host_resolver, - CertVerifier* /* cert_verifier */) - : HttpProxyClientSocketPool(0, 0, NULL, host_resolver, NULL, NULL, NULL) {} - -template<> -CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool( - HostResolver* host_resolver, - CertVerifier* cert_verifier) - : SSLClientSocketPool(0, 0, NULL, host_resolver, cert_verifier, NULL, - NULL, NULL, "", NULL, NULL, NULL, NULL, NULL, NULL) {} - -//----------------------------------------------------------------------------- - -// This is the expected return from a current server advertising SPDY. -static const char kAlternateProtocolHttpHeader[] = - "Alternate-Protocol: 443:npn-spdy/2.1\r\n\r\n"; - -// Helper functions for validating that AuthChallengeInfo's are correctly -// configured for common cases. -bool CheckBasicServerAuth(const AuthChallengeInfo* auth_challenge) { - if (!auth_challenge) - return false; - EXPECT_FALSE(auth_challenge->is_proxy); - EXPECT_EQ("www.google.com:80", auth_challenge->challenger.ToString()); - EXPECT_EQ("MyRealm1", auth_challenge->realm); - EXPECT_EQ("basic", auth_challenge->scheme); - return true; -} - -bool CheckBasicProxyAuth(const AuthChallengeInfo* auth_challenge) { - if (!auth_challenge) - return false; - EXPECT_TRUE(auth_challenge->is_proxy); - EXPECT_EQ("myproxy:70", auth_challenge->challenger.ToString()); - EXPECT_EQ("MyRealm1", auth_challenge->realm); - EXPECT_EQ("basic", auth_challenge->scheme); - return true; -} - -bool CheckDigestServerAuth(const AuthChallengeInfo* auth_challenge) { - if (!auth_challenge) - return false; - EXPECT_FALSE(auth_challenge->is_proxy); - EXPECT_EQ("www.google.com:80", auth_challenge->challenger.ToString()); - EXPECT_EQ("digestive", auth_challenge->realm); - EXPECT_EQ("digest", auth_challenge->scheme); - return true; -} - -bool CheckNTLMServerAuth(const AuthChallengeInfo* auth_challenge) { - if (!auth_challenge) - return false; - EXPECT_FALSE(auth_challenge->is_proxy); - EXPECT_EQ("172.22.68.17:80", auth_challenge->challenger.ToString()); - EXPECT_EQ(std::string(), auth_challenge->realm); - EXPECT_EQ("ntlm", auth_challenge->scheme); - return true; -} - -} // namespace - -TEST_F(HttpNetworkTransactionSpdy21Test, Basic) { - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, SimpleGET) { - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); - EXPECT_EQ("hello world", out.response_data); -} - -// Response with no status line. -TEST_F(HttpNetworkTransactionSpdy21Test, SimpleGETNoHeaders) { - MockRead data_reads[] = { - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); - EXPECT_EQ("hello world", out.response_data); -} - -// Allow up to 4 bytes of junk to precede status line. -TEST_F(HttpNetworkTransactionSpdy21Test, StatusLineJunk2Bytes) { - MockRead data_reads[] = { - MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); - EXPECT_EQ("DATA", out.response_data); -} - -// Allow up to 4 bytes of junk to precede status line. -TEST_F(HttpNetworkTransactionSpdy21Test, StatusLineJunk4Bytes) { - MockRead data_reads[] = { - MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); - EXPECT_EQ("DATA", out.response_data); -} - -// Beyond 4 bytes of slop and it should fail to find a status line. -TEST_F(HttpNetworkTransactionSpdy21Test, StatusLineJunk5Bytes) { - MockRead data_reads[] = { - MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"), - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); - EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data); -} - -// Same as StatusLineJunk4Bytes, except the read chunks are smaller. -TEST_F(HttpNetworkTransactionSpdy21Test, StatusLineJunk4Bytes_Slow) { - MockRead data_reads[] = { - MockRead("\n"), - MockRead("\n"), - MockRead("Q"), - MockRead("J"), - MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"), - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line); - EXPECT_EQ("DATA", out.response_data); -} - -// Close the connection before enough bytes to have a status line. -TEST_F(HttpNetworkTransactionSpdy21Test, StatusLinePartial) { - MockRead data_reads[] = { - MockRead("HTT"), - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/0.9 200 OK", out.status_line); - EXPECT_EQ("HTT", out.response_data); -} - -// Simulate a 204 response, lacking a Content-Length header, sent over a -// persistent connection. The response should still terminate since a 204 -// cannot have a response body. -TEST_F(HttpNetworkTransactionSpdy21Test, StopsReading204) { - MockRead data_reads[] = { - MockRead("HTTP/1.1 204 No Content\r\n\r\n"), - MockRead("junk"), // Should not be read!! - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line); - EXPECT_EQ("", out.response_data); -} - -// A simple request using chunked encoding with some extra data after. -// (Like might be seen in a pipelined response.) -TEST_F(HttpNetworkTransactionSpdy21Test, ChunkedEncoding) { - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"), - MockRead("5\r\nHello\r\n"), - MockRead("1\r\n"), - MockRead(" \r\n"), - MockRead("5\r\nworld\r\n"), - MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("Hello world", out.response_data); -} - -// Next tests deal with http://crbug.com/56344. - -TEST_F(HttpNetworkTransactionSpdy21Test, - MultipleContentLengthHeadersNoTransferEncoding) { - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Length: 10\r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - DuplicateContentLengthHeadersNoTransferEncoding) { - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Length: 5\r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - MockRead("Hello"), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("Hello", out.response_data); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - ComplexContentLengthHeadersNoTransferEncoding) { - // More than 2 dupes. - { - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Length: 5\r\n"), - MockRead("Content-Length: 5\r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - MockRead("Hello"), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("Hello", out.response_data); - } - // HTTP/1.0 - { - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Length: 5\r\n"), - MockRead("Content-Length: 5\r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - MockRead("Hello"), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); - EXPECT_EQ("Hello", out.response_data); - } - // 2 dupes and one mismatched. - { - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Length: 10\r\n"), - MockRead("Content-Length: 10\r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH, out.rv); - } -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - MultipleContentLengthHeadersTransferEncoding) { - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Length: 666\r\n"), - MockRead("Content-Length: 1337\r\n"), - MockRead("Transfer-Encoding: chunked\r\n\r\n"), - MockRead("5\r\nHello\r\n"), - MockRead("1\r\n"), - MockRead(" \r\n"), - MockRead("5\r\nworld\r\n"), - MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("Hello world", out.response_data); -} - -// Next tests deal with http://crbug.com/98895. - -// Checks that a single Content-Disposition header results in no error. -TEST_F(HttpNetworkTransactionSpdy21Test, SingleContentDispositionHeader) { - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Disposition: attachment;filename=\"salutations.txt\"r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - MockRead("Hello"), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("Hello", out.response_data); -} - -// Checks that two identical Content-Disposition headers result in no error. -TEST_F(HttpNetworkTransactionSpdy21Test, - TwoIdenticalContentDispositionHeaders) { - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), - MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - MockRead("Hello"), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("Hello", out.response_data); -} - -// Checks that two distinct Content-Disposition headers result in an error. -TEST_F(HttpNetworkTransactionSpdy21Test, TwoDistinctContentDispositionHeaders) { - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"), - MockRead("Content-Disposition: attachment;filename=\"hi.txt\"r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - MockRead("Hello"), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION, out.rv); -} - -// Checks that two identical Location headers result in no error. -// Also tests Location header behavior. -TEST_F(HttpNetworkTransactionSpdy21Test, TwoIdenticalLocationHeaders) { - MockRead data_reads[] = { - MockRead("HTTP/1.1 302 Redirect\r\n"), - MockRead("Location: http://good.com/\r\n"), - MockRead("Location: http://good.com/\r\n"), - MockRead("Content-Length: 0\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://redirect.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL && response->headers != NULL); - EXPECT_EQ("HTTP/1.1 302 Redirect", response->headers->GetStatusLine()); - std::string url; - EXPECT_TRUE(response->headers->IsRedirect(&url)); - EXPECT_EQ("http://good.com/", url); -} - -// Checks that two distinct Location headers result in an error. -TEST_F(HttpNetworkTransactionSpdy21Test, TwoDistinctLocationHeaders) { - MockRead data_reads[] = { - MockRead("HTTP/1.1 302 Redirect\r\n"), - MockRead("Location: http://good.com/\r\n"), - MockRead("Location: http://evil.com/\r\n"), - MockRead("Content-Length: 0\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION, out.rv); -} - -// Do a request using the HEAD method. Verify that we don't try to read the -// message body (since HEAD has none). -TEST_F(HttpNetworkTransactionSpdy21Test, Head) { - HttpRequestInfo request; - request.method = "HEAD"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes1[] = { - MockWrite("HEAD / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Content-Length: 0\r\n\r\n"), - }; - MockRead data_reads1[] = { - MockRead("HTTP/1.1 404 Not Found\r\n"), - MockRead("Server: Blah\r\n"), - MockRead("Content-Length: 1234\r\n\r\n"), - - // No response body because the test stops reading here. - MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. - }; - - 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.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - // Check that the headers got parsed. - EXPECT_TRUE(response->headers != NULL); - EXPECT_EQ(1234, response->headers->GetContentLength()); - EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine()); - - std::string server_header; - void* iter = NULL; - bool has_server_header = response->headers->EnumerateHeader( - &iter, "Server", &server_header); - EXPECT_TRUE(has_server_header); - EXPECT_EQ("Blah", server_header); - - // Reading should give EOF right away, since there is no message body - // (despite non-zero content-length). - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("", response_data); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ReuseConnection) { - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), - MockRead("hello"), - MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), - MockRead("world"), - MockRead(SYNCHRONOUS, OK), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - const char* const kExpectedResponseData[] = { - "hello", "world" - }; - - for (int i = 0; i < 2; ++i) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ(kExpectedResponseData[i], response_data); - } -} - -TEST_F(HttpNetworkTransactionSpdy21Test, Ignores100) { - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.foo.com/"); - request.upload_data = new UploadData; - request.upload_data->AppendBytes("foo", 3); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockRead data_reads[] = { - MockRead("HTTP/1.0 100 Continue\r\n\r\n"), - MockRead("HTTP/1.0 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("hello world", response_data); -} - -// This test is almost the same as Ignores100 above, but the response contains -// a 102 instead of a 100. Also, instead of HTTP/1.0 the response is -// HTTP/1.1 and the two status headers are read in one read. -TEST_F(HttpNetworkTransactionSpdy21Test, Ignores1xx) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.foo.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockRead data_reads[] = { - MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n" - "HTTP/1.1 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("hello world", response_data); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, Incomplete100ThenEOF) { - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.foo.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockRead data_reads[] = { - MockRead(SYNCHRONOUS, "HTTP/1.0 100 Continue\r\n"), - MockRead(ASYNC, 0), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("", response_data); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, EmptyResponse) { - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.foo.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockRead data_reads[] = { - MockRead(ASYNC, 0), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(ERR_EMPTY_RESPONSE, rv); -} - -void HttpNetworkTransactionSpdy21Test::KeepAliveConnectionResendRequestTest( - const MockWrite* write_failure, - const MockRead* read_failure) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.foo.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Written data for successfully sending both requests. - MockWrite data1_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.foo.com\r\n" - "Connection: keep-alive\r\n\r\n"), - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.foo.com\r\n" - "Connection: keep-alive\r\n\r\n") - }; - - // Read results for the first request. - MockRead data1_reads[] = { - MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), - MockRead("hello"), - MockRead(ASYNC, OK), - }; - - if (write_failure) { - ASSERT_TRUE(!read_failure); - data1_writes[1] = *write_failure; - } else { - ASSERT_TRUE(read_failure); - data1_reads[2] = *read_failure; - } - - StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), - data1_writes, arraysize(data1_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - - MockRead data2_reads[] = { - MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), - MockRead("world"), - MockRead(ASYNC, OK), - }; - StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - const char* kExpectedResponseData[] = { - "hello", "world" - }; - - for (int i = 0; i < 2; ++i) { - TestCompletionCallback callback; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ(kExpectedResponseData[i], response_data); - } -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - KeepAliveConnectionNotConnectedOnWrite) { - MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED); - KeepAliveConnectionResendRequestTest(&write_failure, NULL); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, KeepAliveConnectionReset) { - MockRead read_failure(ASYNC, ERR_CONNECTION_RESET); - KeepAliveConnectionResendRequestTest(NULL, &read_failure); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, KeepAliveConnectionEOF) { - MockRead read_failure(SYNCHRONOUS, OK); // EOF - KeepAliveConnectionResendRequestTest(NULL, &read_failure); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, NonKeepAliveConnectionReset) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockRead data_reads[] = { - MockRead(ASYNC, ERR_CONNECTION_RESET), - MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(ERR_CONNECTION_RESET, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - EXPECT_TRUE(response == NULL); -} - -// What do various browsers do when the server closes a non-keepalive -// connection without sending any response header or body? -// -// IE7: error page -// Safari 3.1.2 (Windows): error page -// Firefox 3.0.1: blank page -// Opera 9.52: after five attempts, blank page -// Us with WinHTTP: error page (ERR_INVALID_RESPONSE) -// Us: error page (EMPTY_RESPONSE) -TEST_F(HttpNetworkTransactionSpdy21Test, NonKeepAliveConnectionEOF) { - MockRead data_reads[] = { - MockRead(SYNCHRONOUS, OK), // EOF - MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - SimpleGetHelperResult out = SimpleGetHelper(data_reads, - arraysize(data_reads)); - EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv); -} - -// Test that we correctly reuse a keep-alive connection after not explicitly -// reading the body. -TEST_F(HttpNetworkTransactionSpdy21Test, KeepAliveAfterUnreadBody) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.foo.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Note that because all these reads happen in the same - // StaticSocketDataProvider, it shows that the same socket is being reused for - // all transactions. - MockRead data1_reads[] = { - MockRead("HTTP/1.1 204 No Content\r\n\r\n"), - MockRead("HTTP/1.1 205 Reset Content\r\n\r\n"), - MockRead("HTTP/1.1 304 Not Modified\r\n\r\n"), - MockRead("HTTP/1.1 302 Found\r\n" - "Content-Length: 0\r\n\r\n"), - MockRead("HTTP/1.1 302 Found\r\n" - "Content-Length: 5\r\n\r\n" - "hello"), - MockRead("HTTP/1.1 301 Moved Permanently\r\n" - "Content-Length: 0\r\n\r\n"), - MockRead("HTTP/1.1 301 Moved Permanently\r\n" - "Content-Length: 5\r\n\r\n" - "hello"), - MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"), - MockRead("hello"), - }; - StaticSocketDataProvider data1(data1_reads, arraysize(data1_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data1); - - MockRead data2_reads[] = { - MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. - }; - StaticSocketDataProvider data2(data2_reads, arraysize(data2_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - const int kNumUnreadBodies = arraysize(data1_reads) - 2; - std::string response_lines[kNumUnreadBodies]; - - for (size_t i = 0; i < arraysize(data1_reads) - 2; ++i) { - TestCompletionCallback callback; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - ASSERT_TRUE(response->headers != NULL); - response_lines[i] = response->headers->GetStatusLine(); - - // We intentionally don't read the response bodies. - } - - const char* const kStatusLines[] = { - "HTTP/1.1 204 No Content", - "HTTP/1.1 205 Reset Content", - "HTTP/1.1 304 Not Modified", - "HTTP/1.1 302 Found", - "HTTP/1.1 302 Found", - "HTTP/1.1 301 Moved Permanently", - "HTTP/1.1 301 Moved Permanently", - }; - - COMPILE_ASSERT(kNumUnreadBodies == arraysize(kStatusLines), - forgot_to_update_kStatusLines); - - for (int i = 0; i < kNumUnreadBodies; ++i) - EXPECT_EQ(kStatusLines[i], response_lines[i]); - - TestCompletionCallback callback; - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("hello", response_data); -} - -// Test the request-challenge-retry sequence for basic auth. -// (basic auth is the easiest to mock, because it has no randomness). -TEST_F(HttpNetworkTransactionSpdy21Test, BasicAuth) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes1[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.0 401 Unauthorized\r\n"), - // Give a couple authenticate options (only the middle one is actually - // supported). - MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed. - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - // Large content-length -- won't matter, as connection will be reset. - MockRead("Content-Length: 10000\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - MockWrite data_writes2[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads2[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(100, response->headers->GetContentLength()); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, DoNotSendAuth) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads[] = { - MockRead("HTTP/1.0 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - // Large content-length -- won't matter, as connection will be reset. - MockRead("Content-Length: 10000\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(0, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); -} - -// Test the request-challenge-retry sequence for basic auth, over a keep-alive -// connection. -TEST_F(HttpNetworkTransactionSpdy21Test, BasicAuthKeepAlive) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - MockWrite data_writes1[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.1 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\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"), - - // Lastly, the server responds with the actual content. - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - MockRead("Hello"), - }; - - // If there is a regression where we disconnect a Keep-Alive - // connection during an auth roundtrip, we'll end up reading this. - MockRead data_reads2[] = { - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(5, response->headers->GetContentLength()); -} - -// Test the request-challenge-retry sequence for basic auth, over a keep-alive -// connection and with no response body to drain. -TEST_F(HttpNetworkTransactionSpdy21Test, BasicAuthKeepAliveNoBody) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - MockWrite data_writes1[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.1 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Length: 0\r\n\r\n"), // No response body. - - // Lastly, the server responds with the actual content. - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - MockRead("hello"), - }; - - // An incorrect reconnect would cause this to be read. - MockRead data_reads2[] = { - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(5, response->headers->GetContentLength()); -} - -// Test the request-challenge-retry sequence for basic auth, over a keep-alive -// connection and with a large response body to drain. -TEST_F(HttpNetworkTransactionSpdy21Test, BasicAuthKeepAliveLargeBody) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - MockWrite data_writes1[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - // Respond with 5 kb of response body. - std::string large_body_string("Unauthorized"); - large_body_string.append(5 * 1024, ' '); - large_body_string.append("\r\n"); - - MockRead data_reads1[] = { - MockRead("HTTP/1.1 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - // 5134 = 12 + 5 * 1024 + 2 - MockRead("Content-Length: 5134\r\n\r\n"), - MockRead(ASYNC, large_body_string.data(), large_body_string.size()), - - // Lastly, the server responds with the actual content. - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - MockRead("hello"), - }; - - // An incorrect reconnect would cause this to be read. - MockRead data_reads2[] = { - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(5, response->headers->GetContentLength()); -} - -// Test the request-challenge-retry sequence for basic auth, over a keep-alive -// connection, but the server gets impatient and closes the connection. -TEST_F(HttpNetworkTransactionSpdy21Test, BasicAuthKeepAliveImpatientServer) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - MockWrite data_writes1[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - // This simulates the seemingly successful write to a closed connection - // if the bug is not fixed. - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.1 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 14\r\n\r\n"), - // Tell MockTCPClientSocket to simulate the server closing the connection. - MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), - MockRead("Unauthorized\r\n"), - MockRead(SYNCHRONOUS, OK), // The server closes the connection. - }; - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - MockWrite data_writes2[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads2[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - MockRead("hello"), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(5, response->headers->GetContentLength()); -} - -// Test the request-challenge-retry sequence for basic auth, over a connection -// that requires a restart when setting up an SSL tunnel. -TEST_F(HttpNetworkTransactionSpdy21Test, BasicAuthProxyNoKeepAlive) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - // when the no authentication data flag is set. - request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; - - // Configure against proxy server "myproxy:70". - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Since we have proxy, should try to establish tunnel. - MockWrite data_writes1[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - // The proxy responds to the connect with a 407, using a persistent - // connection. - MockRead data_reads1[] = { - // No credentials. - MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Proxy-Connection: close\r\n\r\n"), - - MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), - - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 5\r\n\r\n"), - MockRead(SYNCHRONOUS, "hello"), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - SSLSocketDataProvider ssl(ASYNC, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - net::CapturingNetLog::EntryList entries; - log.GetEntries(&entries); - size_t pos = ExpectLogContainsSomewhere( - entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - NetLog::PHASE_NONE); - ExpectLogContainsSomewhere( - entries, pos, - NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - NetLog::PHASE_NONE); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_FALSE(response->headers == NULL); - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_EQ(5, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - - // The password prompt info should not be set. - EXPECT_TRUE(response->auth_challenge.get() == NULL); - - trans.reset(); - session->CloseAllConnections(); -} - -// Test the request-challenge-retry sequence for basic auth, over a keep-alive -// proxy connection, when setting up an SSL tunnel. -TEST_F(HttpNetworkTransactionSpdy21Test, BasicAuthProxyKeepAlive) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - // Ensure that proxy authentication is attempted even - // when the no authentication data flag is set. - request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; - - // Configure against proxy server "myproxy:70". - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - // Since we have proxy, should try to establish tunnel. - MockWrite data_writes1[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"), - }; - - // The proxy responds to the connect with a 407, using a persistent - // connection. - MockRead data_reads1[] = { - // No credentials. - MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Length: 10\r\n\r\n"), - MockRead("0123456789"), - - // Wrong credentials (wrong password). - MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Length: 10\r\n\r\n"), - // No response body because the test stops reading here. - MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. - }; - - 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.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - net::CapturingNetLog::EntryList entries; - log.GetEntries(&entries); - size_t pos = ExpectLogContainsSomewhere( - entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - NetLog::PHASE_NONE); - ExpectLogContainsSomewhere( - entries, pos, - NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - NetLog::PHASE_NONE); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_FALSE(response->headers == NULL); - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_EQ(10, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - // Wrong password (should be "bar"). - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBaz), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_FALSE(response->headers == NULL); - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_EQ(10, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); - - // Flush the idle socket before the NetLog and HttpNetworkTransaction go - // out of scope. - session->CloseAllConnections(); -} - -// Test that we don't read the response body when we fail to establish a tunnel, -// even if the user cancels the proxy's auth attempt. -TEST_F(HttpNetworkTransactionSpdy21Test, BasicAuthProxyCancelTunnel) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - // Configure against proxy server "myproxy:70". - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - // Since we have proxy, should try to establish tunnel. - MockWrite data_writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - - // The proxy responds to the connect with a 407. - MockRead data_reads[] = { - MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Length: 10\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_EQ(10, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); - - // Flush the idle socket before the HttpNetworkTransaction goes out of scope. - session->CloseAllConnections(); -} - -// Test when a server (non-proxy) returns a 407 (proxy-authenticate). -// The request should fail with ERR_UNEXPECTED_PROXY_AUTH. -TEST_F(HttpNetworkTransactionSpdy21Test, UnexpectedProxyAuth) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - // We are using a DIRECT connection (i.e. no proxy) for this session. - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes1[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.0 407 Proxy Auth required\r\n"), - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - // Large content-length -- won't matter, as connection will be reset. - MockRead("Content-Length: 10000\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); -} - -// Tests when an HTTPS server (non-proxy) returns a 407 (proxy-authentication) -// through a non-authenticating proxy. The request should fail with -// ERR_UNEXPECTED_PROXY_AUTH. -// Note that it is impossible to detect if an HTTP server returns a 407 through -// a non-authenticating proxy - there is nothing to indicate whether the -// response came from the proxy or the server, so it is treated as if the proxy -// issued the challenge. -TEST_F(HttpNetworkTransactionSpdy21Test, - HttpsServerRequestsProxyAuthThroughProxy) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Since we have proxy, should try to establish tunnel. - MockWrite data_writes1[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), - - MockRead("HTTP/1.1 407 Unauthorized\r\n"), - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - SSLSocketDataProvider ssl(ASYNC, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(ERR_UNEXPECTED_PROXY_AUTH, rv); - net::CapturingNetLog::EntryList entries; - log.GetEntries(&entries); - size_t pos = ExpectLogContainsSomewhere( - entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - NetLog::PHASE_NONE); - ExpectLogContainsSomewhere( - entries, pos, - NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - NetLog::PHASE_NONE); -} - -// Test a simple get through an HTTPS Proxy. -TEST_F(HttpNetworkTransactionSpdy21Test, HttpsProxyGet) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - - // Configure against https proxy server "proxy:70". - SessionDependencies session_deps(ProxyService::CreateFixed( - "https://proxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Since we have proxy, should use full url - MockWrite data_writes1[] = { - MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - SSLSocketDataProvider ssl(ASYNC, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_EQ(100, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - - // The password prompt info should not be set. - EXPECT_TRUE(response->auth_challenge.get() == NULL); -} - -// Test a SPDY get through an HTTPS Proxy. -TEST_F(HttpNetworkTransactionSpdy21Test, HttpsProxySpdyGet) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - // Configure against https proxy server "proxy:70". - SessionDependencies session_deps(ProxyService::CreateFixed( - "https://proxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // fetch http://www.google.com/ via SPDY - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST, - false)); - MockWrite spdy_writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); - MockRead spdy_reads[] = { - CreateMockRead(*resp), - CreateMockRead(*data), - MockRead(ASYNC, 0, 0), - }; - - scoped_ptr<DelayedSocketData> spdy_data( - new DelayedSocketData( - 1, // wait for one write to finish before reading. - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ(kUploadData, response_data); -} - -// Test a SPDY get through an HTTPS Proxy. -TEST_F(HttpNetworkTransactionSpdy21Test, HttpsProxySpdyGetWithProxyAuth) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - // Configure against https proxy server "myproxy:70". - SessionDependencies session_deps( - ProxyService::CreateFixed("https://myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // The first request will be a bare GET, the second request will be a - // GET with a Proxy-Authorization header. - scoped_ptr<SpdyFrame> req_get( - ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false)); - const char* const kExtraAuthorizationHeaders[] = { - "proxy-authorization", - "Basic Zm9vOmJhcg==", - }; - scoped_ptr<SpdyFrame> req_get_authorization( - ConstructSpdyGet( - kExtraAuthorizationHeaders, arraysize(kExtraAuthorizationHeaders)/2, - false, 3, LOWEST, false)); - MockWrite spdy_writes[] = { - CreateMockWrite(*req_get, 1), - CreateMockWrite(*req_get_authorization, 4), - }; - - // The first response is a 407 proxy authentication challenge, and the second - // response will be a 200 response since the second request includes a valid - // Authorization header. - const char* const kExtraAuthenticationHeaders[] = { - "proxy-authenticate", - "Basic realm=\"MyRealm1\"" - }; - scoped_ptr<SpdyFrame> resp_authentication( - ConstructSpdySynReplyError( - "407 Proxy Authentication Required", - kExtraAuthenticationHeaders, arraysize(kExtraAuthenticationHeaders)/2, - 1)); - scoped_ptr<SpdyFrame> body_authentication( - ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> resp_data(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> body_data(ConstructSpdyBodyFrame(3, true)); - MockRead spdy_reads[] = { - CreateMockRead(*resp_authentication, 2), - CreateMockRead(*body_authentication, 3), - CreateMockRead(*resp_data, 5), - CreateMockRead(*body_data, 6), - MockRead(ASYNC, 0, 7), - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(data.get()); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* const response = trans->GetResponseInfo(); - - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_TRUE(response->was_fetched_via_spdy); - EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* const response_restart = trans->GetResponseInfo(); - - ASSERT_TRUE(response_restart != NULL); - ASSERT_TRUE(response_restart->headers != NULL); - EXPECT_EQ(200, response_restart->headers->response_code()); - // The password prompt info should not be set. - EXPECT_TRUE(response_restart->auth_challenge.get() == NULL); -} - -// Test a SPDY CONNECT through an HTTPS Proxy to an HTTPS (non-SPDY) Server. -TEST_F(HttpNetworkTransactionSpdy21Test, HttpsProxySpdyConnectHttps) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - // Configure against https proxy server "proxy:70". - SessionDependencies session_deps(ProxyService::CreateFixed( - "https://proxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - // CONNECT to www.google.com:443 via SPDY - scoped_ptr<SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); - // fetch https://www.google.com/ via HTTP - - const char get[] = "GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"; - scoped_ptr<SpdyFrame> wrapped_get( - ConstructSpdyBodyFrame(1, get, strlen(get), false)); - scoped_ptr<SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - const char resp[] = "HTTP/1.1 200 OK\r\n" - "Content-Length: 10\r\n\r\n"; - scoped_ptr<SpdyFrame> wrapped_get_resp( - ConstructSpdyBodyFrame(1, resp, strlen(resp), false)); - scoped_ptr<SpdyFrame> wrapped_body( - ConstructSpdyBodyFrame(1, "1234567890", 10, false)); - scoped_ptr<SpdyFrame> window_update( - ConstructSpdyWindowUpdate(1, wrapped_get_resp->length())); - - MockWrite spdy_writes[] = { - CreateMockWrite(*connect, 1), - CreateMockWrite(*wrapped_get, 3), - CreateMockWrite(*window_update, 5) - }; - - MockRead spdy_reads[] = { - CreateMockRead(*conn_resp, 2, ASYNC), - CreateMockRead(*wrapped_get_resp, 4, ASYNC), - CreateMockRead(*wrapped_body, 6, ASYNC), - CreateMockRead(*wrapped_body, 7, ASYNC), - MockRead(ASYNC, 0, 8), - }; - - scoped_ptr<OrderedSocketData> spdy_data( - new OrderedSocketData( - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - SSLSocketDataProvider ssl2(ASYNC, OK); - ssl2.was_npn_negotiated = false; - ssl2.protocol_negotiated = kProtoUnknown; - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("1234567890", response_data); -} - -// Test a SPDY CONNECT through an HTTPS Proxy to a SPDY server. -TEST_F(HttpNetworkTransactionSpdy21Test, HttpsProxySpdyConnectSpdy) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - // Configure against https proxy server "proxy:70". - SessionDependencies session_deps(ProxyService::CreateFixed( - "https://proxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - // CONNECT to www.google.com:443 via SPDY - scoped_ptr<SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); - // fetch https://www.google.com/ via SPDY - const char* const kMyUrl = "https://www.google.com/"; - scoped_ptr<SpdyFrame> get(ConstructSpdyGet(kMyUrl, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> wrapped_get(ConstructWrappedSpdyFrame(get, 1)); - scoped_ptr<SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> get_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> wrapped_get_resp( - ConstructWrappedSpdyFrame(get_resp, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> wrapped_body(ConstructWrappedSpdyFrame(body, 1)); - scoped_ptr<SpdyFrame> window_update_get_resp( - ConstructSpdyWindowUpdate(1, wrapped_get_resp->length())); - scoped_ptr<SpdyFrame> window_update_body( - ConstructSpdyWindowUpdate(1, wrapped_body->length())); - - MockWrite spdy_writes[] = { - CreateMockWrite(*connect, 1), - CreateMockWrite(*wrapped_get, 3), - CreateMockWrite(*window_update_get_resp, 5), - CreateMockWrite(*window_update_body, 7), - }; - - MockRead spdy_reads[] = { - CreateMockRead(*conn_resp, 2, ASYNC), - CreateMockRead(*wrapped_get_resp, 4, ASYNC), - CreateMockRead(*wrapped_body, 6, ASYNC), - MockRead(ASYNC, 0, 8), - }; - - scoped_ptr<OrderedSocketData> spdy_data( - new OrderedSocketData( - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - SSLSocketDataProvider ssl2(ASYNC, OK); - ssl2.SetNextProto(kProtoSPDY21); - ssl2.protocol_negotiated = kProtoSPDY21; - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ(kUploadData, response_data); -} - -// Test a SPDY CONNECT failure through an HTTPS Proxy. -TEST_F(HttpNetworkTransactionSpdy21Test, HttpsProxySpdyConnectFailure) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - // Configure against https proxy server "proxy:70". - SessionDependencies session_deps(ProxyService::CreateFixed( - "https://proxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - // CONNECT to www.google.com:443 via SPDY - scoped_ptr<SpdyFrame> connect(ConstructSpdyConnect(NULL, 0, 1)); - scoped_ptr<SpdyFrame> get(ConstructSpdyRstStream(1, CANCEL)); - - MockWrite spdy_writes[] = { - CreateMockWrite(*connect, 1), - CreateMockWrite(*get, 3), - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdySynReplyError(1)); - scoped_ptr<SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); - MockRead spdy_reads[] = { - CreateMockRead(*resp, 2, ASYNC), - MockRead(ASYNC, 0, 4), - }; - - scoped_ptr<OrderedSocketData> spdy_data( - new OrderedSocketData( - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - SSLSocketDataProvider ssl2(ASYNC, OK); - ssl2.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_EQ(500, response->headers->response_code()); -} - -// Test the challenge-response-retry sequence through an HTTPS Proxy -TEST_F(HttpNetworkTransactionSpdy21Test, HttpsProxyAuthRetry) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - // when the no authentication data flag is set. - request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; - - // Configure against https proxy server "myproxy:70". - SessionDependencies session_deps( - ProxyService::CreateFixed("https://myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Since we have proxy, should use full url - MockWrite data_writes1[] = { - MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - // The proxy responds to the GET with a 407, using a persistent - // connection. - MockRead data_reads1[] = { - // No credentials. - MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Proxy-Connection: keep-alive\r\n"), - MockRead("Content-Length: 0\r\n\r\n"), - - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - SSLSocketDataProvider ssl(ASYNC, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_FALSE(response->headers == NULL); - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_EQ(100, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - - // The password prompt info should not be set. - EXPECT_TRUE(response->auth_challenge.get() == NULL); -} - -void HttpNetworkTransactionSpdy21Test::ConnectStatusHelperWithExpectedStatus( - const MockRead& status, int expected_status) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - // Configure against proxy server "myproxy:70". - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Since we have proxy, should try to establish tunnel. - MockWrite data_writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads[] = { - status, - MockRead("Content-Length: 10\r\n\r\n"), - // No response body because the test stops reading here. - MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(expected_status, rv); -} - -void HttpNetworkTransactionSpdy21Test::ConnectStatusHelper( - const MockRead& status) { - ConnectStatusHelperWithExpectedStatus( - status, ERR_TUNNEL_CONNECTION_FAILED); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus100) { - ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus101) { - ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus201) { - ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus202) { - ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus203) { - ConnectStatusHelper( - MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus204) { - ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus205) { - ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus206) { - ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus300) { - ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus301) { - ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus302) { - ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus303) { - ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus304) { - ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus305) { - ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus306) { - ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus307) { - ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus400) { - ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus401) { - ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus402) { - ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus403) { - ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus404) { - ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus405) { - ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus406) { - ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus407) { - ConnectStatusHelperWithExpectedStatus( - MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), - ERR_PROXY_AUTH_UNSUPPORTED); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus408) { - ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus409) { - ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus410) { - ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus411) { - ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus412) { - ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus413) { - ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus414) { - ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus415) { - ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus416) { - ConnectStatusHelper( - MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus417) { - ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus500) { - ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus501) { - ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus502) { - ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus503) { - ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus504) { - ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n")); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectStatus505) { - ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n")); -} - -// Test the flow when both the proxy server AND origin server require -// authentication. Again, this uses basic auth for both since that is -// the simplest to mock. -TEST_F(HttpNetworkTransactionSpdy21Test, BasicAuthProxyThenServer) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - - // Configure against proxy server "myproxy:70". - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction( - CreateSession(&session_deps))); - - MockWrite data_writes1[] = { - MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.0 407 Unauthorized\r\n"), - // Give a couple authenticate options (only the middle one is actually - // supported). - MockRead("Proxy-Authenticate: Basic invalid\r\n"), // Malformed. - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - // Large content-length -- won't matter, as connection will be reset. - MockRead("Content-Length: 10000\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - // After calling trans->RestartWithAuth() the first time, this is the - // request we should be issuing -- the final header line contains the - // proxy's credentials. - MockWrite data_writes2[] = { - MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - // Now the proxy server lets the request pass through to origin server. - // The origin server responds with a 401. - MockRead data_reads2[] = { - MockRead("HTTP/1.0 401 Unauthorized\r\n"), - // Note: We are using the same realm-name as the proxy server. This is - // completely valid, as realms are unique across hosts. - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 2000\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_FAILED), // Won't be reached. - }; - - // After calling trans->RestartWithAuth() the second time, we should send - // the credentials for both the proxy and origin server. - MockWrite data_writes3[] = { - MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n" - "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), - }; - - // Lastly we get the desired content. - MockRead data_reads3[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), - data_writes3, arraysize(data_writes3)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - session_deps.socket_factory.AddSocketDataProvider(&data3); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback3; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo2, kBar2), callback3.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback3.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(100, response->headers->GetContentLength()); -} - -// For the NTLM implementation using SSPI, we skip the NTLM tests since we -// can't hook into its internals to cause it to generate predictable NTLM -// authorization headers. -#if defined(NTLM_PORTABLE) -// The NTLM authentication unit tests were generated by capturing the HTTP -// requests and responses using Fiddler 2 and inspecting the generated random -// bytes in the debugger. - -// Enter the correct password and authenticate successfully. -TEST_F(HttpNetworkTransactionSpdy21Test, NTLMAuth1) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://172.22.68.17/kids/login.aspx"); - request.load_flags = 0; - - HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom1, - MockGetHostName); - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - MockWrite data_writes1[] = { - MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" - "Host: 172.22.68.17\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.1 401 Access Denied\r\n"), - // Negotiate and NTLM are often requested together. However, we only want - // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip - // the header that requests Negotiate for this test. - MockRead("WWW-Authenticate: NTLM\r\n"), - MockRead("Connection: close\r\n"), - MockRead("Content-Length: 42\r\n"), - MockRead("Content-Type: text/html\r\n\r\n"), - // Missing content -- won't matter, as connection will be reset. - MockRead(SYNCHRONOUS, ERR_UNEXPECTED), - }; - - MockWrite data_writes2[] = { - // After restarting with a null identity, this is the - // request we should be issuing -- the final header line contains a Type - // 1 message. - MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" - "Host: 172.22.68.17\r\n" - "Connection: keep-alive\r\n" - "Authorization: NTLM " - "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), - - // After calling trans->RestartWithAuth(), we should send a Type 3 message - // (the credentials for the origin server). The second request continues - // on the same connection. - MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" - "Host: 172.22.68.17\r\n" - "Connection: keep-alive\r\n" - "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" - "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" - "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBVKW" - "Yma5xzVAAAAAAAAAAAAAAAAAAAAACH+gWcm+YsP9Tqb9zCR3WAeZZX" - "ahlhx5I=\r\n\r\n"), - }; - - MockRead data_reads2[] = { - // The origin server responds with a Type 2 message. - MockRead("HTTP/1.1 401 Access Denied\r\n"), - MockRead("WWW-Authenticate: NTLM " - "TlRMTVNTUAACAAAADAAMADgAAAAFgokCjGpMpPGlYKkAAAAAAAAAALo" - "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" - "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" - "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" - "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" - "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" - "BtAAAAAAA=\r\n"), - MockRead("Content-Length: 42\r\n"), - MockRead("Content-Type: text/html\r\n\r\n"), - MockRead("You are not authorized to view this page\r\n"), - - // Lastly we get the desired content. - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=utf-8\r\n"), - MockRead("Content-Length: 13\r\n\r\n"), - MockRead("Please Login\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - EXPECT_FALSE(trans->IsReadyToRestartForAuth()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_FALSE(response == NULL); - EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM), - callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - EXPECT_TRUE(trans->IsReadyToRestartForAuth()); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - - TestCompletionCallback callback3; - - rv = trans->RestartWithAuth(AuthCredentials(), callback3.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback3.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(13, response->headers->GetContentLength()); -} - -// Enter a wrong password, and then the correct one. -TEST_F(HttpNetworkTransactionSpdy21Test, NTLMAuth2) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://172.22.68.17/kids/login.aspx"); - request.load_flags = 0; - - HttpAuthHandlerNTLM::ScopedProcSetter proc_setter(MockGenerateRandom2, - MockGetHostName); - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - MockWrite data_writes1[] = { - MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" - "Host: 172.22.68.17\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.1 401 Access Denied\r\n"), - // Negotiate and NTLM are often requested together. However, we only want - // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip - // the header that requests Negotiate for this test. - MockRead("WWW-Authenticate: NTLM\r\n"), - MockRead("Connection: close\r\n"), - MockRead("Content-Length: 42\r\n"), - MockRead("Content-Type: text/html\r\n\r\n"), - // Missing content -- won't matter, as connection will be reset. - MockRead(SYNCHRONOUS, ERR_UNEXPECTED), - }; - - MockWrite data_writes2[] = { - // After restarting with a null identity, this is the - // request we should be issuing -- the final header line contains a Type - // 1 message. - MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" - "Host: 172.22.68.17\r\n" - "Connection: keep-alive\r\n" - "Authorization: NTLM " - "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), - - // After calling trans->RestartWithAuth(), we should send a Type 3 message - // (the credentials for the origin server). The second request continues - // on the same connection. - MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" - "Host: 172.22.68.17\r\n" - "Connection: keep-alive\r\n" - "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" - "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" - "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwCWeY" - "XnSZNwoQAAAAAAAAAAAAAAAAAAAADLa34/phTTKzNTWdub+uyFleOj" - "4Ww7b7E=\r\n\r\n"), - }; - - MockRead data_reads2[] = { - // The origin server responds with a Type 2 message. - MockRead("HTTP/1.1 401 Access Denied\r\n"), - MockRead("WWW-Authenticate: NTLM " - "TlRMTVNTUAACAAAADAAMADgAAAAFgokCbVWUZezVGpAAAAAAAAAAALo" - "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" - "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" - "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" - "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" - "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" - "BtAAAAAAA=\r\n"), - MockRead("Content-Length: 42\r\n"), - MockRead("Content-Type: text/html\r\n\r\n"), - MockRead("You are not authorized to view this page\r\n"), - - // Wrong password. - MockRead("HTTP/1.1 401 Access Denied\r\n"), - MockRead("WWW-Authenticate: NTLM\r\n"), - MockRead("Connection: close\r\n"), - MockRead("Content-Length: 42\r\n"), - MockRead("Content-Type: text/html\r\n\r\n"), - // Missing content -- won't matter, as connection will be reset. - MockRead(SYNCHRONOUS, ERR_UNEXPECTED), - }; - - MockWrite data_writes3[] = { - // After restarting with a null identity, this is the - // request we should be issuing -- the final header line contains a Type - // 1 message. - MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" - "Host: 172.22.68.17\r\n" - "Connection: keep-alive\r\n" - "Authorization: NTLM " - "TlRMTVNTUAABAAAAB4IIAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n"), - - // After calling trans->RestartWithAuth(), we should send a Type 3 message - // (the credentials for the origin server). The second request continues - // on the same connection. - MockWrite("GET /kids/login.aspx HTTP/1.1\r\n" - "Host: 172.22.68.17\r\n" - "Connection: keep-alive\r\n" - "Authorization: NTLM TlRMTVNTUAADAAAAGAAYAGgAAAAYABgAgA" - "AAAAAAAABAAAAAGAAYAEAAAAAQABAAWAAAAAAAAAAAAAAABYIIAHQA" - "ZQBzAHQAaQBuAGcALQBuAHQAbABtAFcAVABDAC0AVwBJAE4ANwBO54" - "dFMVvTHwAAAAAAAAAAAAAAAAAAAACS7sT6Uzw7L0L//WUqlIaVWpbI" - "+4MUm7c=\r\n\r\n"), - }; - - MockRead data_reads3[] = { - // The origin server responds with a Type 2 message. - MockRead("HTTP/1.1 401 Access Denied\r\n"), - MockRead("WWW-Authenticate: NTLM " - "TlRMTVNTUAACAAAADAAMADgAAAAFgokCL24VN8dgOR8AAAAAAAAAALo" - "AugBEAAAABQEoCgAAAA9HAE8ATwBHAEwARQACAAwARwBPAE8ARwBMAE" - "UAAQAaAEEASwBFAEUAUwBBAFIAQQAtAEMATwBSAFAABAAeAGMAbwByA" - "HAALgBnAG8AbwBnAGwAZQAuAGMAbwBtAAMAQABhAGsAZQBlAHMAYQBy" - "AGEALQBjAG8AcgBwAC4AYQBkAC4AYwBvAHIAcAAuAGcAbwBvAGcAbAB" - "lAC4AYwBvAG0ABQAeAGMAbwByAHAALgBnAG8AbwBnAGwAZQAuAGMAbw" - "BtAAAAAAA=\r\n"), - MockRead("Content-Length: 42\r\n"), - MockRead("Content-Type: text/html\r\n\r\n"), - MockRead("You are not authorized to view this page\r\n"), - - // Lastly we get the desired content. - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=utf-8\r\n"), - MockRead("Content-Length: 13\r\n\r\n"), - MockRead("Please Login\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), - data_writes3, arraysize(data_writes3)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - session_deps.socket_factory.AddSocketDataProvider(&data3); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - EXPECT_FALSE(trans->IsReadyToRestartForAuth()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - // Enter the wrong password. - rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kWrongPassword), - callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - EXPECT_TRUE(trans->IsReadyToRestartForAuth()); - TestCompletionCallback callback3; - rv = trans->RestartWithAuth(AuthCredentials(), callback3.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback3.WaitForResult(); - EXPECT_EQ(OK, rv); - EXPECT_FALSE(trans->IsReadyToRestartForAuth()); - - response = trans->GetResponseInfo(); - ASSERT_FALSE(response == NULL); - EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback4; - - // Now enter the right password. - rv = trans->RestartWithAuth(AuthCredentials(kTestingNTLM, kTestingNTLM), - callback4.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback4.WaitForResult(); - EXPECT_EQ(OK, rv); - - EXPECT_TRUE(trans->IsReadyToRestartForAuth()); - - TestCompletionCallback callback5; - - // One more roundtrip - rv = trans->RestartWithAuth(AuthCredentials(), callback5.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback5.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(13, response->headers->GetContentLength()); -} -#endif // NTLM_PORTABLE - -// Test reading a server response which has only headers, and no body. -// After some maximum number of bytes is consumed, the transaction should -// fail with ERR_RESPONSE_HEADERS_TOO_BIG. -TEST_F(HttpNetworkTransactionSpdy21Test, LargeHeadersNoBody) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - // Respond with 300 kb of headers (we should fail after 256 kb). - std::string large_headers_string; - FillLargeHeadersString(&large_headers_string, 300 * 1024); - - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead(ASYNC, large_headers_string.data(), large_headers_string.size()), - MockRead("\r\nBODY"), - MockRead(SYNCHRONOUS, OK), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(ERR_RESPONSE_HEADERS_TOO_BIG, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - EXPECT_TRUE(response == NULL); -} - -// Make sure that we don't try to reuse a TCPClientSocket when failing to -// establish tunnel. -// http://code.google.com/p/chromium/issues/detail?id=3772 -TEST_F(HttpNetworkTransactionSpdy21Test, - DontRecycleTransportSocketForSSLTunnel) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - // Configure against proxy server "myproxy:70". - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - // Since we have proxy, should try to establish tunnel. - MockWrite data_writes1[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - - // The proxy responds to the connect with a 404, using a persistent - // connection. Usually a proxy would return 501 (not implemented), - // or 200 (tunnel established). - MockRead data_reads1[] = { - MockRead("HTTP/1.1 404 Not Found\r\n"), - MockRead("Content-Length: 10\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached. - }; - - 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.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - EXPECT_TRUE(response == NULL); - - // Empty the current queue. This is necessary because idle sockets are - // added to the connection pool asynchronously with a PostTask. - MessageLoop::current()->RunAllPending(); - - // We now check to make sure the TCPClientSocket was not added back to - // the pool. - EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session)); - trans.reset(); - MessageLoop::current()->RunAllPending(); - // Make sure that the socket didn't get recycled after calling the destructor. - EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session)); -} - -// Make sure that we recycle a socket after reading all of the response body. -TEST_F(HttpNetworkTransactionSpdy21Test, RecycleSocket) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - MockRead data_reads[] = { - // A part of the response body is received with the response headers. - MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"), - // The rest of the response body is received in two parts. - MockRead("lo"), - MockRead(" world"), - MockRead("junk"), // Should not be read!! - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers != NULL); - std::string status_line = response->headers->GetStatusLine(); - EXPECT_EQ("HTTP/1.1 200 OK", status_line); - - EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session)); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("hello world", response_data); - - // Empty the current queue. This is necessary because idle sockets are - // added to the connection pool asynchronously with a PostTask. - MessageLoop::current()->RunAllPending(); - - // We now check to make sure the socket was added back to the pool. - EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session)); -} - -// Make sure that we recycle a SSL socket after reading all of the response -// body. -TEST_F(HttpNetworkTransactionSpdy21Test, RecycleSSLSocket) { - SessionDependencies session_deps; - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - MockWrite data_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Length: 11\r\n\r\n"), - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - - SSLSocketDataProvider ssl(ASYNC, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session)); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("hello world", response_data); - - // Empty the current queue. This is necessary because idle sockets are - // added to the connection pool asynchronously with a PostTask. - MessageLoop::current()->RunAllPending(); - - // We now check to make sure the socket was added back to the pool. - EXPECT_EQ(1, GetIdleSocketCountInSSLSocketPool(session)); -} - -// Grab a SSL socket, use it, and put it back into the pool. Then, reuse it -// from the pool and make sure that we recover okay. -TEST_F(HttpNetworkTransactionSpdy21Test, RecycleDeadSSLSocket) { - SessionDependencies session_deps; - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - MockWrite data_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Length: 11\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), - MockRead("hello world"), - MockRead(ASYNC, 0, 0) // EOF - }; - - SSLSocketDataProvider ssl(ASYNC, OK); - SSLSocketDataProvider ssl2(ASYNC, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl2); - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - StaticSocketDataProvider data2(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback; - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session)); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("hello world", response_data); - - // Empty the current queue. This is necessary because idle sockets are - // added to the connection pool asynchronously with a PostTask. - MessageLoop::current()->RunAllPending(); - - // We now check to make sure the socket was added back to the pool. - EXPECT_EQ(1, GetIdleSocketCountInSSLSocketPool(session)); - - // Now start the second transaction, which should reuse the previous socket. - - trans.reset(new HttpNetworkTransaction(session)); - - rv = trans->Start(&request, callback.callback(), BoundNetLog()); - - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session)); - - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("hello world", response_data); - - // Empty the current queue. This is necessary because idle sockets are - // added to the connection pool asynchronously with a PostTask. - MessageLoop::current()->RunAllPending(); - - // We now check to make sure the socket was added back to the pool. - EXPECT_EQ(1, GetIdleSocketCountInSSLSocketPool(session)); -} - -// Make sure that we recycle a socket after a zero-length response. -// http://crbug.com/9880 -TEST_F(HttpNetworkTransactionSpdy21Test, RecycleSocketAfterZeroContentLength) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/csi?v=3&s=web&action=&" - "tran=undefined&ei=mAXcSeegAo-SMurloeUN&" - "e=17259,18167,19592,19773,19981,20133,20173,20233&" - "rt=prt.2642,ol.2649,xjs.2951"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - MockRead data_reads[] = { - MockRead("HTTP/1.1 204 No Content\r\n" - "Content-Length: 0\r\n" - "Content-Type: text/html\r\n\r\n"), - MockRead("junk"), // Should not be read!! - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers != NULL); - std::string status_line = response->headers->GetStatusLine(); - EXPECT_EQ("HTTP/1.1 204 No Content", status_line); - - EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session)); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("", response_data); - - // Empty the current queue. This is necessary because idle sockets are - // added to the connection pool asynchronously with a PostTask. - MessageLoop::current()->RunAllPending(); - - // We now check to make sure the socket was added back to the pool. - EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session)); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ResendRequestOnWriteBodyError) { - HttpRequestInfo request[2]; - // Transaction 1: a GET request that succeeds. The socket is recycled - // after use. - request[0].method = "GET"; - request[0].url = GURL("http://www.google.com/"); - request[0].load_flags = 0; - // Transaction 2: a POST request. Reuses the socket kept alive from - // transaction 1. The first attempts fails when writing the POST data. - // This causes the transaction to retry with a new socket. The second - // attempt succeeds. - request[1].method = "POST"; - request[1].url = GURL("http://www.google.com/login.cgi"); - request[1].upload_data = new UploadData; - request[1].upload_data->AppendBytes("foo", 3); - request[1].load_flags = 0; - - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // The first socket is used for transaction 1 and the first attempt of - // transaction 2. - - // The response of transaction 1. - MockRead data_reads1[] = { - MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"), - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - // The mock write results of transaction 1 and the first attempt of - // transaction 2. - MockWrite data_writes1[] = { - MockWrite(SYNCHRONOUS, 64), // GET - MockWrite(SYNCHRONOUS, 93), // POST - MockWrite(SYNCHRONOUS, ERR_CONNECTION_ABORTED), // POST data - }; - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - - // The second socket is used for the second attempt of transaction 2. - - // The response of transaction 2. - MockRead data_reads2[] = { - MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"), - MockRead("welcome"), - MockRead(SYNCHRONOUS, OK), - }; - // The mock write results of the second attempt of transaction 2. - MockWrite data_writes2[] = { - MockWrite(SYNCHRONOUS, 93), // POST - MockWrite(SYNCHRONOUS, 3), // POST data - }; - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - const char* kExpectedResponseData[] = { - "hello world", "welcome" - }; - - for (int i = 0; i < 2; ++i) { - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(session)); - - TestCompletionCallback callback; - - int rv = trans->Start(&request[i], callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ(kExpectedResponseData[i], response_data); - } -} - -// Test the request-challenge-retry sequence for basic auth when there is -// an identity in the URL. The request should be sent as normal, but when -// it fails the identity from the URL is no longer used. -TEST_F(HttpNetworkTransactionSpdy21Test, IgnoreAuthIdentityInURL) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://foo:b@r@www.google.com/"); - request.load_flags = LOAD_NORMAL; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - // The password contains an escaped character -- for this test to pass it - // will need to be unescaped by HttpNetworkTransaction. - EXPECT_EQ("b%40r", request.url.password()); - - MockWrite data_writes1[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.0 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Length: 10\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - 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.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - EXPECT_FALSE(trans->IsReadyToRestartForAuth()); - - // Empty the current queue. - MessageLoop::current()->RunAllPending(); -} - -// Test that previously tried username/passwords for a realm get re-used. -TEST_F(HttpNetworkTransactionSpdy21Test, BasicAuthCacheAndPreauth) { - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Transaction 1: authenticate (foo, bar) on MyRealm1 - { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/x/y/z"); - request.load_flags = 0; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - MockWrite data_writes1[] = { - MockWrite("GET /x/y/z HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.0 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Length: 10000\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - // Resend with authorization (username=foo, password=bar) - MockWrite data_writes2[] = { - MockWrite("GET /x/y/z HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - // Sever accepts the authorization. - MockRead data_reads2[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(100, response->headers->GetContentLength()); - } - - // ------------------------------------------------------------------------ - - // Transaction 2: authenticate (foo2, bar2) on MyRealm2 - { - HttpRequestInfo request; - request.method = "GET"; - // Note that Transaction 1 was at /x/y/z, so this is in the same - // protection space as MyRealm1. - request.url = GURL("http://www.google.com/x/y/a/b"); - request.load_flags = 0; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - MockWrite data_writes1[] = { - MockWrite("GET /x/y/a/b HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - // Send preemptive authorization for MyRealm1 - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - // The server didn't like the preemptive authorization, and - // challenges us for a different realm (MyRealm2). - MockRead data_reads1[] = { - MockRead("HTTP/1.0 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"), - MockRead("Content-Length: 10000\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - // Resend with authorization for MyRealm2 (username=foo2, password=bar2) - MockWrite data_writes2[] = { - MockWrite("GET /x/y/a/b HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"), - }; - - // Sever accepts the authorization. - MockRead data_reads2[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->auth_challenge.get()); - EXPECT_FALSE(response->auth_challenge->is_proxy); - EXPECT_EQ("www.google.com:80", - response->auth_challenge->challenger.ToString()); - EXPECT_EQ("MyRealm2", response->auth_challenge->realm); - EXPECT_EQ("basic", response->auth_challenge->scheme); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo2, kBar2), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(100, response->headers->GetContentLength()); - } - - // ------------------------------------------------------------------------ - - // Transaction 3: Resend a request in MyRealm's protection space -- - // succeed with preemptive authorization. - { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/x/y/z2"); - request.load_flags = 0; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - MockWrite data_writes1[] = { - MockWrite("GET /x/y/z2 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - // The authorization for MyRealm1 gets sent preemptively - // (since the url is in the same protection space) - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - // Sever accepts the preemptive authorization - MockRead data_reads1[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - 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.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(100, response->headers->GetContentLength()); - } - - // ------------------------------------------------------------------------ - - // Transaction 4: request another URL in MyRealm (however the - // url is not known to belong to the protection space, so no pre-auth). - { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/x/1"); - request.load_flags = 0; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - MockWrite data_writes1[] = { - MockWrite("GET /x/1 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.0 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Length: 10000\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - // Resend with authorization from MyRealm's cache. - MockWrite data_writes2[] = { - MockWrite("GET /x/1 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - // Sever accepts the authorization. - MockRead data_reads2[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - EXPECT_TRUE(trans->IsReadyToRestartForAuth()); - TestCompletionCallback callback2; - rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - EXPECT_FALSE(trans->IsReadyToRestartForAuth()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(100, response->headers->GetContentLength()); - } - - // ------------------------------------------------------------------------ - - // Transaction 5: request a URL in MyRealm, but the server rejects the - // cached identity. Should invalidate and re-prompt. - { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/p/q/t"); - request.load_flags = 0; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - MockWrite data_writes1[] = { - MockWrite("GET /p/q/t HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.0 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Length: 10000\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - // Resend with authorization from cache for MyRealm. - MockWrite data_writes2[] = { - MockWrite("GET /p/q/t HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - // Sever rejects the authorization. - MockRead data_reads2[] = { - MockRead("HTTP/1.0 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Length: 10000\r\n\r\n"), - MockRead(SYNCHRONOUS, ERR_FAILED), - }; - - // At this point we should prompt for new credentials for MyRealm. - // Restart with username=foo3, password=foo4. - MockWrite data_writes3[] = { - MockWrite("GET /p/q/t HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"), - }; - - // Sever accepts the authorization. - MockRead data_reads3[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), - data_writes3, arraysize(data_writes3)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - session_deps.socket_factory.AddSocketDataProvider(&data3); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - EXPECT_TRUE(trans->IsReadyToRestartForAuth()); - TestCompletionCallback callback2; - rv = trans->RestartWithAuth(AuthCredentials(), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - EXPECT_FALSE(trans->IsReadyToRestartForAuth()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback3; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo3, kBar3), callback3.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback3.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(100, response->headers->GetContentLength()); - } -} - -// Tests that nonce count increments when multiple auth attempts -// are started with the same nonce. -TEST_F(HttpNetworkTransactionSpdy21Test, DigestPreAuthNonceCount) { - SessionDependencies session_deps; - HttpAuthHandlerDigest::Factory* digest_factory = - new HttpAuthHandlerDigest::Factory(); - HttpAuthHandlerDigest::FixedNonceGenerator* nonce_generator = - new HttpAuthHandlerDigest::FixedNonceGenerator("0123456789abcdef"); - digest_factory->set_nonce_generator(nonce_generator); - session_deps.http_auth_handler_factory.reset(digest_factory); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Transaction 1: authenticate (foo, bar) on MyRealm1 - { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/x/y/z"); - request.load_flags = 0; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - MockWrite data_writes1[] = { - MockWrite("GET /x/y/z HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.0 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Digest realm=\"digestive\", nonce=\"OU812\", " - "algorithm=MD5, qop=\"auth\"\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - // Resend with authorization (username=foo, password=bar) - MockWrite data_writes2[] = { - MockWrite("GET /x/y/z HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Digest username=\"foo\", realm=\"digestive\", " - "nonce=\"OU812\", uri=\"/x/y/z\", algorithm=MD5, " - "response=\"03ffbcd30add722589c1de345d7a927f\", qop=auth, " - "nc=00000001, cnonce=\"0123456789abcdef\"\r\n\r\n"), - }; - - // Sever accepts the authorization. - MockRead data_reads2[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckDigestServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - } - - // ------------------------------------------------------------------------ - - // Transaction 2: Request another resource in digestive's protection space. - // This will preemptively add an Authorization header which should have an - // "nc" value of 2 (as compared to 1 in the first use. - { - HttpRequestInfo request; - request.method = "GET"; - // Note that Transaction 1 was at /x/y/z, so this is in the same - // protection space as digest. - request.url = GURL("http://www.google.com/x/y/a/b"); - request.load_flags = 0; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - MockWrite data_writes1[] = { - MockWrite("GET /x/y/a/b HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Digest username=\"foo\", realm=\"digestive\", " - "nonce=\"OU812\", uri=\"/x/y/a/b\", algorithm=MD5, " - "response=\"d6f9a2c07d1c5df7b89379dca1269b35\", qop=auth, " - "nc=00000002, cnonce=\"0123456789abcdef\"\r\n\r\n"), - }; - - // Sever accepts the authorization. - MockRead data_reads1[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - 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.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - } -} - -// Test the ResetStateForRestart() private method. -TEST_F(HttpNetworkTransactionSpdy21Test, ResetStateForRestart) { - // Create a transaction (the dependencies aren't important). - SessionDependencies session_deps; - scoped_ptr<HttpNetworkTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - // Setup some state (which we expect ResetStateForRestart() will clear). - trans->read_buf_ = new IOBuffer(15); - trans->read_buf_len_ = 15; - trans->request_headers_.SetHeader("Authorization", "NTLM"); - - // Setup state in response_ - HttpResponseInfo* response = &trans->response_; - response->auth_challenge = new AuthChallengeInfo(); - response->ssl_info.cert_status = static_cast<CertStatus>(-1); // Nonsensical. - response->response_time = base::Time::Now(); - response->was_cached = true; // (Wouldn't ever actually be true...) - - { // Setup state for response_.vary_data - HttpRequestInfo request; - std::string temp("HTTP/1.1 200 OK\nVary: foo, bar\n\n"); - std::replace(temp.begin(), temp.end(), '\n', '\0'); - scoped_refptr<HttpResponseHeaders> headers(new HttpResponseHeaders(temp)); - request.extra_headers.SetHeader("Foo", "1"); - request.extra_headers.SetHeader("bar", "23"); - EXPECT_TRUE(response->vary_data.Init(request, *headers)); - } - - // Cause the above state to be reset. - trans->ResetStateForRestart(); - - // Verify that the state that needed to be reset, has been reset. - EXPECT_TRUE(trans->read_buf_.get() == NULL); - EXPECT_EQ(0, trans->read_buf_len_); - EXPECT_TRUE(trans->request_headers_.IsEmpty()); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_TRUE(response->headers.get() == NULL); - EXPECT_FALSE(response->was_cached); - EXPECT_EQ(0U, response->ssl_info.cert_status); - EXPECT_FALSE(response->vary_data.is_valid()); -} - -// Test HTTPS connections to a site with a bad certificate -TEST_F(HttpNetworkTransactionSpdy21Test, HTTPSBadCertificate) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider ssl_bad_certificate; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); - SSLSocketDataProvider ssl(ASYNC, OK); - - session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); - session_deps.socket_factory.AddSocketDataProvider(&data); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); - - rv = trans->RestartIgnoringLastError(callback.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - - ASSERT_TRUE(response != NULL); - EXPECT_EQ(100, response->headers->GetContentLength()); -} - -// Test HTTPS connections to a site with a bad certificate, going through a -// proxy -TEST_F(HttpNetworkTransactionSpdy21Test, HTTPSBadCertificateViaProxy) { - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - MockWrite proxy_writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - - MockRead proxy_reads[] = { - MockRead("HTTP/1.0 200 Connected\r\n\r\n"), - MockRead(SYNCHRONOUS, OK) - }; - - MockWrite data_writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 Connected\r\n\r\n"), - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider ssl_bad_certificate( - proxy_reads, arraysize(proxy_reads), - proxy_writes, arraysize(proxy_writes)); - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); - SSLSocketDataProvider ssl(ASYNC, OK); - - session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); - session_deps.socket_factory.AddSocketDataProvider(&data); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback; - - for (int i = 0; i < 2; i++) { - session_deps.socket_factory.ResetNextMockIndexes(); - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); - - rv = trans->RestartIgnoringLastError(callback.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - - ASSERT_TRUE(response != NULL); - EXPECT_EQ(100, response->headers->GetContentLength()); - } -} - - -// Test HTTPS connections to a site, going through an HTTPS proxy -TEST_F(HttpNetworkTransactionSpdy21Test, HTTPSViaHttpsProxy) { - SessionDependencies session_deps(ProxyService::CreateFixed( - "https://proxy:70")); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - MockWrite data_writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 Connected\r\n\r\n"), - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy - SSLSocketDataProvider tunnel_ssl(ASYNC, OK); // SSL through the tunnel - - session_deps.socket_factory.AddSocketDataProvider(&data); - session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); - session_deps.socket_factory.AddSSLSocketDataProvider(&tunnel_ssl); - - TestCompletionCallback callback; - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - const HttpResponseInfo* response = trans->GetResponseInfo(); - - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_EQ(100, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); -} - -// Test an HTTPS Proxy's ability to redirect a CONNECT request -TEST_F(HttpNetworkTransactionSpdy21Test, RedirectOfHttpsConnectViaHttpsProxy) { - SessionDependencies session_deps( - ProxyService::CreateFixed("https://proxy:70")); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - MockWrite data_writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads[] = { - MockRead("HTTP/1.1 302 Redirect\r\n"), - MockRead("Location: http://login.example.com/\r\n"), - MockRead("Content-Length: 0\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy - - session_deps.socket_factory.AddSocketDataProvider(&data); - session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); - - TestCompletionCallback callback; - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - const HttpResponseInfo* response = trans->GetResponseInfo(); - - ASSERT_TRUE(response != NULL); - - EXPECT_EQ(302, response->headers->response_code()); - std::string url; - EXPECT_TRUE(response->headers->IsRedirect(&url)); - EXPECT_EQ("http://login.example.com/", url); -} - -// Test an HTTPS (SPDY) Proxy's ability to redirect a CONNECT request -TEST_F(HttpNetworkTransactionSpdy21Test, RedirectOfHttpsConnectViaSpdyProxy) { - SessionDependencies session_deps( - ProxyService::CreateFixed("https://proxy:70")); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - scoped_ptr<SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1)); - scoped_ptr<SpdyFrame> goaway(ConstructSpdyRstStream(1, CANCEL)); - MockWrite data_writes[] = { - CreateMockWrite(*conn.get(), 0, SYNCHRONOUS), - }; - - static const char* const kExtraHeaders[] = { - "location", - "http://login.example.com/", - }; - scoped_ptr<SpdyFrame> resp( - ConstructSpdySynReplyError("302 Redirect", kExtraHeaders, - arraysize(kExtraHeaders)/2, 1)); - MockRead data_reads[] = { - CreateMockRead(*resp.get(), 1, SYNCHRONOUS), - MockRead(ASYNC, 0, 2), // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData( - 1, // wait for one write to finish before reading. - data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes))); - SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy - proxy_ssl.SetNextProto(kProtoSPDY21); - - session_deps.socket_factory.AddSocketDataProvider(data.get()); - session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); - - TestCompletionCallback callback; - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - const HttpResponseInfo* response = trans->GetResponseInfo(); - - ASSERT_TRUE(response != NULL); - - EXPECT_EQ(302, response->headers->response_code()); - std::string url; - EXPECT_TRUE(response->headers->IsRedirect(&url)); - EXPECT_EQ("http://login.example.com/", url); -} - -// Test an HTTPS Proxy's ability to provide a response to a CONNECT request -TEST_F(HttpNetworkTransactionSpdy21Test, - ErrorResponseTofHttpsConnectViaHttpsProxy) { - SessionDependencies session_deps( - ProxyService::CreateFixed("https://proxy:70")); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - MockWrite data_writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads[] = { - MockRead("HTTP/1.1 404 Not Found\r\n"), - MockRead("Content-Length: 23\r\n\r\n"), - MockRead("The host does not exist"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy - - session_deps.socket_factory.AddSocketDataProvider(&data); - session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); - - TestCompletionCallback callback; - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - const HttpResponseInfo* response = trans->GetResponseInfo(); - - ASSERT_TRUE(response != NULL); - - EXPECT_EQ(404, response->headers->response_code()); - EXPECT_EQ(23, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - EXPECT_FALSE(response->ssl_info.is_valid()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("The host does not exist", response_data); -} - -// Test an HTTPS (SPDY) Proxy's ability to provide a response to a CONNECT -// request -TEST_F(HttpNetworkTransactionSpdy21Test, - ErrorResponseTofHttpsConnectViaSpdyProxy) { - SessionDependencies session_deps( - ProxyService::CreateFixed("https://proxy:70")); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - scoped_ptr<SpdyFrame> conn(ConstructSpdyConnect(NULL, 0, 1)); - scoped_ptr<SpdyFrame> goaway(ConstructSpdyRstStream(1, CANCEL)); - MockWrite data_writes[] = { - CreateMockWrite(*conn.get(), 0, SYNCHRONOUS), - }; - - static const char* const kExtraHeaders[] = { - "location", - "http://login.example.com/", - }; - scoped_ptr<SpdyFrame> resp( - ConstructSpdySynReplyError("404 Not Found", kExtraHeaders, - arraysize(kExtraHeaders)/2, 1)); - scoped_ptr<SpdyFrame> body( - ConstructSpdyBodyFrame(1, "The host does not exist", 23, true)); - MockRead data_reads[] = { - CreateMockRead(*resp.get(), 1, SYNCHRONOUS), - CreateMockRead(*body.get(), 2, SYNCHRONOUS), - MockRead(ASYNC, 0, 3), // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData( - 1, // wait for one write to finish before reading. - data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes))); - SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy - proxy_ssl.SetNextProto(kProtoSPDY21); - - session_deps.socket_factory.AddSocketDataProvider(data.get()); - session_deps.socket_factory.AddSSLSocketDataProvider(&proxy_ssl); - - TestCompletionCallback callback; - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - const HttpResponseInfo* response = trans->GetResponseInfo(); - - ASSERT_TRUE(response != NULL); - - EXPECT_EQ(404, response->headers->response_code()); - EXPECT_FALSE(response->ssl_info.is_valid()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("The host does not exist", response_data); -} - -// Test the request-challenge-retry sequence for basic auth, through -// a SPDY proxy over a single SPDY session. -TEST_F(HttpNetworkTransactionSpdy21Test, BasicAuthSpdyProxy) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - // when the no authentication data flag is set. - request.load_flags = net::LOAD_DO_NOT_SEND_AUTH_DATA; - - // Configure against https proxy server "myproxy:70". - SessionDependencies session_deps( - ProxyService::CreateFixed("https://myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Since we have proxy, should try to establish tunnel. - scoped_ptr<SpdyFrame> req(ConstructSpdyConnect(NULL, 0, 1)); - scoped_ptr<SpdyFrame> rst(ConstructSpdyRstStream(1, CANCEL)); - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - const char* const kAuthCredentials[] = { - "proxy-authorization", "Basic Zm9vOmJhcg==", - }; - scoped_ptr<SpdyFrame> connect2( - ConstructSpdyConnect(kAuthCredentials, arraysize(kAuthCredentials)/2, 3)); - // fetch https://www.google.com/ via HTTP - const char get[] = "GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"; - scoped_ptr<SpdyFrame> wrapped_get( - ConstructSpdyBodyFrame(3, get, strlen(get), false)); - - MockWrite spdy_writes[] = { - CreateMockWrite(*req, 0, ASYNC), - CreateMockWrite(*rst, 2, ASYNC), - CreateMockWrite(*connect2, 3), - CreateMockWrite(*wrapped_get, 5) - }; - - // The proxy responds to the connect with a 407, using a persistent - // connection. - const char* const kAuthChallenge[] = { - "status", "407 Proxy Authentication Required", - "version", "HTTP/1.1", - "proxy-authenticate", "Basic realm=\"MyRealm1\"", - }; - - scoped_ptr<SpdyFrame> conn_auth_resp( - ConstructSpdyControlFrame(NULL, - 0, - false, - 1, - LOWEST, - SYN_REPLY, - CONTROL_FLAG_NONE, - kAuthChallenge, - arraysize(kAuthChallenge))); - - scoped_ptr<SpdyFrame> conn_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); - const char resp[] = "HTTP/1.1 200 OK\r\n" - "Content-Length: 5\r\n\r\n"; - - scoped_ptr<SpdyFrame> wrapped_get_resp( - ConstructSpdyBodyFrame(3, resp, strlen(resp), false)); - scoped_ptr<SpdyFrame> wrapped_body( - ConstructSpdyBodyFrame(3, "hello", 5, false)); - MockRead spdy_reads[] = { - CreateMockRead(*conn_auth_resp, 1, ASYNC), - CreateMockRead(*conn_resp, 4, ASYNC), - CreateMockRead(*wrapped_get_resp, 5, ASYNC), - CreateMockRead(*wrapped_body, 6, ASYNC), - MockRead(SYNCHRONOUS, ERR_IO_PENDING), - }; - - scoped_ptr<OrderedSocketData> spdy_data( - new OrderedSocketData( - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - // Negotiate SPDY to the proxy - SSLSocketDataProvider proxy(ASYNC, OK); - proxy.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&proxy); - // Vanilla SSL to the server - SSLSocketDataProvider server(ASYNC, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&server); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - net::CapturingNetLog::EntryList entries; - log.GetEntries(&entries); - size_t pos = ExpectLogContainsSomewhere( - entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - NetLog::PHASE_NONE); - ExpectLogContainsSomewhere( - entries, pos, - NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - NetLog::PHASE_NONE); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_FALSE(response->headers == NULL); - EXPECT_EQ(407, response->headers->response_code()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - EXPECT_TRUE(response->auth_challenge.get() != NULL); - EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), - callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_EQ(5, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - - // The password prompt info should not be set. - EXPECT_TRUE(response->auth_challenge.get() == NULL); - - trans.reset(); - session->CloseAllConnections(); -} - -// Test that an explicitly trusted SPDY proxy can push a resource from an -// origin that is different from that of its associated resource. -TEST_F(HttpNetworkTransactionSpdy21Test, CrossOriginProxyPush) { - HttpRequestInfo request; - HttpRequestInfo push_request; - - static const unsigned char kPushBodyFrame[] = { - 0x00, 0x00, 0x00, 0x02, // header, ID - 0x01, 0x00, 0x00, 0x06, // FIN, length - 'p', 'u', 's', 'h', 'e', 'd' // "pushed" - }; - - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - push_request.method = "GET"; - push_request.url = GURL("http://www.another-origin.com/foo.dat"); - - // Enable cross-origin push. - net::SpdySession::set_allow_spdy_proxy_push_across_origins("myproxy:70"); - - // Configure against https proxy server "myproxy:70". - SessionDependencies session_deps( - ProxyService::CreateFixed("https://myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false)); - - MockWrite spdy_writes[] = { - CreateMockWrite(*stream1_syn, 1, ASYNC) - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 1, - "http://www.another-origin.com/foo.dat")); - - MockRead spdy_reads[] = { - CreateMockRead(*stream1_reply, 2, ASYNC), - CreateMockRead(*stream2_syn, 3, ASYNC), - CreateMockRead(*stream1_body, 4, ASYNC), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), - arraysize(kPushBodyFrame), 5), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause - }; - - scoped_ptr<OrderedSocketData> spdy_data( - new OrderedSocketData( - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - // Negotiate SPDY to the proxy - SSLSocketDataProvider proxy(ASYNC, OK); - proxy.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&proxy); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - int rv = trans->Start(&request, callback.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - const HttpResponseInfo* response = trans->GetResponseInfo(); - - scoped_ptr<HttpTransaction> push_trans(new HttpNetworkTransaction(session)); - rv = push_trans->Start(&push_request, callback.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - const HttpResponseInfo* push_response = push_trans->GetResponseInfo(); - - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->headers->IsKeepAlive()); - - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("hello!", response_data); - - // Verify the pushed stream. - EXPECT_TRUE(push_response->headers != NULL); - EXPECT_EQ(200, push_response->headers->response_code()); - - rv = ReadTransaction(push_trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("pushed", response_data); - - trans.reset(); - push_trans.reset(); - session->CloseAllConnections(); -} - -// Test that an explicitly trusted SPDY proxy cannot push HTTPS content. -TEST_F(HttpNetworkTransactionSpdy21Test, CrossOriginProxyPushCorrectness) { - HttpRequestInfo request; - - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - - // Enable cross-origin push. - net::SpdySession::set_allow_spdy_proxy_push_across_origins("myproxy:70"); - - // Configure against https proxy server "myproxy:70". - SessionDependencies session_deps( - ProxyService::CreateFixed("https://myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false)); - - scoped_ptr<SpdyFrame> push_rst( - ConstructSpdyRstStream(2, REFUSED_STREAM)); - - MockWrite spdy_writes[] = { - CreateMockWrite(*stream1_syn, 1, ASYNC), - CreateMockWrite(*push_rst, 4), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 1, - "https://www.another-origin.com/foo.dat")); - - MockRead spdy_reads[] = { - CreateMockRead(*stream1_reply, 2, ASYNC), - CreateMockRead(*stream2_syn, 3, ASYNC), - CreateMockRead(*stream1_body, 5, ASYNC), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause - }; - - scoped_ptr<OrderedSocketData> spdy_data( - new OrderedSocketData( - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - // Negotiate SPDY to the proxy - SSLSocketDataProvider proxy(ASYNC, OK); - proxy.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&proxy); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - int rv = trans->Start(&request, callback.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - const HttpResponseInfo* response = trans->GetResponseInfo(); - - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->headers->IsKeepAlive()); - - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("hello!", response_data); - - trans.reset(); - session->CloseAllConnections(); -} - -// Test HTTPS connections to a site with a bad certificate, going through an -// HTTPS proxy -TEST_F(HttpNetworkTransactionSpdy21Test, HTTPSBadCertificateViaHttpsProxy) { - SessionDependencies session_deps(ProxyService::CreateFixed( - "https://proxy:70")); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - // Attempt to fetch the URL from a server with a bad cert - MockWrite bad_cert_writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - - MockRead bad_cert_reads[] = { - MockRead("HTTP/1.0 200 Connected\r\n\r\n"), - MockRead(SYNCHRONOUS, OK) - }; - - // Attempt to fetch the URL with a good cert - MockWrite good_data_writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead good_cert_reads[] = { - MockRead("HTTP/1.0 200 Connected\r\n\r\n"), - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider ssl_bad_certificate( - bad_cert_reads, arraysize(bad_cert_reads), - bad_cert_writes, arraysize(bad_cert_writes)); - StaticSocketDataProvider data(good_cert_reads, arraysize(good_cert_reads), - good_data_writes, arraysize(good_data_writes)); - SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID); - SSLSocketDataProvider ssl(ASYNC, OK); - - // SSL to the proxy, then CONNECT request, then SSL with bad certificate - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - session_deps.socket_factory.AddSocketDataProvider(&ssl_bad_certificate); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_bad); - - // SSL to the proxy, then CONNECT request, then valid SSL certificate - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - session_deps.socket_factory.AddSocketDataProvider(&data); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback; - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(ERR_CERT_AUTHORITY_INVALID, rv); - - rv = trans->RestartIgnoringLastError(callback.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - - ASSERT_TRUE(response != NULL); - EXPECT_EQ(100, response->headers->GetContentLength()); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, BuildRequest_UserAgent) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, - "Chromium Ultra Awesome X Edition"); - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, BuildRequest_UserAgentOverTunnel) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, - "Chromium Ultra Awesome X Edition"); - - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"), - }; - MockRead data_reads[] = { - // Return an error, so the transaction stops here (this test isn't - // interested in the rest). - MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"), - MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Proxy-Connection: close\r\n\r\n"), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, BuildRequest_Referer) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - request.extra_headers.SetHeader(HttpRequestHeaders::kReferer, - "http://the.previous.site.com/"); - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Referer: http://the.previous.site.com/\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, BuildRequest_PostContentLengthZero) { - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.google.com/"); - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("POST / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Content-Length: 0\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, BuildRequest_PutContentLengthZero) { - HttpRequestInfo request; - request.method = "PUT"; - request.url = GURL("http://www.google.com/"); - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("PUT / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Content-Length: 0\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, BuildRequest_HeadContentLengthZero) { - HttpRequestInfo request; - request.method = "HEAD"; - request.url = GURL("http://www.google.com/"); - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("HEAD / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Content-Length: 0\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, BuildRequest_CacheControlNoCache) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = LOAD_BYPASS_CACHE; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Pragma: no-cache\r\n" - "Cache-Control: no-cache\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - BuildRequest_CacheControlValidateCache) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = LOAD_VALIDATE_CACHE; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Cache-Control: max-age=0\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, BuildRequest_ExtraHeaders) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.extra_headers.SetHeader("FooHeader", "Bar"); - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "FooHeader: Bar\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, BuildRequest_ExtraHeadersStripped) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.extra_headers.SetHeader("referer", "www.foo.com"); - request.extra_headers.SetHeader("hEllo", "Kitty"); - request.extra_headers.SetHeader("FoO", "bar"); - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockWrite data_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "referer: www.foo.com\r\n" - "hEllo: Kitty\r\n" - "FoO: bar\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, SOCKS4_HTTP_GET) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps( - ProxyService::CreateFixed("socks4://myproxy:1080")); - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 }; - char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; - - MockWrite data_writes[] = { - MockWrite(ASYNC, write_buffer, arraysize(write_buffer)), - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n") - }; - - MockRead data_reads[] = { - MockRead(ASYNC, read_buffer, arraysize(read_buffer)), - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), - MockRead("Payload"), - MockRead(SYNCHRONOUS, OK) - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - std::string response_text; - rv = ReadTransaction(trans.get(), &response_text); - EXPECT_EQ(OK, rv); - EXPECT_EQ("Payload", response_text); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, SOCKS4_SSL_GET) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps( - ProxyService::CreateFixed("socks4://myproxy:1080")); - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - unsigned char write_buffer[] = { 0x04, 0x01, 0x01, 0xBB, 127, 0, 0, 1, 0 }; - unsigned char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 }; - - MockWrite data_writes[] = { - MockWrite(ASYNC, reinterpret_cast<char*>(write_buffer), - arraysize(write_buffer)), - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n") - }; - - MockRead data_reads[] = { - MockWrite(ASYNC, reinterpret_cast<char*>(read_buffer), - arraysize(read_buffer)), - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), - MockRead("Payload"), - MockRead(SYNCHRONOUS, OK) - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - SSLSocketDataProvider ssl(ASYNC, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - std::string response_text; - rv = ReadTransaction(trans.get(), &response_text); - EXPECT_EQ(OK, rv); - EXPECT_EQ("Payload", response_text); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, SOCKS5_HTTP_GET) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps( - ProxyService::CreateFixed("socks5://myproxy:1080")); - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; - const char kSOCKS5GreetResponse[] = { 0x05, 0x00 }; - const char kSOCKS5OkRequest[] = { - 0x05, // Version - 0x01, // Command (CONNECT) - 0x00, // Reserved. - 0x03, // Address type (DOMAINNAME). - 0x0E, // Length of domain (14) - // Domain string: - 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', - 0x00, 0x50, // 16-bit port (80) - }; - const char kSOCKS5OkResponse[] = - { 0x05, 0x00, 0x00, 0x01, 127, 0, 0, 1, 0x00, 0x50 }; - - MockWrite data_writes[] = { - MockWrite(ASYNC, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)), - MockWrite(ASYNC, kSOCKS5OkRequest, arraysize(kSOCKS5OkRequest)), - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n") - }; - - MockRead data_reads[] = { - MockWrite(ASYNC, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), - MockWrite(ASYNC, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)), - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), - MockRead("Payload"), - MockRead(SYNCHRONOUS, OK) - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - std::string response_text; - rv = ReadTransaction(trans.get(), &response_text); - EXPECT_EQ(OK, rv); - EXPECT_EQ("Payload", response_text); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, SOCKS5_SSL_GET) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps( - ProxyService::CreateFixed("socks5://myproxy:1080")); - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - const char kSOCKS5GreetRequest[] = { 0x05, 0x01, 0x00 }; - const char kSOCKS5GreetResponse[] = { 0x05, 0x00 }; - const unsigned char kSOCKS5OkRequest[] = { - 0x05, // Version - 0x01, // Command (CONNECT) - 0x00, // Reserved. - 0x03, // Address type (DOMAINNAME). - 0x0E, // Length of domain (14) - // Domain string: - 'w', 'w', 'w', '.', 'g', 'o', 'o', 'g', 'l', 'e', '.', 'c', 'o', 'm', - 0x01, 0xBB, // 16-bit port (443) - }; - - const char kSOCKS5OkResponse[] = - { 0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0x00, 0x00 }; - - MockWrite data_writes[] = { - MockWrite(ASYNC, kSOCKS5GreetRequest, arraysize(kSOCKS5GreetRequest)), - MockWrite(ASYNC, reinterpret_cast<const char*>(kSOCKS5OkRequest), - arraysize(kSOCKS5OkRequest)), - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n") - }; - - MockRead data_reads[] = { - MockWrite(ASYNC, kSOCKS5GreetResponse, arraysize(kSOCKS5GreetResponse)), - MockWrite(ASYNC, kSOCKS5OkResponse, arraysize(kSOCKS5OkResponse)), - MockRead("HTTP/1.0 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"), - MockRead("Payload"), - MockRead(SYNCHRONOUS, OK) - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - SSLSocketDataProvider ssl(ASYNC, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - std::string response_text; - rv = ReadTransaction(trans.get(), &response_text); - EXPECT_EQ(OK, rv); - EXPECT_EQ("Payload", response_text); -} - -namespace { - -// Tests that for connection endpoints the group names are correctly set. - -struct GroupNameTest { - std::string proxy_server; - std::string url; - std::string expected_group_name; - bool ssl; -}; - -scoped_refptr<HttpNetworkSession> SetupSessionForGroupNameTests( - SessionDependencies* session_deps) { - scoped_refptr<HttpNetworkSession> session(CreateSession(session_deps)); - - HttpServerProperties* http_server_properties = - session->http_server_properties(); - http_server_properties->SetAlternateProtocol( - HostPortPair("host.with.alternate", 80), 443, - NPN_SPDY_21); - - return session; -} - -int GroupNameTransactionHelper( - const std::string& url, - const scoped_refptr<HttpNetworkSession>& session) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL(url); - request.load_flags = 0; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - TestCompletionCallback callback; - - // We do not complete this request, the dtor will clean the transaction up. - return trans->Start(&request, callback.callback(), BoundNetLog()); -} - -} // namespace - -TEST_F(HttpNetworkTransactionSpdy21Test, GroupNameForDirectConnections) { - const GroupNameTest tests[] = { - { - "", // unused - "http://www.google.com/direct", - "www.google.com:80", - false, - }, - { - "", // unused - "http://[2001:1418:13:1::25]/direct", - "[2001:1418:13:1::25]:80", - false, - }, - - // SSL Tests - { - "", // unused - "https://www.google.com/direct_ssl", - "ssl/www.google.com:443", - true, - }, - { - "", // unused - "https://[2001:1418:13:1::25]/direct", - "ssl/[2001:1418:13:1::25]:443", - true, - }, - { - "", // unused - "http://host.with.alternate/direct", - "ssl/host.with.alternate:443", - true, - }, - }; - - HttpStreamFactory::set_use_alternate_protocols(true); - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { - SessionDependencies session_deps( - ProxyService::CreateFixed(tests[i].proxy_server)); - scoped_refptr<HttpNetworkSession> session( - SetupSessionForGroupNameTests(&session_deps)); - - HttpNetworkSessionPeer peer(session); - CaptureGroupNameTransportSocketPool* transport_conn_pool = - new CaptureGroupNameTransportSocketPool(NULL, NULL); - CaptureGroupNameSSLSocketPool* ssl_conn_pool = - new CaptureGroupNameSSLSocketPool(NULL, NULL); - MockClientSocketPoolManager* mock_pool_manager = - new MockClientSocketPoolManager; - mock_pool_manager->SetTransportSocketPool(transport_conn_pool); - mock_pool_manager->SetSSLSocketPool(ssl_conn_pool); - peer.SetClientSocketPoolManager(mock_pool_manager); - - EXPECT_EQ(ERR_IO_PENDING, - GroupNameTransactionHelper(tests[i].url, session)); - if (tests[i].ssl) - EXPECT_EQ(tests[i].expected_group_name, - ssl_conn_pool->last_group_name_received()); - else - EXPECT_EQ(tests[i].expected_group_name, - transport_conn_pool->last_group_name_received()); - } - - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, GroupNameForHTTPProxyConnections) { - const GroupNameTest tests[] = { - { - "http_proxy", - "http://www.google.com/http_proxy_normal", - "www.google.com:80", - false, - }, - - // SSL Tests - { - "http_proxy", - "https://www.google.com/http_connect_ssl", - "ssl/www.google.com:443", - true, - }, - - { - "http_proxy", - "http://host.with.alternate/direct", - "ssl/host.with.alternate:443", - true, - }, - }; - - HttpStreamFactory::set_use_alternate_protocols(true); - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { - SessionDependencies session_deps( - ProxyService::CreateFixed(tests[i].proxy_server)); - scoped_refptr<HttpNetworkSession> session( - SetupSessionForGroupNameTests(&session_deps)); - - HttpNetworkSessionPeer peer(session); - - HostPortPair proxy_host("http_proxy", 80); - CaptureGroupNameHttpProxySocketPool* http_proxy_pool = - new CaptureGroupNameHttpProxySocketPool(NULL, NULL); - CaptureGroupNameSSLSocketPool* ssl_conn_pool = - new CaptureGroupNameSSLSocketPool(NULL, NULL); - - MockClientSocketPoolManager* mock_pool_manager = - new MockClientSocketPoolManager; - mock_pool_manager->SetSocketPoolForHTTPProxy(proxy_host, http_proxy_pool); - mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); - peer.SetClientSocketPoolManager(mock_pool_manager); - - EXPECT_EQ(ERR_IO_PENDING, - GroupNameTransactionHelper(tests[i].url, session)); - if (tests[i].ssl) - EXPECT_EQ(tests[i].expected_group_name, - ssl_conn_pool->last_group_name_received()); - else - EXPECT_EQ(tests[i].expected_group_name, - http_proxy_pool->last_group_name_received()); - } - - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, GroupNameForSOCKSConnections) { - const GroupNameTest tests[] = { - { - "socks4://socks_proxy:1080", - "http://www.google.com/socks4_direct", - "socks4/www.google.com:80", - false, - }, - { - "socks5://socks_proxy:1080", - "http://www.google.com/socks5_direct", - "socks5/www.google.com:80", - false, - }, - - // SSL Tests - { - "socks4://socks_proxy:1080", - "https://www.google.com/socks4_ssl", - "socks4/ssl/www.google.com:443", - true, - }, - { - "socks5://socks_proxy:1080", - "https://www.google.com/socks5_ssl", - "socks5/ssl/www.google.com:443", - true, - }, - - { - "socks4://socks_proxy:1080", - "http://host.with.alternate/direct", - "socks4/ssl/host.with.alternate:443", - true, - }, - }; - - HttpStreamFactory::set_use_alternate_protocols(true); - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { - SessionDependencies session_deps( - ProxyService::CreateFixed(tests[i].proxy_server)); - scoped_refptr<HttpNetworkSession> session( - SetupSessionForGroupNameTests(&session_deps)); - - HttpNetworkSessionPeer peer(session); - - HostPortPair proxy_host("socks_proxy", 1080); - CaptureGroupNameSOCKSSocketPool* socks_conn_pool = - new CaptureGroupNameSOCKSSocketPool(NULL, NULL); - CaptureGroupNameSSLSocketPool* ssl_conn_pool = - new CaptureGroupNameSSLSocketPool(NULL, NULL); - - MockClientSocketPoolManager* mock_pool_manager = - new MockClientSocketPoolManager; - mock_pool_manager->SetSocketPoolForSOCKSProxy(proxy_host, socks_conn_pool); - mock_pool_manager->SetSocketPoolForSSLWithProxy(proxy_host, ssl_conn_pool); - peer.SetClientSocketPoolManager(mock_pool_manager); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - EXPECT_EQ(ERR_IO_PENDING, - GroupNameTransactionHelper(tests[i].url, session)); - if (tests[i].ssl) - EXPECT_EQ(tests[i].expected_group_name, - ssl_conn_pool->last_group_name_received()); - else - EXPECT_EQ(tests[i].expected_group_name, - socks_conn_pool->last_group_name_received()); - } - - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ReconsiderProxyAfterFailedConnection) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - - SessionDependencies session_deps( - ProxyService::CreateFixed("myproxy:70;foobar:80")); - - // This simulates failure resolving all hostnames; that means we will fail - // connecting to both proxies (myproxy:70 and foobar:80). - session_deps.host_resolver->rules()->AddSimulatedFailure("*"); - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv); -} - -namespace { - -// Base test to make sure that when the load flags for a request specify to -// bypass the cache, the DNS cache is not used. -void BypassHostCacheOnRefreshHelper(int load_flags) { - // Issue a request, asking to bypass the cache(s). - HttpRequestInfo request; - request.method = "GET"; - request.load_flags = load_flags; - request.url = GURL("http://www.google.com/"); - - SessionDependencies session_deps; - - // Select a host resolver that does caching. - session_deps.host_resolver.reset(new MockCachingHostResolver); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction( - CreateSession(&session_deps))); - - // Warm up the host cache so it has an entry for "www.google.com". - AddressList addrlist; - TestCompletionCallback callback; - int rv = session_deps.host_resolver->Resolve( - HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist, - callback.callback(), NULL, BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - // Verify that it was added to host cache, by doing a subsequent async lookup - // and confirming it completes synchronously. - rv = session_deps.host_resolver->Resolve( - HostResolver::RequestInfo(HostPortPair("www.google.com", 80)), &addrlist, - callback.callback(), NULL, BoundNetLog()); - ASSERT_EQ(OK, rv); - - // Inject a failure the next time that "www.google.com" is resolved. This way - // we can tell if the next lookup hit the cache, or the "network". - // (cache --> success, "network" --> failure). - session_deps.host_resolver->rules()->AddSimulatedFailure("www.google.com"); - - // Connect up a mock socket which will fail with ERR_UNEXPECTED during the - // first read -- this won't be reached as the host resolution will fail first. - MockRead data_reads[] = { MockRead(SYNCHRONOUS, ERR_UNEXPECTED) }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - // Run the request. - rv = trans->Start(&request, callback.callback(), BoundNetLog()); - ASSERT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - - // If we bypassed the cache, we would have gotten a failure while resolving - // "www.google.com". - EXPECT_EQ(ERR_NAME_NOT_RESOLVED, rv); -} - -} // namespace - -// There are multiple load flags that should trigger the host cache bypass. -// Test each in isolation: -TEST_F(HttpNetworkTransactionSpdy21Test, BypassHostCacheOnRefresh1) { - BypassHostCacheOnRefreshHelper(LOAD_BYPASS_CACHE); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, BypassHostCacheOnRefresh2) { - BypassHostCacheOnRefreshHelper(LOAD_VALIDATE_CACHE); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, BypassHostCacheOnRefresh3) { - BypassHostCacheOnRefreshHelper(LOAD_DISABLE_CACHE); -} - -// Make sure we can handle an error when writing the request. -TEST_F(HttpNetworkTransactionSpdy21Test, RequestWriteError) { - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.foo.com/"); - request.load_flags = 0; - - MockWrite write_failure[] = { - MockWrite(ASYNC, ERR_CONNECTION_RESET), - }; - StaticSocketDataProvider data(NULL, 0, - write_failure, arraysize(write_failure)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(ERR_CONNECTION_RESET, rv); -} - -// Check that a connection closed after the start of the headers finishes ok. -TEST_F(HttpNetworkTransactionSpdy21Test, ConnectionClosedAfterStartOfHeaders) { - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.foo.com/"); - request.load_flags = 0; - - MockRead data_reads[] = { - MockRead("HTTP/1."), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("", response_data); -} - -// Make sure that a dropped connection while draining the body for auth -// restart does the right thing. -TEST_F(HttpNetworkTransactionSpdy21Test, DrainResetOK) { - SessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - MockWrite data_writes1[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.1 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 14\r\n\r\n"), - MockRead("Unauth"), - MockRead(ASYNC, ERR_CONNECTION_RESET), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - - // After calling trans->RestartWithAuth(), this is the request we should - // be issuing -- the final header line contains the credentials. - MockWrite data_writes2[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - - // Lastly, the server responds with the actual content. - MockRead data_reads2[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(100, response->headers->GetContentLength()); -} - -// Test HTTPS connections going through a proxy that sends extra data. -TEST_F(HttpNetworkTransactionSpdy21Test, HTTPSViaProxyWithExtraData) { - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - MockRead proxy_reads[] = { - MockRead("HTTP/1.0 200 Connected\r\n\r\nExtra data"), - MockRead(SYNCHRONOUS, OK) - }; - - StaticSocketDataProvider data(proxy_reads, arraysize(proxy_reads), NULL, 0); - SSLSocketDataProvider ssl(ASYNC, OK); - - session_deps.socket_factory.AddSocketDataProvider(&data); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback; - - session_deps.socket_factory.ResetNextMockIndexes(); - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, LargeContentLengthThenClose) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\nContent-Length:6719476739\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(ERR_CONNECTION_CLOSED, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, UploadFileSmallerThanLength) { - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.google.com/upload"); - request.upload_data = new UploadData; - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - FilePath temp_file_path; - ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file_path)); - const uint64 kFakeSize = 100000; // file is actually blank - - std::vector<UploadData::Element> elements; - UploadData::Element element; - element.SetToFilePath(temp_file_path); - element.SetContentLength(kFakeSize); - elements.push_back(element); - request.upload_data->SetElements(elements); - EXPECT_EQ(kFakeSize, request.upload_data->GetContentLengthSync()); - - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("hello world", response_data); - - file_util::Delete(temp_file_path, false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, UploadUnreadableFile) { - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.google.com/upload"); - request.upload_data = new UploadData; - request.load_flags = 0; - - // If we try to upload an unreadable file, the network stack should report - // the file size as zero and upload zero bytes for that file. - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - FilePath temp_file; - ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file)); - std::string temp_file_content("Unreadable file."); - ASSERT_TRUE(file_util::WriteFile(temp_file, temp_file_content.c_str(), - temp_file_content.length())); - ASSERT_TRUE(file_util::MakeFileUnreadable(temp_file)); - - std::vector<UploadData::Element> elements; - UploadData::Element element; - element.SetToFilePath(temp_file); - elements.push_back(element); - request.upload_data->SetElements(elements); - - MockRead data_reads[] = { - MockRead("HTTP/1.0 200 OK\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - MockWrite data_writes[] = { - MockWrite("POST /upload HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Content-Length: 0\r\n\r\n"), - MockWrite(SYNCHRONOUS, OK), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, - arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine()); - - file_util::Delete(temp_file, false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, UnreadableUploadFileAfterAuthRestart) { - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.google.com/upload"); - request.upload_data = new UploadData; - request.load_flags = 0; - - SessionDependencies session_deps; - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - FilePath temp_file; - ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file)); - std::string temp_file_contents("Unreadable file."); - std::string unreadable_contents(temp_file_contents.length(), '\0'); - ASSERT_TRUE(file_util::WriteFile(temp_file, temp_file_contents.c_str(), - temp_file_contents.length())); - - std::vector<UploadData::Element> elements; - UploadData::Element element; - element.SetToFilePath(temp_file); - elements.push_back(element); - request.upload_data->SetElements(elements); - - MockRead data_reads[] = { - MockRead("HTTP/1.1 401 Unauthorized\r\n"), - MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead("Content-Length: 0\r\n\r\n"), // No response body. - - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Length: 0\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - MockWrite data_writes[] = { - MockWrite("POST /upload HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Content-Length: 16\r\n\r\n"), - MockWrite(SYNCHRONOUS, temp_file_contents.c_str()), - - MockWrite("POST /upload HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Content-Length: 16\r\n" - "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - MockWrite(SYNCHRONOUS, unreadable_contents.c_str(), - temp_file_contents.length()), - MockWrite(SYNCHRONOUS, OK), - }; - StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes, - arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback1; - - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 401 Unauthorized", response->headers->GetStatusLine()); - EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get())); - - // Now make the file unreadable and try again. - ASSERT_TRUE(file_util::MakeFileUnreadable(temp_file)); - - TestCompletionCallback callback2; - - rv = trans->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->headers != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - file_util::Delete(temp_file, false); -} - -// Tests that changes to Auth realms are treated like auth rejections. -TEST_F(HttpNetworkTransactionSpdy21Test, ChangeAuthRealms) { - SessionDependencies session_deps; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - // First transaction will request a resource and receive a Basic challenge - // with realm="first_realm". - MockWrite data_writes1[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "\r\n"), - }; - MockRead data_reads1[] = { - MockRead("HTTP/1.1 401 Unauthorized\r\n" - "WWW-Authenticate: Basic realm=\"first_realm\"\r\n" - "\r\n"), - }; - - // After calling trans->RestartWithAuth(), provide an Authentication header - // for first_realm. The server will reject and provide a challenge with - // second_realm. - MockWrite data_writes2[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zmlyc3Q6YmF6\r\n" - "\r\n"), - }; - MockRead data_reads2[] = { - MockRead("HTTP/1.1 401 Unauthorized\r\n" - "WWW-Authenticate: Basic realm=\"second_realm\"\r\n" - "\r\n"), - }; - - // This again fails, and goes back to first_realm. Make sure that the - // entry is removed from cache. - MockWrite data_writes3[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic c2Vjb25kOmZvdQ==\r\n" - "\r\n"), - }; - MockRead data_reads3[] = { - MockRead("HTTP/1.1 401 Unauthorized\r\n" - "WWW-Authenticate: Basic realm=\"first_realm\"\r\n" - "\r\n"), - }; - - // Try one last time (with the correct password) and get the resource. - MockWrite data_writes4[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: Basic Zmlyc3Q6YmFy\r\n" - "\r\n"), - }; - MockRead data_reads4[] = { - MockRead("HTTP/1.1 200 OK\r\n" - "Content-Type: text/html; charset=iso-8859-1\r\n" - "Content-Length: 5\r\n" - "\r\n" - "hello"), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - StaticSocketDataProvider data3(data_reads3, arraysize(data_reads3), - data_writes3, arraysize(data_writes3)); - StaticSocketDataProvider data4(data_reads4, arraysize(data_reads4), - data_writes4, arraysize(data_writes4)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - session_deps.socket_factory.AddSocketDataProvider(&data2); - session_deps.socket_factory.AddSocketDataProvider(&data3); - session_deps.socket_factory.AddSocketDataProvider(&data4); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - // Issue the first request with Authorize headers. There should be a - // password prompt for first_realm waiting to be filled in after the - // transaction completes. - int rv = trans->Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - const AuthChallengeInfo* challenge = response->auth_challenge.get(); - ASSERT_FALSE(challenge == NULL); - EXPECT_FALSE(challenge->is_proxy); - EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); - EXPECT_EQ("first_realm", challenge->realm); - EXPECT_EQ("basic", challenge->scheme); - - // Issue the second request with an incorrect password. There should be a - // password prompt for second_realm waiting to be filled in after the - // transaction completes. - TestCompletionCallback callback2; - rv = trans->RestartWithAuth( - AuthCredentials(kFirst, kBaz), callback2.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback2.WaitForResult(); - EXPECT_EQ(OK, rv); - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - challenge = response->auth_challenge.get(); - ASSERT_FALSE(challenge == NULL); - EXPECT_FALSE(challenge->is_proxy); - EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); - EXPECT_EQ("second_realm", challenge->realm); - EXPECT_EQ("basic", challenge->scheme); - - // Issue the third request with another incorrect password. There should be - // a password prompt for first_realm waiting to be filled in. If the password - // prompt is not present, it indicates that the HttpAuthCacheEntry for - // first_realm was not correctly removed. - TestCompletionCallback callback3; - rv = trans->RestartWithAuth( - AuthCredentials(kSecond, kFou), callback3.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback3.WaitForResult(); - EXPECT_EQ(OK, rv); - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - challenge = response->auth_challenge.get(); - ASSERT_FALSE(challenge == NULL); - EXPECT_FALSE(challenge->is_proxy); - EXPECT_EQ("www.google.com:80", challenge->challenger.ToString()); - EXPECT_EQ("first_realm", challenge->realm); - EXPECT_EQ("basic", challenge->scheme); - - // Issue the fourth request with the correct password and username. - TestCompletionCallback callback4; - rv = trans->RestartWithAuth( - AuthCredentials(kFirst, kBar), callback4.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback4.WaitForResult(); - EXPECT_EQ(OK, rv); - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, HonorAlternateProtocolHeader) { - HttpStreamFactory::SetNextProtos(SpdyNextProtos()); - HttpStreamFactory::set_use_alternate_protocols(true); - - SessionDependencies session_deps; - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead(kAlternateProtocolHttpHeader), - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - HostPortPair http_host_port_pair("www.google.com", 80); - const HttpServerProperties& http_server_properties = - *session->http_server_properties(); - EXPECT_FALSE( - http_server_properties.HasAlternateProtocol(http_host_port_pair)); - - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_FALSE(response->was_fetched_via_spdy); - EXPECT_FALSE(response->was_npn_negotiated); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello world", response_data); - - ASSERT_TRUE(http_server_properties.HasAlternateProtocol(http_host_port_pair)); - const PortAlternateProtocolPair alternate = - http_server_properties.GetAlternateProtocol(http_host_port_pair); - PortAlternateProtocolPair expected_alternate; - expected_alternate.port = 443; - expected_alternate.protocol = NPN_SPDY_21; - EXPECT_TRUE(expected_alternate.Equals(alternate)); - - HttpStreamFactory::set_use_alternate_protocols(false); - HttpStreamFactory::SetNextProtos(std::vector<std::string>()); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - MarkBrokenAlternateProtocolAndFallback) { - HttpStreamFactory::set_use_alternate_protocols(true); - SessionDependencies session_deps; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); - StaticSocketDataProvider first_data; - first_data.set_connect_data(mock_connect); - session_deps.socket_factory.AddSocketDataProvider(&first_data); - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(ASYNC, OK), - }; - StaticSocketDataProvider second_data( - data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&second_data); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpServerProperties* http_server_properties = - session->http_server_properties(); - // Port must be < 1024, or the header will be ignored (since initial port was - // port 80 (another restricted port). - http_server_properties->SetAlternateProtocol( - HostPortPair::FromURL(request.url), - 666 /* port is ignored by MockConnect anyway */, - NPN_SPDY_21); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello world", response_data); - - ASSERT_TRUE(http_server_properties->HasAlternateProtocol( - HostPortPair::FromURL(request.url))); - const PortAlternateProtocolPair alternate = - http_server_properties->GetAlternateProtocol( - HostPortPair::FromURL(request.url)); - EXPECT_EQ(ALTERNATE_PROTOCOL_BROKEN, alternate.protocol); - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - AlternateProtocolPortRestrictedBlocked) { - // Ensure that we're not allowed to redirect traffic via an alternate - // protocol to an unrestricted (port >= 1024) when the original traffic was - // on a restricted port (port < 1024). Ensure that we can redirect in all - // other cases. - HttpStreamFactory::set_use_alternate_protocols(true); - SessionDependencies session_deps; - - HttpRequestInfo restricted_port_request; - restricted_port_request.method = "GET"; - restricted_port_request.url = GURL("http://www.google.com:1023/"); - restricted_port_request.load_flags = 0; - - MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); - StaticSocketDataProvider first_data; - first_data.set_connect_data(mock_connect); - session_deps.socket_factory.AddSocketDataProvider(&first_data); - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(ASYNC, OK), - }; - StaticSocketDataProvider second_data( - data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&second_data); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpServerProperties* http_server_properties = - session->http_server_properties(); - const int kUnrestrictedAlternatePort = 1024; - http_server_properties->SetAlternateProtocol( - HostPortPair::FromURL(restricted_port_request.url), - kUnrestrictedAlternatePort, - NPN_SPDY_21); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - - int rv = trans->Start( - &restricted_port_request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - // Invalid change to unrestricted port should fail. - EXPECT_EQ(ERR_CONNECTION_REFUSED, callback.WaitForResult()); - - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - AlternateProtocolPortRestrictedAllowed) { - // Ensure that we're not allowed to redirect traffic via an alternate - // protocol to an unrestricted (port >= 1024) when the original traffic was - // on a restricted port (port < 1024). Ensure that we can redirect in all - // other cases. - HttpStreamFactory::set_use_alternate_protocols(true); - SessionDependencies session_deps; - - HttpRequestInfo restricted_port_request; - restricted_port_request.method = "GET"; - restricted_port_request.url = GURL("http://www.google.com:1023/"); - restricted_port_request.load_flags = 0; - - MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); - StaticSocketDataProvider first_data; - first_data.set_connect_data(mock_connect); - session_deps.socket_factory.AddSocketDataProvider(&first_data); - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(ASYNC, OK), - }; - StaticSocketDataProvider second_data( - data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&second_data); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpServerProperties* http_server_properties = - session->http_server_properties(); - const int kRestrictedAlternatePort = 80; - http_server_properties->SetAlternateProtocol( - HostPortPair::FromURL(restricted_port_request.url), - kRestrictedAlternatePort, - NPN_SPDY_21); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - - int rv = trans->Start( - &restricted_port_request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - // Valid change to restricted port should pass. - EXPECT_EQ(OK, callback.WaitForResult()); - - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - AlternateProtocolPortUnrestrictedAllowed1) { - // Ensure that we're not allowed to redirect traffic via an alternate - // protocol to an unrestricted (port >= 1024) when the original traffic was - // on a restricted port (port < 1024). Ensure that we can redirect in all - // other cases. - HttpStreamFactory::set_use_alternate_protocols(true); - SessionDependencies session_deps; - - HttpRequestInfo unrestricted_port_request; - unrestricted_port_request.method = "GET"; - unrestricted_port_request.url = GURL("http://www.google.com:1024/"); - unrestricted_port_request.load_flags = 0; - - MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); - StaticSocketDataProvider first_data; - first_data.set_connect_data(mock_connect); - session_deps.socket_factory.AddSocketDataProvider(&first_data); - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(ASYNC, OK), - }; - StaticSocketDataProvider second_data( - data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&second_data); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpServerProperties* http_server_properties = - session->http_server_properties(); - const int kRestrictedAlternatePort = 80; - http_server_properties->SetAlternateProtocol( - HostPortPair::FromURL(unrestricted_port_request.url), - kRestrictedAlternatePort, - NPN_SPDY_21); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - - int rv = trans->Start( - &unrestricted_port_request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - // Valid change to restricted port should pass. - EXPECT_EQ(OK, callback.WaitForResult()); - - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - AlternateProtocolPortUnrestrictedAllowed2) { - // Ensure that we're not allowed to redirect traffic via an alternate - // protocol to an unrestricted (port >= 1024) when the original traffic was - // on a restricted port (port < 1024). Ensure that we can redirect in all - // other cases. - HttpStreamFactory::set_use_alternate_protocols(true); - SessionDependencies session_deps; - - HttpRequestInfo unrestricted_port_request; - unrestricted_port_request.method = "GET"; - unrestricted_port_request.url = GURL("http://www.google.com:1024/"); - unrestricted_port_request.load_flags = 0; - - MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED); - StaticSocketDataProvider first_data; - first_data.set_connect_data(mock_connect); - session_deps.socket_factory.AddSocketDataProvider(&first_data); - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(ASYNC, OK), - }; - StaticSocketDataProvider second_data( - data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&second_data); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpServerProperties* http_server_properties = - session->http_server_properties(); - const int kUnrestrictedAlternatePort = 1024; - http_server_properties->SetAlternateProtocol( - HostPortPair::FromURL(unrestricted_port_request.url), - kUnrestrictedAlternatePort, - NPN_SPDY_21); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - - int rv = trans->Start( - &unrestricted_port_request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - // Valid change to an unrestricted port should pass. - EXPECT_EQ(OK, callback.WaitForResult()); - - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - AlternateProtocolUnsafeBlocked) { - // Ensure that we're not allowed to redirect traffic via an alternate - // protocol to an unsafe port, and that we resume the second - // HttpStreamFactoryImpl::Job once the alternate protocol request fails. - HttpStreamFactory::set_use_alternate_protocols(true); - SessionDependencies session_deps; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - // The alternate protocol request will error out before we attempt to connect, - // so only the standard HTTP request will try to connect. - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(ASYNC, OK), - }; - StaticSocketDataProvider data( - data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpServerProperties* http_server_properties = - session->http_server_properties(); - const int kUnsafePort = 7; - http_server_properties->SetAlternateProtocol( - HostPortPair::FromURL(request.url), - kUnsafePort, - NPN_SPDY_2); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - // The HTTP request should succeed. - EXPECT_EQ(OK, callback.WaitForResult()); - - // Disable alternate protocol before the asserts. - HttpStreamFactory::set_use_alternate_protocols(false); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello world", response_data); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - UseAlternateProtocolForNpnSpdy) { - HttpStreamFactory::set_use_alternate_protocols(true); - HttpStreamFactory::SetNextProtos(SpdyNextProtos()); - SessionDependencies session_deps; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead(kAlternateProtocolHttpHeader), - MockRead("hello world"), - MockRead(ASYNC, OK), - }; - - StaticSocketDataProvider first_transaction( - data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&first_transaction); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite spdy_writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); - MockRead spdy_reads[] = { - CreateMockRead(*resp), - CreateMockRead(*data), - MockRead(ASYNC, 0, 0), - }; - - scoped_ptr<DelayedSocketData> spdy_data( - new DelayedSocketData( - 1, // wait for one write to finish before reading. - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); - StaticSocketDataProvider hanging_non_alternate_protocol_socket( - NULL, 0, NULL, 0); - hanging_non_alternate_protocol_socket.set_connect_data( - never_finishing_connect); - session_deps.socket_factory.AddSocketDataProvider( - &hanging_non_alternate_protocol_socket); - - TestCompletionCallback callback; - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello world", response_data); - - trans.reset(new HttpNetworkTransaction(session)); - - rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_TRUE(response->was_fetched_via_spdy); - EXPECT_TRUE(response->was_npn_negotiated); - - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello!", response_data); - - HttpStreamFactory::SetNextProtos(std::vector<std::string>()); - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, AlternateProtocolWithSpdyLateBinding) { - HttpStreamFactory::set_use_alternate_protocols(true); - HttpStreamFactory::SetNextProtos(SpdyNextProtos()); - SessionDependencies session_deps; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead(kAlternateProtocolHttpHeader), - MockRead("hello world"), - MockRead(ASYNC, OK), - }; - - StaticSocketDataProvider first_transaction( - data_reads, arraysize(data_reads), NULL, 0); - // Socket 1 is the HTTP transaction with the Alternate-Protocol header. - session_deps.socket_factory.AddSocketDataProvider(&first_transaction); - - MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); - StaticSocketDataProvider hanging_socket( - NULL, 0, NULL, 0); - hanging_socket.set_connect_data(never_finishing_connect); - // Socket 2 and 3 are the hanging Alternate-Protocol and - // non-Alternate-Protocol jobs from the 2nd transaction. - session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); - session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - scoped_ptr<SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); - MockWrite spdy_writes[] = { - CreateMockWrite(*req1), - CreateMockWrite(*req2), - }; - scoped_ptr<SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> data1(ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> data2(ConstructSpdyBodyFrame(3, true)); - MockRead spdy_reads[] = { - CreateMockRead(*resp1), - CreateMockRead(*data1), - CreateMockRead(*resp2), - CreateMockRead(*data2), - MockRead(ASYNC, 0, 0), - }; - - scoped_ptr<DelayedSocketData> spdy_data( - new DelayedSocketData( - 2, // wait for writes to finish before reading. - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - // Socket 4 is the successful Alternate-Protocol for transaction 3. - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - // Socket 5 is the unsuccessful non-Alternate-Protocol for transaction 3. - session_deps.socket_factory.AddSocketDataProvider(&hanging_socket); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - TestCompletionCallback callback1; - HttpNetworkTransaction trans1(session); - - int rv = trans1.Start(&request, callback1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback1.WaitForResult()); - - const HttpResponseInfo* response = trans1.GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); - EXPECT_EQ("hello world", response_data); - - TestCompletionCallback callback2; - HttpNetworkTransaction trans2(session); - rv = trans2.Start(&request, callback2.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - TestCompletionCallback callback3; - HttpNetworkTransaction trans3(session); - rv = trans3.Start(&request, callback3.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - EXPECT_EQ(OK, callback2.WaitForResult()); - EXPECT_EQ(OK, callback3.WaitForResult()); - - response = trans2.GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_TRUE(response->was_fetched_via_spdy); - EXPECT_TRUE(response->was_npn_negotiated); - ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); - EXPECT_EQ("hello!", response_data); - - response = trans3.GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_TRUE(response->was_fetched_via_spdy); - EXPECT_TRUE(response->was_npn_negotiated); - ASSERT_EQ(OK, ReadTransaction(&trans3, &response_data)); - EXPECT_EQ("hello!", response_data); - - HttpStreamFactory::SetNextProtos(std::vector<std::string>()); - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, StallAlternateProtocolForNpnSpdy) { - HttpStreamFactory::set_use_alternate_protocols(true); - HttpStreamFactory::SetNextProtos(SpdyNextProtos()); - SessionDependencies session_deps; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead(kAlternateProtocolHttpHeader), - MockRead("hello world"), - MockRead(ASYNC, OK), - }; - - StaticSocketDataProvider first_transaction( - data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&first_transaction); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); - StaticSocketDataProvider hanging_alternate_protocol_socket( - NULL, 0, NULL, 0); - hanging_alternate_protocol_socket.set_connect_data( - never_finishing_connect); - session_deps.socket_factory.AddSocketDataProvider( - &hanging_alternate_protocol_socket); - - // 2nd request is just a copy of the first one, over HTTP again. - session_deps.socket_factory.AddSocketDataProvider(&first_transaction); - - TestCompletionCallback callback; - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello world", response_data); - - trans.reset(new HttpNetworkTransaction(session)); - - rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_FALSE(response->was_fetched_via_spdy); - EXPECT_FALSE(response->was_npn_negotiated); - - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello world", response_data); - - HttpStreamFactory::SetNextProtos(std::vector<std::string>()); - HttpStreamFactory::set_use_alternate_protocols(false); -} - -class CapturingProxyResolver : public ProxyResolver { - public: - CapturingProxyResolver() : ProxyResolver(false /* expects_pac_bytes */) {} - virtual ~CapturingProxyResolver() {} - - virtual int GetProxyForURL(const GURL& url, - ProxyInfo* results, - const CompletionCallback& callback, - RequestHandle* request, - const BoundNetLog& net_log) { - ProxyServer proxy_server(ProxyServer::SCHEME_HTTP, - HostPortPair("myproxy", 80)); - results->UseProxyServer(proxy_server); - resolved_.push_back(url); - return OK; - } - - virtual void CancelRequest(RequestHandle request) { - NOTREACHED(); - } - - virtual LoadState GetLoadState(RequestHandle request) const OVERRIDE { - NOTREACHED(); - return LOAD_STATE_IDLE; - } - - virtual LoadState GetLoadStateThreadSafe( - RequestHandle request) const OVERRIDE { - NOTREACHED(); - return LOAD_STATE_IDLE; - } - - virtual void CancelSetPacScript() { - NOTREACHED(); - } - - virtual int SetPacScript(const scoped_refptr<ProxyResolverScriptData>&, - const CompletionCallback& /*callback*/) { - return OK; - } - - const std::vector<GURL>& resolved() const { return resolved_; } - - private: - std::vector<GURL> resolved_; - - DISALLOW_COPY_AND_ASSIGN(CapturingProxyResolver); -}; - -TEST_F(HttpNetworkTransactionSpdy21Test, - UseAlternateProtocolForTunneledNpnSpdy) { - HttpStreamFactory::set_use_alternate_protocols(true); - HttpStreamFactory::SetNextProtos(SpdyNextProtos()); - - ProxyConfig proxy_config; - proxy_config.set_auto_detect(true); - proxy_config.set_pac_url(GURL("http://fooproxyurl")); - - CapturingProxyResolver* capturing_proxy_resolver = - new CapturingProxyResolver(); - SessionDependencies session_deps(new ProxyService( - new ProxyConfigServiceFixed(proxy_config), capturing_proxy_resolver, - NULL)); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead(kAlternateProtocolHttpHeader), - MockRead("hello world"), - MockRead(ASYNC, OK), - }; - - StaticSocketDataProvider first_transaction( - data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&first_transaction); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite spdy_writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), // 0 - CreateMockWrite(*req) // 3 - }; - - const char kCONNECTResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); - MockRead spdy_reads[] = { - MockRead(ASYNC, kCONNECTResponse, arraysize(kCONNECTResponse) - 1, 1), // 1 - CreateMockRead(*resp.get(), 4), // 2, 4 - CreateMockRead(*data.get(), 4), // 5 - MockRead(ASYNC, 0, 0, 4), // 6 - }; - - scoped_ptr<OrderedSocketData> spdy_data( - new OrderedSocketData( - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); - StaticSocketDataProvider hanging_non_alternate_protocol_socket( - NULL, 0, NULL, 0); - hanging_non_alternate_protocol_socket.set_connect_data( - never_finishing_connect); - session_deps.socket_factory.AddSocketDataProvider( - &hanging_non_alternate_protocol_socket); - - TestCompletionCallback callback; - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_FALSE(response->was_fetched_via_spdy); - EXPECT_FALSE(response->was_npn_negotiated); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello world", response_data); - - trans.reset(new HttpNetworkTransaction(session)); - - rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_TRUE(response->was_fetched_via_spdy); - EXPECT_TRUE(response->was_npn_negotiated); - - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello!", response_data); - ASSERT_EQ(3u, capturing_proxy_resolver->resolved().size()); - EXPECT_EQ("http://www.google.com/", - capturing_proxy_resolver->resolved()[0].spec()); - EXPECT_EQ("https://www.google.com/", - capturing_proxy_resolver->resolved()[1].spec()); - - HttpStreamFactory::SetNextProtos(std::vector<std::string>()); - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, - UseAlternateProtocolForNpnSpdyWithExistingSpdySession) { - HttpStreamFactory::set_use_alternate_protocols(true); - HttpStreamFactory::SetNextProtos(SpdyNextProtos()); - SessionDependencies session_deps; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead(kAlternateProtocolHttpHeader), - MockRead("hello world"), - MockRead(ASYNC, OK), - }; - - StaticSocketDataProvider first_transaction( - data_reads, arraysize(data_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&first_transaction); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite spdy_writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); - MockRead spdy_reads[] = { - CreateMockRead(*resp), - CreateMockRead(*data), - MockRead(ASYNC, 0, 0), - }; - - scoped_ptr<DelayedSocketData> spdy_data( - new DelayedSocketData( - 1, // wait for one write to finish before reading. - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - TestCompletionCallback callback; - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello world", response_data); - - // Set up an initial SpdySession in the pool to reuse. - HostPortPair host_port_pair("www.google.com", 443); - HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); - scoped_refptr<SpdySession> spdy_session = - session->spdy_session_pool()->Get(pair, BoundNetLog()); - scoped_refptr<TransportSocketParams> transport_params( - new TransportSocketParams(host_port_pair, MEDIUM, false, false)); - - scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); - EXPECT_EQ(ERR_IO_PENDING, - connection->Init(host_port_pair.ToString(), - transport_params, - LOWEST, - callback.callback(), - session->GetTransportSocketPool( - HttpNetworkSession::NORMAL_SOCKET_POOL), - BoundNetLog())); - EXPECT_EQ(OK, callback.WaitForResult()); - - SSLConfig ssl_config; - session->ssl_config_service()->GetSSLConfig(&ssl_config); - scoped_ptr<ClientSocketHandle> ssl_connection(new ClientSocketHandle); - SSLClientSocketContext context; - context.cert_verifier = session_deps.cert_verifier.get(); - ssl_connection->set_socket(session_deps.socket_factory.CreateSSLClientSocket( - connection.release(), HostPortPair("" , 443), ssl_config, - NULL /* ssl_host_info */, context)); - EXPECT_EQ(ERR_IO_PENDING, - ssl_connection->socket()->Connect(callback.callback())); - EXPECT_EQ(OK, callback.WaitForResult()); - - EXPECT_EQ(OK, spdy_session->InitializeWithSocket(ssl_connection.release(), - true, OK)); - - trans.reset(new HttpNetworkTransaction(session)); - - rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_TRUE(response->was_fetched_via_spdy); - EXPECT_TRUE(response->was_npn_negotiated); - - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello!", response_data); - - HttpStreamFactory::SetNextProtos(std::vector<std::string>()); - HttpStreamFactory::set_use_alternate_protocols(false); -} - -// GenerateAuthToken is a mighty big test. -// It tests all permutation of GenerateAuthToken behavior: -// - Synchronous and Asynchronous completion. -// - OK or error on completion. -// - Direct connection, non-authenticating proxy, and authenticating proxy. -// - HTTP or HTTPS backend (to include proxy tunneling). -// - Non-authenticating and authenticating backend. -// -// In all, there are 44 reasonable permuations (for example, if there are -// problems generating an auth token for an authenticating proxy, we don't -// need to test all permutations of the backend server). -// -// The test proceeds by going over each of the configuration cases, and -// potentially running up to three rounds in each of the tests. The TestConfig -// specifies both the configuration for the test as well as the expectations -// for the results. -TEST_F(HttpNetworkTransactionSpdy21Test, GenerateAuthToken) { - static const char kServer[] = "http://www.example.com"; - static const char kSecureServer[] = "https://www.example.com"; - static const char kProxy[] = "myproxy:70"; - const int kAuthErr = ERR_INVALID_AUTH_CREDENTIALS; - - enum AuthTiming { - AUTH_NONE, - AUTH_SYNC, - AUTH_ASYNC, - }; - - const MockWrite kGet( - "GET / HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Connection: keep-alive\r\n\r\n"); - const MockWrite kGetProxy( - "GET http://www.example.com/ HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"); - const MockWrite kGetAuth( - "GET / HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: auth_token\r\n\r\n"); - const MockWrite kGetProxyAuth( - "GET http://www.example.com/ HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: auth_token\r\n\r\n"); - const MockWrite kGetAuthThroughProxy( - "GET http://www.example.com/ HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Authorization: auth_token\r\n\r\n"); - const MockWrite kGetAuthWithProxyAuth( - "GET http://www.example.com/ HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: auth_token\r\n" - "Authorization: auth_token\r\n\r\n"); - const MockWrite kConnect( - "CONNECT www.example.com:443 HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"); - const MockWrite kConnectProxyAuth( - "CONNECT www.example.com:443 HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: auth_token\r\n\r\n"); - - const MockRead kSuccess( - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html; charset=iso-8859-1\r\n" - "Content-Length: 3\r\n\r\n" - "Yes"); - const MockRead kFailure( - "Should not be called."); - const MockRead kServerChallenge( - "HTTP/1.1 401 Unauthorized\r\n" - "WWW-Authenticate: Mock realm=server\r\n" - "Content-Type: text/html; charset=iso-8859-1\r\n" - "Content-Length: 14\r\n\r\n" - "Unauthorized\r\n"); - const MockRead kProxyChallenge( - "HTTP/1.1 407 Unauthorized\r\n" - "Proxy-Authenticate: Mock realm=proxy\r\n" - "Proxy-Connection: close\r\n" - "Content-Type: text/html; charset=iso-8859-1\r\n" - "Content-Length: 14\r\n\r\n" - "Unauthorized\r\n"); - const MockRead kProxyConnected( - "HTTP/1.1 200 Connection Established\r\n\r\n"); - - // NOTE(cbentzel): I wanted TestReadWriteRound to be a simple struct with - // no constructors, but the C++ compiler on Windows warns about - // unspecified data in compound literals. So, moved to using constructors, - // and TestRound's created with the default constructor should not be used. - struct TestRound { - TestRound() - : expected_rv(ERR_UNEXPECTED), - extra_write(NULL), - extra_read(NULL) { - } - TestRound(const MockWrite& write_arg, const MockRead& read_arg, - int expected_rv_arg) - : write(write_arg), - read(read_arg), - expected_rv(expected_rv_arg), - extra_write(NULL), - extra_read(NULL) { - } - TestRound(const MockWrite& write_arg, const MockRead& read_arg, - int expected_rv_arg, const MockWrite* extra_write_arg, - const MockWrite* extra_read_arg) - : write(write_arg), - read(read_arg), - expected_rv(expected_rv_arg), - extra_write(extra_write_arg), - extra_read(extra_read_arg) { - } - MockWrite write; - MockRead read; - int expected_rv; - const MockWrite* extra_write; - const MockRead* extra_read; - }; - - static const int kNoSSL = 500; - - struct TestConfig { - const char* proxy_url; - AuthTiming proxy_auth_timing; - int proxy_auth_rv; - const char* server_url; - AuthTiming server_auth_timing; - int server_auth_rv; - int num_auth_rounds; - int first_ssl_round; - TestRound rounds[3]; - } test_configs[] = { - // Non-authenticating HTTP server with a direct connection. - { NULL, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL, - { TestRound(kGet, kSuccess, OK)}}, - // Authenticating HTTP server with a direct connection. - { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL, - { TestRound(kGet, kServerChallenge, OK), - TestRound(kGetAuth, kSuccess, OK)}}, - { NULL, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL, - { TestRound(kGet, kServerChallenge, OK), - TestRound(kGetAuth, kFailure, kAuthErr)}}, - { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL, - { TestRound(kGet, kServerChallenge, OK), - TestRound(kGetAuth, kSuccess, OK)}}, - { NULL, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL, - { TestRound(kGet, kServerChallenge, OK), - TestRound(kGetAuth, kFailure, kAuthErr)}}, - // Non-authenticating HTTP server through a non-authenticating proxy. - { kProxy, AUTH_NONE, OK, kServer, AUTH_NONE, OK, 1, kNoSSL, - { TestRound(kGetProxy, kSuccess, OK)}}, - // Authenticating HTTP server through a non-authenticating proxy. - { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, OK, 2, kNoSSL, - { TestRound(kGetProxy, kServerChallenge, OK), - TestRound(kGetAuthThroughProxy, kSuccess, OK)}}, - { kProxy, AUTH_NONE, OK, kServer, AUTH_SYNC, kAuthErr, 2, kNoSSL, - { TestRound(kGetProxy, kServerChallenge, OK), - TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}}, - { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, OK, 2, kNoSSL, - { TestRound(kGetProxy, kServerChallenge, OK), - TestRound(kGetAuthThroughProxy, kSuccess, OK)}}, - { kProxy, AUTH_NONE, OK, kServer, AUTH_ASYNC, kAuthErr, 2, kNoSSL, - { TestRound(kGetProxy, kServerChallenge, OK), - TestRound(kGetAuthThroughProxy, kFailure, kAuthErr)}}, - // Non-authenticating HTTP server through an authenticating proxy. - { kProxy, AUTH_SYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kSuccess, OK)}}, - { kProxy, AUTH_SYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kFailure, kAuthErr)}}, - { kProxy, AUTH_ASYNC, OK, kServer, AUTH_NONE, OK, 2, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kSuccess, OK)}}, - { kProxy, AUTH_ASYNC, kAuthErr, kServer, AUTH_NONE, OK, 2, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kFailure, kAuthErr)}}, - // Authenticating HTTP server through an authenticating proxy. - { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kServerChallenge, OK), - TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, - { kProxy, AUTH_SYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kServerChallenge, OK), - TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, - { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, OK, 3, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kServerChallenge, OK), - TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, - { kProxy, AUTH_ASYNC, OK, kServer, AUTH_SYNC, kAuthErr, 3, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kServerChallenge, OK), - TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, - { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kServerChallenge, OK), - TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, - { kProxy, AUTH_SYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kServerChallenge, OK), - TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, - { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, OK, 3, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kServerChallenge, OK), - TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}}, - { kProxy, AUTH_ASYNC, OK, kServer, AUTH_ASYNC, kAuthErr, 3, kNoSSL, - { TestRound(kGetProxy, kProxyChallenge, OK), - TestRound(kGetProxyAuth, kServerChallenge, OK), - TestRound(kGetAuthWithProxyAuth, kFailure, kAuthErr)}}, - // Non-authenticating HTTPS server with a direct connection. - { NULL, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0, - { TestRound(kGet, kSuccess, OK)}}, - // Authenticating HTTPS server with a direct connection. - { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0, - { TestRound(kGet, kServerChallenge, OK), - TestRound(kGetAuth, kSuccess, OK)}}, - { NULL, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0, - { TestRound(kGet, kServerChallenge, OK), - TestRound(kGetAuth, kFailure, kAuthErr)}}, - { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0, - { TestRound(kGet, kServerChallenge, OK), - TestRound(kGetAuth, kSuccess, OK)}}, - { NULL, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0, - { TestRound(kGet, kServerChallenge, OK), - TestRound(kGetAuth, kFailure, kAuthErr)}}, - // Non-authenticating HTTPS server with a non-authenticating proxy. - { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_NONE, OK, 1, 0, - { TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}}, - // Authenticating HTTPS server through a non-authenticating proxy. - { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, OK, 2, 0, - { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), - TestRound(kGetAuth, kSuccess, OK)}}, - { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_SYNC, kAuthErr, 2, 0, - { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), - TestRound(kGetAuth, kFailure, kAuthErr)}}, - { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, OK, 2, 0, - { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), - TestRound(kGetAuth, kSuccess, OK)}}, - { kProxy, AUTH_NONE, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 2, 0, - { TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge), - TestRound(kGetAuth, kFailure, kAuthErr)}}, - // Non-Authenticating HTTPS server through an authenticating proxy. - { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}}, - { kProxy, AUTH_SYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kFailure, kAuthErr)}}, - { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_NONE, OK, 2, 1, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}}, - { kProxy, AUTH_ASYNC, kAuthErr, kSecureServer, AUTH_NONE, OK, 2, kNoSSL, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kFailure, kAuthErr)}}, - // Authenticating HTTPS server through an authenticating proxy. - { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kProxyConnected, OK, - &kGet, &kServerChallenge), - TestRound(kGetAuth, kSuccess, OK)}}, - { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kProxyConnected, OK, - &kGet, &kServerChallenge), - TestRound(kGetAuth, kFailure, kAuthErr)}}, - { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, OK, 3, 1, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kProxyConnected, OK, - &kGet, &kServerChallenge), - TestRound(kGetAuth, kSuccess, OK)}}, - { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_SYNC, kAuthErr, 3, 1, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kProxyConnected, OK, - &kGet, &kServerChallenge), - TestRound(kGetAuth, kFailure, kAuthErr)}}, - { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kProxyConnected, OK, - &kGet, &kServerChallenge), - TestRound(kGetAuth, kSuccess, OK)}}, - { kProxy, AUTH_SYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kProxyConnected, OK, - &kGet, &kServerChallenge), - TestRound(kGetAuth, kFailure, kAuthErr)}}, - { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, OK, 3, 1, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kProxyConnected, OK, - &kGet, &kServerChallenge), - TestRound(kGetAuth, kSuccess, OK)}}, - { kProxy, AUTH_ASYNC, OK, kSecureServer, AUTH_ASYNC, kAuthErr, 3, 1, - { TestRound(kConnect, kProxyChallenge, OK), - TestRound(kConnectProxyAuth, kProxyConnected, OK, - &kGet, &kServerChallenge), - TestRound(kGetAuth, kFailure, kAuthErr)}}, - }; - - SessionDependencies session_deps; - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_configs); ++i) { - HttpAuthHandlerMock::Factory* auth_factory( - new HttpAuthHandlerMock::Factory()); - session_deps.http_auth_handler_factory.reset(auth_factory); - const TestConfig& test_config = test_configs[i]; - - // Set up authentication handlers as necessary. - if (test_config.proxy_auth_timing != AUTH_NONE) { - for (int n = 0; n < 2; n++) { - HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); - std::string auth_challenge = "Mock realm=proxy"; - GURL origin(test_config.proxy_url); - HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(), - auth_challenge.end()); - auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_PROXY, - origin, BoundNetLog()); - auth_handler->SetGenerateExpectation( - test_config.proxy_auth_timing == AUTH_ASYNC, - test_config.proxy_auth_rv); - auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); - } - } - if (test_config.server_auth_timing != AUTH_NONE) { - HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); - std::string auth_challenge = "Mock realm=server"; - GURL origin(test_config.server_url); - HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(), - auth_challenge.end()); - auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER, - origin, BoundNetLog()); - auth_handler->SetGenerateExpectation( - test_config.server_auth_timing == AUTH_ASYNC, - test_config.server_auth_rv); - auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER); - } - if (test_config.proxy_url) { - session_deps.proxy_service.reset( - ProxyService::CreateFixed(test_config.proxy_url)); - } else { - session_deps.proxy_service.reset(ProxyService::CreateDirect()); - } - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL(test_config.server_url); - request.load_flags = 0; - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - HttpNetworkTransaction trans(CreateSession(&session_deps)); - - for (int round = 0; round < test_config.num_auth_rounds; ++round) { - const TestRound& read_write_round = test_config.rounds[round]; - - // Set up expected reads and writes. - MockRead reads[2]; - reads[0] = read_write_round.read; - size_t length_reads = 1; - if (read_write_round.extra_read) { - reads[1] = *read_write_round.extra_read; - length_reads = 2; - } - - MockWrite writes[2]; - writes[0] = read_write_round.write; - size_t length_writes = 1; - if (read_write_round.extra_write) { - writes[1] = *read_write_round.extra_write; - length_writes = 2; - } - StaticSocketDataProvider data_provider( - reads, length_reads, writes, length_writes); - session_deps.socket_factory.AddSocketDataProvider(&data_provider); - - // Add an SSL sequence if necessary. - SSLSocketDataProvider ssl_socket_data_provider(SYNCHRONOUS, OK); - if (round >= test_config.first_ssl_round) - session_deps.socket_factory.AddSSLSocketDataProvider( - &ssl_socket_data_provider); - - // Start or restart the transaction. - TestCompletionCallback callback; - int rv; - if (round == 0) { - rv = trans.Start(&request, callback.callback(), BoundNetLog()); - } else { - rv = trans.RestartWithAuth( - AuthCredentials(kFoo, kBar), callback.callback()); - } - if (rv == ERR_IO_PENDING) - rv = callback.WaitForResult(); - - // Compare results with expected data. - EXPECT_EQ(read_write_round.expected_rv, rv); - const HttpResponseInfo* response = trans.GetResponseInfo(); - if (read_write_round.expected_rv == OK) { - ASSERT_TRUE(response != NULL); - } else { - EXPECT_TRUE(response == NULL); - EXPECT_EQ(round + 1, test_config.num_auth_rounds); - continue; - } - if (round + 1 < test_config.num_auth_rounds) { - EXPECT_FALSE(response->auth_challenge.get() == NULL); - } else { - EXPECT_TRUE(response->auth_challenge.get() == NULL); - } - } - } -} - -TEST_F(HttpNetworkTransactionSpdy21Test, MultiRoundAuth) { - // Do multi-round authentication and make sure it works correctly. - SessionDependencies session_deps; - HttpAuthHandlerMock::Factory* auth_factory( - new HttpAuthHandlerMock::Factory()); - session_deps.http_auth_handler_factory.reset(auth_factory); - session_deps.proxy_service.reset(ProxyService::CreateDirect()); - session_deps.host_resolver->rules()->AddRule("www.example.com", "10.0.0.1"); - session_deps.host_resolver->set_synchronous_mode(true); - - HttpAuthHandlerMock* auth_handler(new HttpAuthHandlerMock()); - auth_handler->set_connection_based(true); - std::string auth_challenge = "Mock realm=server"; - GURL origin("http://www.example.com"); - HttpAuth::ChallengeTokenizer tokenizer(auth_challenge.begin(), - auth_challenge.end()); - auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER, - origin, BoundNetLog()); - auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER); - - int rv = OK; - const HttpResponseInfo* response = NULL; - HttpRequestInfo request; - request.method = "GET"; - request.url = origin; - request.load_flags = 0; - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Use a TCP Socket Pool with only one connection per group. This is used - // to validate that the TCP socket is not released to the pool between - // each round of multi-round authentication. - HttpNetworkSessionPeer session_peer(session); - ClientSocketPoolHistograms transport_pool_histograms("SmallTCP"); - TransportClientSocketPool* transport_pool = new TransportClientSocketPool( - 50, // Max sockets for pool - 1, // Max sockets per group - &transport_pool_histograms, - session_deps.host_resolver.get(), - &session_deps.socket_factory, - session_deps.net_log); - MockClientSocketPoolManager* mock_pool_manager = - new MockClientSocketPoolManager; - mock_pool_manager->SetTransportSocketPool(transport_pool); - session_peer.SetClientSocketPoolManager(mock_pool_manager); - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - - const MockWrite kGet( - "GET / HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Connection: keep-alive\r\n\r\n"); - const MockWrite kGetAuth( - "GET / HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Connection: keep-alive\r\n" - "Authorization: auth_token\r\n\r\n"); - - const MockRead kServerChallenge( - "HTTP/1.1 401 Unauthorized\r\n" - "WWW-Authenticate: Mock realm=server\r\n" - "Content-Type: text/html; charset=iso-8859-1\r\n" - "Content-Length: 14\r\n\r\n" - "Unauthorized\r\n"); - const MockRead kSuccess( - "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html; charset=iso-8859-1\r\n" - "Content-Length: 3\r\n\r\n" - "Yes"); - - MockWrite writes[] = { - // First round - kGet, - // Second round - kGetAuth, - // Third round - kGetAuth, - // Fourth round - kGetAuth, - // Competing request - kGet, - }; - MockRead reads[] = { - // First round - kServerChallenge, - // Second round - kServerChallenge, - // Third round - kServerChallenge, - // Fourth round - kSuccess, - // Competing response - kSuccess, - }; - StaticSocketDataProvider data_provider(reads, arraysize(reads), - writes, arraysize(writes)); - session_deps.socket_factory.AddSocketDataProvider(&data_provider); - - const char* const kSocketGroup = "www.example.com:80"; - - // First round of authentication. - auth_handler->SetGenerateExpectation(false, OK); - rv = trans->Start(&request, callback.callback(), BoundNetLog()); - if (rv == ERR_IO_PENDING) - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_FALSE(response->auth_challenge.get() == NULL); - EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); - - // In between rounds, another request comes in for the same domain. - // It should not be able to grab the TCP socket that trans has already - // claimed. - scoped_ptr<HttpTransaction> trans_compete( - new HttpNetworkTransaction(session)); - TestCompletionCallback callback_compete; - rv = trans_compete->Start( - &request, callback_compete.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - // callback_compete.WaitForResult at this point would stall forever, - // since the HttpNetworkTransaction does not release the request back to - // the pool until after authentication completes. - - // Second round of authentication. - auth_handler->SetGenerateExpectation(false, OK); - rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback()); - if (rv == ERR_IO_PENDING) - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); - - // Third round of authentication. - auth_handler->SetGenerateExpectation(false, OK); - rv = trans->RestartWithAuth(AuthCredentials(), callback.callback()); - if (rv == ERR_IO_PENDING) - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); - - // Fourth round of authentication, which completes successfully. - auth_handler->SetGenerateExpectation(false, OK); - rv = trans->RestartWithAuth(AuthCredentials(), callback.callback()); - if (rv == ERR_IO_PENDING) - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->auth_challenge.get() == NULL); - EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); - - // Read the body since the fourth round was successful. This will also - // release the socket back to the pool. - scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(50)); - rv = trans->Read(io_buf, io_buf->size(), callback.callback()); - if (rv == ERR_IO_PENDING) - rv = callback.WaitForResult(); - EXPECT_EQ(3, rv); - rv = trans->Read(io_buf, io_buf->size(), callback.callback()); - EXPECT_EQ(0, rv); - // There are still 0 idle sockets, since the trans_compete transaction - // will be handed it immediately after trans releases it to the group. - EXPECT_EQ(0, transport_pool->IdleSocketCountInGroup(kSocketGroup)); - - // The competing request can now finish. Wait for the headers and then - // read the body. - rv = callback_compete.WaitForResult(); - EXPECT_EQ(OK, rv); - rv = trans_compete->Read(io_buf, io_buf->size(), callback.callback()); - if (rv == ERR_IO_PENDING) - rv = callback.WaitForResult(); - EXPECT_EQ(3, rv); - rv = trans_compete->Read(io_buf, io_buf->size(), callback.callback()); - EXPECT_EQ(0, rv); - - // Finally, the socket is released to the group. - EXPECT_EQ(1, transport_pool->IdleSocketCountInGroup(kSocketGroup)); -} - -class TLSDecompressionFailureSocketDataProvider : public SocketDataProvider { - public: - explicit TLSDecompressionFailureSocketDataProvider(bool fail_all) - : fail_all_(fail_all) { - } - - virtual MockRead GetNextRead() { - if (fail_all_) - return MockRead(SYNCHRONOUS, ERR_SSL_DECOMPRESSION_FAILURE_ALERT); - - return MockRead(SYNCHRONOUS, - "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nok.\r\n"); - } - - virtual MockWriteResult OnWrite(const std::string& data) { - return MockWriteResult(SYNCHRONOUS /* async */, data.size()); - } - - void Reset() { - } - - private: - const bool fail_all_; -}; - -// Test that we restart a connection when we see a decompression failure from -// the peer during the handshake. (In the real world we'll restart with SSLv3 -// and we won't offer DEFLATE in that case.) -TEST_F(HttpNetworkTransactionSpdy21Test, RestartAfterTLSDecompressionFailure) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://tlsdecompressionfailure.example.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - TLSDecompressionFailureSocketDataProvider socket_data_provider1( - false /* fail all reads */); - TLSDecompressionFailureSocketDataProvider socket_data_provider2(false); - SSLSocketDataProvider ssl_socket_data_provider1( - SYNCHRONOUS, ERR_SSL_DECOMPRESSION_FAILURE_ALERT); - SSLSocketDataProvider ssl_socket_data_provider2(SYNCHRONOUS, OK); - session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider1); - session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider2); - session_deps.socket_factory.AddSSLSocketDataProvider( - &ssl_socket_data_provider1); - session_deps.socket_factory.AddSSLSocketDataProvider( - &ssl_socket_data_provider2); - - // Work around http://crbug.com/37454 - StaticSocketDataProvider bug37454_connection; - bug37454_connection.set_connect_data(MockConnect(ASYNC, ERR_UNEXPECTED)); - session_deps.socket_factory.AddSocketDataProvider(&bug37454_connection); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("ok.", response_data); -} - -// Test that we restart a connection if we get a decompression failure from the -// peer while reading the first bytes from the connection. This occurs when the -// peer cannot handle DEFLATE but we're using False Start, so we don't notice -// in the handshake. -TEST_F(HttpNetworkTransactionSpdy21Test, - RestartAfterTLSDecompressionFailureWithFalseStart) { - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://tlsdecompressionfailure2.example.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - TLSDecompressionFailureSocketDataProvider socket_data_provider1( - true /* fail all reads */); - TLSDecompressionFailureSocketDataProvider socket_data_provider2(false); - SSLSocketDataProvider ssl_socket_data_provider1(SYNCHRONOUS, OK); - SSLSocketDataProvider ssl_socket_data_provider2(SYNCHRONOUS, OK); - session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider1); - session_deps.socket_factory.AddSocketDataProvider(&socket_data_provider2); - session_deps.socket_factory.AddSSLSocketDataProvider( - &ssl_socket_data_provider1); - session_deps.socket_factory.AddSSLSocketDataProvider( - &ssl_socket_data_provider2); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("ok.", response_data); -} - -// This tests the case that a request is issued via http instead of spdy after -// npn is negotiated. -TEST_F(HttpNetworkTransactionSpdy21Test, NpnWithHttpOverSSL) { - HttpStreamFactory::set_use_alternate_protocols(true); - HttpStreamFactory::SetNextProtos( - MakeNextProtos("http/1.1", "http1.1", NULL)); - SessionDependencies session_deps; - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - MockWrite data_writes[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead(kAlternateProtocolHttpHeader), - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.next_proto_status = SSLClientSocket::kNextProtoNegotiated; - ssl.next_proto = "http/1.1"; - ssl.protocol_negotiated = kProtoHTTP11; - - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans.get(), &response_data)); - EXPECT_EQ("hello world", response_data); - - EXPECT_FALSE(response->was_fetched_via_spdy); - EXPECT_TRUE(response->was_npn_negotiated); - - HttpStreamFactory::SetNextProtos(std::vector<std::string>()); - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, SpdyPostNPNServerHangup) { - // Simulate the SSL handshake completing with an NPN negotiation - // followed by an immediate server closing of the socket. - // Fix crash: http://crbug.com/46369 - HttpStreamFactory::set_use_alternate_protocols(true); - HttpStreamFactory::SetNextProtos(SpdyNextProtos()); - SessionDependencies session_deps; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite spdy_writes[] = { CreateMockWrite(*req) }; - - MockRead spdy_reads[] = { - MockRead(SYNCHRONOUS, 0, 0) // Not async - return 0 immediately. - }; - - scoped_ptr<DelayedSocketData> spdy_data( - new DelayedSocketData( - 0, // don't wait in this case, immediate hangup. - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - TestCompletionCallback callback; - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.WaitForResult()); - - HttpStreamFactory::SetNextProtos(std::vector<std::string>()); - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, SpdyAlternateProtocolThroughProxy) { - // This test ensures that the URL passed into the proxy is upgraded - // to https when doing an Alternate Protocol upgrade. - HttpStreamFactory::set_use_alternate_protocols(true); - HttpStreamFactory::SetNextProtos( - MakeNextProtos( - "http/1.1", "http1.1", "spdy/2.1", "spdy/2", "spdy", NULL)); - - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - HttpAuthHandlerMock::Factory* auth_factory = - new HttpAuthHandlerMock::Factory(); - HttpAuthHandlerMock* auth_handler = new HttpAuthHandlerMock(); - auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_PROXY); - auth_factory->set_do_init_from_challenge(true); - session_deps.http_auth_handler_factory.reset(auth_factory); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com"); - request.load_flags = 0; - - // First round goes unauthenticated through the proxy. - MockWrite data_writes_1[] = { - MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "\r\n"), - }; - MockRead data_reads_1[] = { - MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), - MockRead("HTTP/1.1 200 OK\r\n" - "Alternate-Protocol: 443:npn-spdy/2.1\r\n" - "Proxy-Connection: close\r\n" - "\r\n"), - }; - StaticSocketDataProvider data_1(data_reads_1, arraysize(data_reads_1), - data_writes_1, arraysize(data_writes_1)); - - // Second round tries to tunnel to www.google.com due to the - // Alternate-Protocol announcement in the first round. It fails due - // to a proxy authentication challenge. - // After the failure, a tunnel is established to www.google.com using - // Proxy-Authorization headers. There is then a SPDY request round. - // - // NOTE: Despite the "Proxy-Connection: Close", these are done on the - // same MockTCPClientSocket since the underlying HttpNetworkClientSocket - // does a Disconnect and Connect on the same socket, rather than trying - // to obtain a new one. - // - // NOTE: Originally, the proxy response to the second CONNECT request - // simply returned another 407 so the unit test could skip the SSL connection - // establishment and SPDY framing issues. Alas, the - // retry-http-when-alternate-protocol fails logic kicks in, which was more - // complicated to set up expectations for than the SPDY session. - - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); - - MockWrite data_writes_2[] = { - // First connection attempt without Proxy-Authorization. - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "\r\n"), - - // Second connection attempt with Proxy-Authorization. - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: auth_token\r\n" - "\r\n"), - - // SPDY request - CreateMockWrite(*req), - }; - const char kRejectConnectResponse[] = ("HTTP/1.1 407 Unauthorized\r\n" - "Proxy-Authenticate: Mock\r\n" - "Proxy-Connection: close\r\n" - "\r\n"); - const char kAcceptConnectResponse[] = "HTTP/1.1 200 Connected\r\n\r\n"; - MockRead data_reads_2[] = { - // First connection attempt fails - MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ, 1), - MockRead(ASYNC, kRejectConnectResponse, - arraysize(kRejectConnectResponse) - 1, 1), - - // Second connection attempt passes - MockRead(ASYNC, kAcceptConnectResponse, - arraysize(kAcceptConnectResponse) -1, 4), - - // SPDY response - CreateMockRead(*resp.get(), 6), - CreateMockRead(*data.get(), 6), - MockRead(ASYNC, 0, 0, 6), - }; - scoped_ptr<OrderedSocketData> data_2( - new OrderedSocketData(data_reads_2, arraysize(data_reads_2), - data_writes_2, arraysize(data_writes_2))); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - - MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); - StaticSocketDataProvider hanging_non_alternate_protocol_socket( - NULL, 0, NULL, 0); - hanging_non_alternate_protocol_socket.set_connect_data( - never_finishing_connect); - - session_deps.socket_factory.AddSocketDataProvider(&data_1); - session_deps.socket_factory.AddSocketDataProvider(data_2.get()); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - session_deps.socket_factory.AddSocketDataProvider( - &hanging_non_alternate_protocol_socket); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // First round should work and provide the Alternate-Protocol state. - TestCompletionCallback callback_1; - scoped_ptr<HttpTransaction> trans_1(new HttpNetworkTransaction(session)); - int rv = trans_1->Start(&request, callback_1.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback_1.WaitForResult()); - - // Second round should attempt a tunnel connect and get an auth challenge. - TestCompletionCallback callback_2; - scoped_ptr<HttpTransaction> trans_2(new HttpNetworkTransaction(session)); - rv = trans_2->Start(&request, callback_2.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback_2.WaitForResult()); - const HttpResponseInfo* response = trans_2->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_FALSE(response->auth_challenge.get() == NULL); - - // Restart with auth. Tunnel should work and response received. - TestCompletionCallback callback_3; - rv = trans_2->RestartWithAuth( - AuthCredentials(kFoo, kBar), callback_3.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback_3.WaitForResult()); - - // After all that work, these two lines (or actually, just the scheme) are - // what this test is all about. Make sure it happens correctly. - const GURL& request_url = auth_handler->request_url(); - EXPECT_EQ("https", request_url.scheme()); - EXPECT_EQ("www.google.com", request_url.host()); - - HttpStreamFactory::SetNextProtos(std::vector<std::string>()); - HttpStreamFactory::set_use_alternate_protocols(false); -} - -// Test that if we cancel the transaction as the connection is completing, that -// everything tears down correctly. -TEST_F(HttpNetworkTransactionSpdy21Test, SimpleCancel) { - // Setup everything about the connection to complete synchronously, so that - // after calling HttpNetworkTransaction::Start, the only thing we're waiting - // for is the callback from the HttpStreamRequest. - // Then cancel the transaction. - // Verify that we don't crash. - MockConnect mock_connect(SYNCHRONOUS, OK); - MockRead data_reads[] = { - MockRead(SYNCHRONOUS, "HTTP/1.0 200 OK\r\n\r\n"), - MockRead(SYNCHRONOUS, "hello world"), - MockRead(SYNCHRONOUS, OK), - }; - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - - SessionDependencies session_deps; - session_deps.host_resolver->set_synchronous_mode(true); - scoped_ptr<HttpTransaction> trans( - new HttpNetworkTransaction(CreateSession(&session_deps))); - - StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0); - data.set_connect_data(mock_connect); - session_deps.socket_factory.AddSocketDataProvider(&data); - - TestCompletionCallback callback; - - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - int rv = trans->Start(&request, callback.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - trans.reset(); // Cancel the transaction here. - - MessageLoop::current()->RunAllPending(); -} - -// Test a basic GET request through a proxy. -TEST_F(HttpNetworkTransactionSpdy21Test, ProxyGet) { - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - - MockWrite data_writes1[] = { - MockWrite("GET http://www.google.com/ HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_EQ(100, response->headers->GetContentLength()); - EXPECT_TRUE(response->was_fetched_via_proxy); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); -} - -// Test a basic HTTPS GET request through a proxy. -TEST_F(HttpNetworkTransactionSpdy21Test, ProxyTunnelGet) { - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - - // Since we have proxy, should try to establish tunnel. - MockWrite data_writes1[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), - - MockRead("HTTP/1.1 200 OK\r\n"), - MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"), - MockRead("Content-Length: 100\r\n\r\n"), - MockRead(SYNCHRONOUS, OK), - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - SSLSocketDataProvider ssl(ASYNC, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(OK, rv); - net::CapturingNetLog::EntryList entries; - log.GetEntries(&entries); - size_t pos = ExpectLogContainsSomewhere( - entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - NetLog::PHASE_NONE); - ExpectLogContainsSomewhere( - entries, pos, - NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - NetLog::PHASE_NONE); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - - EXPECT_TRUE(response->headers->IsKeepAlive()); - EXPECT_EQ(200, response->headers->response_code()); - EXPECT_EQ(100, response->headers->GetContentLength()); - EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion()); - EXPECT_TRUE(response->was_fetched_via_proxy); -} - -// Test a basic HTTPS GET request through a proxy, but the server hangs up -// while establishing the tunnel. -TEST_F(HttpNetworkTransactionSpdy21Test, ProxyTunnelGetHangup) { - SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - - // Since we have proxy, should try to establish tunnel. - MockWrite data_writes1[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - - MockRead data_reads1[] = { - MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ), - MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"), - MockRead(ASYNC, 0, 0), // EOF - }; - - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), - data_writes1, arraysize(data_writes1)); - session_deps.socket_factory.AddSocketDataProvider(&data1); - SSLSocketDataProvider ssl(ASYNC, OK); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - TestCompletionCallback callback1; - - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback1.callback(), log.bound()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback1.WaitForResult(); - EXPECT_EQ(ERR_EMPTY_RESPONSE, rv); - net::CapturingNetLog::EntryList entries; - log.GetEntries(&entries); - size_t pos = ExpectLogContainsSomewhere( - entries, 0, NetLog::TYPE_HTTP_TRANSACTION_SEND_TUNNEL_HEADERS, - NetLog::PHASE_NONE); - ExpectLogContainsSomewhere( - entries, pos, - NetLog::TYPE_HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS, - NetLog::PHASE_NONE); -} - -// Test for crbug.com/55424. -TEST_F(HttpNetworkTransactionSpdy21Test, PreconnectWithExistingSpdySession) { - SessionDependencies session_deps; - - scoped_ptr<SpdyFrame> req(ConstructSpdyGet( - "https://www.google.com", false, 1, LOWEST)); - MockWrite spdy_writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> data(ConstructSpdyBodyFrame(1, true)); - MockRead spdy_reads[] = { - CreateMockRead(*resp), - CreateMockRead(*data), - MockRead(ASYNC, 0, 0), - }; - - scoped_ptr<DelayedSocketData> spdy_data( - new DelayedSocketData( - 1, // wait for one write to finish before reading. - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - - // Set up an initial SpdySession in the pool to reuse. - HostPortPair host_port_pair("www.google.com", 443); - HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); - scoped_refptr<SpdySession> spdy_session = - session->spdy_session_pool()->Get(pair, BoundNetLog()); - scoped_refptr<TransportSocketParams> transport_params( - new TransportSocketParams(host_port_pair, MEDIUM, false, false)); - TestCompletionCallback callback; - - scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); - EXPECT_EQ(ERR_IO_PENDING, - connection->Init(host_port_pair.ToString(), - transport_params, - LOWEST, - callback.callback(), - session->GetTransportSocketPool( - HttpNetworkSession::NORMAL_SOCKET_POOL), - BoundNetLog())); - EXPECT_EQ(OK, callback.WaitForResult()); - spdy_session->InitializeWithSocket(connection.release(), false, OK); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("https://www.google.com/"); - request.load_flags = 0; - - // This is the important line that marks this as a preconnect. - request.motivation = HttpRequestInfo::PRECONNECT_MOTIVATED; - - scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); -} - -// Given a net error, cause that error to be returned from the first Write() -// call and verify that the HttpTransaction fails with that error. -static void CheckErrorIsPassedBack(int error, IoMode mode) { - net::HttpRequestInfo request_info; - request_info.url = GURL("https://www.example.com/"); - request_info.method = "GET"; - request_info.load_flags = net::LOAD_NORMAL; - - SessionDependencies session_deps; - - SSLSocketDataProvider ssl_data(mode, OK); - net::MockWrite data_writes[] = { - net::MockWrite(mode, error), - }; - net::StaticSocketDataProvider data(NULL, 0, - data_writes, arraysize(data_writes)); - session_deps.socket_factory.AddSocketDataProvider(&data); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); - - TestCompletionCallback callback; - int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); - if (rv == net::ERR_IO_PENDING) - rv = callback.WaitForResult(); - ASSERT_EQ(error, rv); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, SSLWriteCertError) { - // Just check a grab bag of cert errors. - static const int kErrors[] = { - ERR_CERT_COMMON_NAME_INVALID, - ERR_CERT_AUTHORITY_INVALID, - ERR_CERT_DATE_INVALID, - }; - for (size_t i = 0; i < arraysize(kErrors); i++) { - CheckErrorIsPassedBack(kErrors[i], ASYNC); - CheckErrorIsPassedBack(kErrors[i], SYNCHRONOUS); - } -} - -// Ensure that a client certificate is removed from the SSL client auth -// cache when: -// 1) No proxy is involved. -// 2) TLS False Start is disabled. -// 3) The initial TLS handshake requests a client certificate. -// 4) The client supplies an invalid/unacceptable certificate. -TEST_F(HttpNetworkTransactionSpdy21Test, - ClientAuthCertCache_Direct_NoFalseStart) { - net::HttpRequestInfo request_info; - request_info.url = GURL("https://www.example.com/"); - request_info.method = "GET"; - request_info.load_flags = net::LOAD_NORMAL; - - SessionDependencies session_deps; - - scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); - cert_request->host_and_port = "www.example.com:443"; - - // [ssl_]data1 contains the data for the first SSL handshake. When a - // CertificateRequest is received for the first time, the handshake will - // be aborted to allow the caller to provide a certificate. - SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); - ssl_data1.cert_request_info = cert_request.get(); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1); - net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data1); - - // [ssl_]data2 contains the data for the second SSL handshake. When TLS - // False Start is not being used, the result of the SSL handshake will be - // returned as part of the SSLClientSocket::Connect() call. This test - // matches the result of a server sending a handshake_failure alert, - // rather than a Finished message, because it requires a client - // certificate and none was supplied. - SSLSocketDataProvider ssl_data2(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); - ssl_data2.cert_request_info = cert_request.get(); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2); - net::StaticSocketDataProvider data2(NULL, 0, NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - // [ssl_]data3 contains the data for the third SSL handshake. When a - // connection to a server fails during an SSL handshake, - // HttpNetworkTransaction will attempt to fallback to SSLv3 if the initial - // connection was attempted with TLSv1. This is transparent to the caller - // of the HttpNetworkTransaction. Because this test failure is due to - // requiring a client certificate, this fallback handshake should also - // fail. - SSLSocketDataProvider ssl_data3(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); - ssl_data3.cert_request_info = cert_request.get(); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); - net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data3); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); - - // Begin the SSL handshake with the peer. This consumes ssl_data1. - TestCompletionCallback callback; - int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); - ASSERT_EQ(net::ERR_IO_PENDING, rv); - - // Complete the SSL handshake, which should abort due to requiring a - // client certificate. - rv = callback.WaitForResult(); - ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); - - // Indicate that no certificate should be supplied. From the perspective - // of SSLClientCertCache, NULL is just as meaningful as a real - // certificate, so this is the same as supply a - // legitimate-but-unacceptable certificate. - rv = trans->RestartWithCertificate(NULL, callback.callback()); - ASSERT_EQ(net::ERR_IO_PENDING, rv); - - // Ensure the certificate was added to the client auth cache before - // allowing the connection to continue restarting. - scoped_refptr<X509Certificate> client_cert; - ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", - &client_cert)); - ASSERT_EQ(NULL, client_cert.get()); - - // Restart the handshake. This will consume ssl_data2, which fails, and - // then consume ssl_data3, which should also fail. The result code is - // checked against what ssl_data3 should return. - rv = callback.WaitForResult(); - ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); - - // Ensure that the client certificate is removed from the cache on a - // handshake failure. - ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", - &client_cert)); -} - -// Ensure that a client certificate is removed from the SSL client auth -// cache when: -// 1) No proxy is involved. -// 2) TLS False Start is enabled. -// 3) The initial TLS handshake requests a client certificate. -// 4) The client supplies an invalid/unacceptable certificate. -TEST_F(HttpNetworkTransactionSpdy21Test, - ClientAuthCertCache_Direct_FalseStart) { - net::HttpRequestInfo request_info; - request_info.url = GURL("https://www.example.com/"); - request_info.method = "GET"; - request_info.load_flags = net::LOAD_NORMAL; - - SessionDependencies session_deps; - - scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); - cert_request->host_and_port = "www.example.com:443"; - - // When TLS False Start is used, SSLClientSocket::Connect() calls will - // return successfully after reading up to the peer's Certificate message. - // This is to allow the caller to call SSLClientSocket::Write(), which can - // enqueue application data to be sent in the same packet as the - // ChangeCipherSpec and Finished messages. - // The actual handshake will be finished when SSLClientSocket::Read() is - // called, which expects to process the peer's ChangeCipherSpec and - // Finished messages. If there was an error negotiating with the peer, - // such as due to the peer requiring a client certificate when none was - // supplied, the alert sent by the peer won't be processed until Read() is - // called. - - // Like the non-False Start case, when a client certificate is requested by - // the peer, the handshake is aborted during the Connect() call. - // [ssl_]data1 represents the initial SSL handshake with the peer. - SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); - ssl_data1.cert_request_info = cert_request.get(); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1); - net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data1); - - // When a client certificate is supplied, Connect() will not be aborted - // when the peer requests the certificate. Instead, the handshake will - // artificially succeed, allowing the caller to write the HTTP request to - // the socket. The handshake messages are not processed until Read() is - // called, which then detects that the handshake was aborted, due to the - // peer sending a handshake_failure because it requires a client - // certificate. - SSLSocketDataProvider ssl_data2(ASYNC, net::OK); - ssl_data2.cert_request_info = cert_request.get(); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2); - net::MockRead data2_reads[] = { - net::MockRead(ASYNC /* async */, net::ERR_SSL_PROTOCOL_ERROR), - }; - net::StaticSocketDataProvider data2( - data2_reads, arraysize(data2_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - // As described in ClientAuthCertCache_Direct_NoFalseStart, [ssl_]data3 is - // the data for the SSL handshake once the TLSv1 connection falls back to - // SSLv3. It has the same behaviour as [ssl_]data2. - SSLSocketDataProvider ssl_data3(ASYNC, net::OK); - ssl_data3.cert_request_info = cert_request.get(); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); - net::StaticSocketDataProvider data3( - data2_reads, arraysize(data2_reads), NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data3); - - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpNetworkTransaction> trans(new HttpNetworkTransaction(session)); - - // Begin the initial SSL handshake. - TestCompletionCallback callback; - int rv = trans->Start(&request_info, callback.callback(), net::BoundNetLog()); - ASSERT_EQ(net::ERR_IO_PENDING, rv); - - // Complete the SSL handshake, which should abort due to requiring a - // client certificate. - rv = callback.WaitForResult(); - ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); - - // Indicate that no certificate should be supplied. From the perspective - // of SSLClientCertCache, NULL is just as meaningful as a real - // certificate, so this is the same as supply a - // legitimate-but-unacceptable certificate. - rv = trans->RestartWithCertificate(NULL, callback.callback()); - ASSERT_EQ(net::ERR_IO_PENDING, rv); - - // Ensure the certificate was added to the client auth cache before - // allowing the connection to continue restarting. - scoped_refptr<X509Certificate> client_cert; - ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", - &client_cert)); - ASSERT_EQ(NULL, client_cert.get()); - - - // Restart the handshake. This will consume ssl_data2, which fails, and - // then consume ssl_data3, which should also fail. The result code is - // checked against what ssl_data3 should return. - rv = callback.WaitForResult(); - ASSERT_EQ(net::ERR_SSL_PROTOCOL_ERROR, rv); - - // Ensure that the client certificate is removed from the cache on a - // handshake failure. - ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", - &client_cert)); -} - -// Ensure that a client certificate is removed from the SSL client auth -// cache when: -// 1) An HTTPS proxy is involved. -// 3) The HTTPS proxy requests a client certificate. -// 4) The client supplies an invalid/unacceptable certificate for the -// proxy. -// The test is repeated twice, first for connecting to an HTTPS endpoint, -// then for connecting to an HTTP endpoint. -TEST_F(HttpNetworkTransactionSpdy21Test, ClientAuthCertCache_Proxy_Fail) { - SessionDependencies session_deps( - ProxyService::CreateFixed("https://proxy:70")); - CapturingBoundNetLog log(CapturingNetLog::kUnbounded); - session_deps.net_log = log.bound().net_log(); - - scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo()); - cert_request->host_and_port = "proxy:70"; - - // See ClientAuthCertCache_Direct_NoFalseStart for the explanation of - // [ssl_]data[1-3]. Rather than represending the endpoint - // (www.example.com:443), they represent failures with the HTTPS proxy - // (proxy:70). - SSLSocketDataProvider ssl_data1(ASYNC, net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED); - ssl_data1.cert_request_info = cert_request.get(); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data1); - net::StaticSocketDataProvider data1(NULL, 0, NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data1); - - SSLSocketDataProvider ssl_data2(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); - ssl_data2.cert_request_info = cert_request.get(); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data2); - net::StaticSocketDataProvider data2(NULL, 0, NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data2); - - SSLSocketDataProvider ssl_data3(ASYNC, net::ERR_SSL_PROTOCOL_ERROR); - ssl_data3.cert_request_info = cert_request.get(); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl_data3); - net::StaticSocketDataProvider data3(NULL, 0, NULL, 0); - session_deps.socket_factory.AddSocketDataProvider(&data3); - - net::HttpRequestInfo requests[2]; - requests[0].url = GURL("https://www.example.com/"); - requests[0].method = "GET"; - requests[0].load_flags = net::LOAD_NORMAL; - - requests[1].url = GURL("http://www.example.com/"); - requests[1].method = "GET"; - requests[1].load_flags = net::LOAD_NORMAL; - - for (size_t i = 0; i < arraysize(requests); ++i) { - session_deps.socket_factory.ResetNextMockIndexes(); - scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps)); - scoped_ptr<HttpNetworkTransaction> trans( - new HttpNetworkTransaction(session)); - - // Begin the SSL handshake with the proxy. - TestCompletionCallback callback; - int rv = trans->Start( - &requests[i], callback.callback(), net::BoundNetLog()); - ASSERT_EQ(net::ERR_IO_PENDING, rv); - - // Complete the SSL handshake, which should abort due to requiring a - // client certificate. - rv = callback.WaitForResult(); - ASSERT_EQ(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED, rv); - - // Indicate that no certificate should be supplied. From the perspective - // of SSLClientCertCache, NULL is just as meaningful as a real - // certificate, so this is the same as supply a - // legitimate-but-unacceptable certificate. - rv = trans->RestartWithCertificate(NULL, callback.callback()); - ASSERT_EQ(net::ERR_IO_PENDING, rv); - - // Ensure the certificate was added to the client auth cache before - // allowing the connection to continue restarting. - scoped_refptr<X509Certificate> client_cert; - ASSERT_TRUE(session->ssl_client_auth_cache()->Lookup("proxy:70", - &client_cert)); - ASSERT_EQ(NULL, client_cert.get()); - // Ensure the certificate was NOT cached for the endpoint. This only - // applies to HTTPS requests, but is fine to check for HTTP requests. - ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", - &client_cert)); - - // Restart the handshake. This will consume ssl_data2, which fails, and - // then consume ssl_data3, which should also fail. The result code is - // checked against what ssl_data3 should return. - rv = callback.WaitForResult(); - ASSERT_EQ(net::ERR_PROXY_CONNECTION_FAILED, rv); - - // Now that the new handshake has failed, ensure that the client - // certificate was removed from the client auth cache. - ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("proxy:70", - &client_cert)); - ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup("www.example.com:443", - &client_cert)); - } -} - -namespace { - -void IPPoolingAddAlias(MockCachingHostResolver* host_resolver, - SpdySessionPoolPeer* pool_peer, - std::string host, - int port, - std::string iplist) { - // Create a host resolver dependency that returns address |iplist| for - // resolutions of |host|. - host_resolver->rules()->AddIPLiteralRule(host, iplist, ""); - - // Setup a HostPortProxyPair. - HostPortPair host_port_pair(host, port); - HostPortProxyPair pair = HostPortProxyPair(host_port_pair, - ProxyServer::Direct()); - - // Resolve the host and port. - AddressList addresses; - HostResolver::RequestInfo info(host_port_pair); - TestCompletionCallback callback; - int rv = host_resolver->Resolve(info, &addresses, callback.callback(), NULL, - BoundNetLog()); - if (rv == ERR_IO_PENDING) - rv = callback.WaitForResult(); - DCHECK_EQ(OK, rv); - - // Add the first address as an alias. It would have been better to call - // MockClientSocket::GetPeerAddress but that returns 192.0.2.33 whereas - // MockHostResolver returns 127.0.0.1 (MockHostResolverBase::Reset). So we use - // the first address (127.0.0.1) returned by MockHostResolver as an alias for - // the |pair|. - const addrinfo* address = addresses.head(); - pool_peer->AddAlias(address, pair); -} - -} // namespace - -TEST_F(HttpNetworkTransactionSpdy21Test, UseIPConnectionPooling) { - HttpStreamFactory::set_use_alternate_protocols(true); - HttpStreamFactory::SetNextProtos(SpdyNextProtos()); - - // Set up a special HttpNetworkSession with a MockCachingHostResolver. - SessionDependencies session_deps; - MockCachingHostResolver host_resolver; - net::HttpNetworkSession::Params params; - params.client_socket_factory = &session_deps.socket_factory; - params.host_resolver = &host_resolver; - params.cert_verifier = session_deps.cert_verifier.get(); - params.proxy_service = session_deps.proxy_service.get(); - params.ssl_config_service = session_deps.ssl_config_service; - params.http_auth_handler_factory = - session_deps.http_auth_handler_factory.get(); - params.http_server_properties = &session_deps.http_server_properties; - params.net_log = session_deps.net_log; - scoped_refptr<HttpNetworkSession> session(new HttpNetworkSession(params)); - SpdySessionPoolPeer pool_peer(session->spdy_session_pool()); - pool_peer.DisableDomainAuthenticationVerification(); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - scoped_ptr<SpdyFrame> host1_req(ConstructSpdyGet( - "https://www.google.com", false, 1, LOWEST)); - scoped_ptr<SpdyFrame> host2_req(ConstructSpdyGet( - "https://www.gmail.com", false, 3, LOWEST)); - MockWrite spdy_writes[] = { - CreateMockWrite(*host1_req, 1), - CreateMockWrite(*host2_req, 4), - }; - scoped_ptr<SpdyFrame> host1_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> host1_resp_body(ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> host2_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> host2_resp_body(ConstructSpdyBodyFrame(3, true)); - MockRead spdy_reads[] = { - CreateMockRead(*host1_resp, 2), - CreateMockRead(*host1_resp_body, 3), - CreateMockRead(*host2_resp, 5), - CreateMockRead(*host2_resp_body, 6), - MockRead(ASYNC, 0, 7), - }; - - scoped_ptr<OrderedSocketData> spdy_data( - new OrderedSocketData( - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - TestCompletionCallback callback; - HttpRequestInfo request1; - request1.method = "GET"; - request1.url = GURL("https://www.google.com/"); - request1.load_flags = 0; - HttpNetworkTransaction trans1(session); - - int rv = trans1.Start(&request1, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans1.GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); - EXPECT_EQ("hello!", response_data); - - // Preload www.gmail.com into HostCache. - HostPortPair host_port("www.gmail.com", 443); - HostResolver::RequestInfo resolve_info(host_port); - AddressList ignored; - rv = host_resolver.Resolve(resolve_info, &ignored, callback.callback(), NULL, - BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - // MockHostResolver returns 127.0.0.1, port 443 for https://www.google.com/ - // and https://www.gmail.com/. Add 127.0.0.1 as alias for host_port_pair: - // (www.google.com, 443). - IPPoolingAddAlias(&host_resolver, &pool_peer, "www.google.com", 443, - "127.0.0.1"); - - HttpRequestInfo request2; - request2.method = "GET"; - request2.url = GURL("https://www.gmail.com/"); - request2.load_flags = 0; - HttpNetworkTransaction trans2(session); - - rv = trans2.Start(&request2, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - response = trans2.GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_TRUE(response->was_fetched_via_spdy); - EXPECT_TRUE(response->was_npn_negotiated); - ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); - EXPECT_EQ("hello!", response_data); - - HttpStreamFactory::SetNextProtos(std::vector<std::string>()); - HttpStreamFactory::set_use_alternate_protocols(false); -} - -class OneTimeCachingHostResolver : public net::HostResolver { - public: - explicit OneTimeCachingHostResolver(const HostPortPair& host_port) - : host_port_(host_port) {} - virtual ~OneTimeCachingHostResolver() {} - - RuleBasedHostResolverProc* rules() { return host_resolver_.rules(); } - - // HostResolver methods: - virtual int Resolve(const RequestInfo& info, - AddressList* addresses, - const CompletionCallback& callback, - RequestHandle* out_req, - const BoundNetLog& net_log) OVERRIDE { - return host_resolver_.Resolve( - info, addresses, callback, out_req, net_log); - } - - virtual int ResolveFromCache(const RequestInfo& info, - AddressList* addresses, - const BoundNetLog& net_log) OVERRIDE { - int rv = host_resolver_.ResolveFromCache(info, addresses, net_log); - if (rv == OK && info.host_port_pair().Equals(host_port_)) - host_resolver_.GetHostCache()->clear(); - return rv; - } - - virtual void CancelRequest(RequestHandle req) OVERRIDE { - host_resolver_.CancelRequest(req); - } - - MockCachingHostResolver* GetMockHostResolver() { - return &host_resolver_; - } - - private: - MockCachingHostResolver host_resolver_; - const HostPortPair host_port_; -}; - -TEST_F(HttpNetworkTransactionSpdy21Test, - UseIPConnectionPoolingWithHostCacheExpiration) { - HttpStreamFactory::set_use_alternate_protocols(true); - HttpStreamFactory::SetNextProtos(SpdyNextProtos()); - - // Set up a special HttpNetworkSession with a OneTimeCachingHostResolver. - SessionDependencies session_deps; - OneTimeCachingHostResolver host_resolver(HostPortPair("www.gmail.com", 443)); - net::HttpNetworkSession::Params params; - params.client_socket_factory = &session_deps.socket_factory; - params.host_resolver = &host_resolver; - params.cert_verifier = session_deps.cert_verifier.get(); - params.proxy_service = session_deps.proxy_service.get(); - params.ssl_config_service = session_deps.ssl_config_service; - params.http_auth_handler_factory = - session_deps.http_auth_handler_factory.get(); - params.http_server_properties = &session_deps.http_server_properties; - params.net_log = session_deps.net_log; - scoped_refptr<HttpNetworkSession> session(new HttpNetworkSession(params)); - SpdySessionPoolPeer pool_peer(session->spdy_session_pool()); - pool_peer.DisableDomainAuthenticationVerification(); - - SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); - session_deps.socket_factory.AddSSLSocketDataProvider(&ssl); - - scoped_ptr<SpdyFrame> host1_req(ConstructSpdyGet( - "https://www.google.com", false, 1, LOWEST)); - scoped_ptr<SpdyFrame> host2_req(ConstructSpdyGet( - "https://www.gmail.com", false, 3, LOWEST)); - MockWrite spdy_writes[] = { - CreateMockWrite(*host1_req, 1), - CreateMockWrite(*host2_req, 4), - }; - scoped_ptr<SpdyFrame> host1_resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> host1_resp_body(ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> host2_resp(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> host2_resp_body(ConstructSpdyBodyFrame(3, true)); - MockRead spdy_reads[] = { - CreateMockRead(*host1_resp, 2), - CreateMockRead(*host1_resp_body, 3), - CreateMockRead(*host2_resp, 5), - CreateMockRead(*host2_resp_body, 6), - MockRead(ASYNC, 0, 7), - }; - - scoped_ptr<OrderedSocketData> spdy_data( - new OrderedSocketData( - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - session_deps.socket_factory.AddSocketDataProvider(spdy_data.get()); - - TestCompletionCallback callback; - HttpRequestInfo request1; - request1.method = "GET"; - request1.url = GURL("https://www.google.com/"); - request1.load_flags = 0; - HttpNetworkTransaction trans1(session); - - int rv = trans1.Start(&request1, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - const HttpResponseInfo* response = trans1.GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(&trans1, &response_data)); - EXPECT_EQ("hello!", response_data); - - // Preload cache entries into HostCache. - HostResolver::RequestInfo resolve_info(HostPortPair("www.gmail.com", 443)); - AddressList ignored; - rv = host_resolver.Resolve(resolve_info, &ignored, callback.callback(), NULL, - BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - HttpRequestInfo request2; - request2.method = "GET"; - request2.url = GURL("https://www.gmail.com/"); - request2.load_flags = 0; - HttpNetworkTransaction trans2(session); - - // MockHostResolver returns 127.0.0.1, port 443 for https://www.google.com/ - // and https://www.gmail.com/. Add 127.0.0.1 as alias for host_port_pair: - // (www.google.com, 443). - IPPoolingAddAlias(host_resolver.GetMockHostResolver(), &pool_peer, - "www.google.com", 443, "127.0.0.1"); - - rv = trans2.Start(&request2, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_EQ(OK, callback.WaitForResult()); - - response = trans2.GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_TRUE(response->was_fetched_via_spdy); - EXPECT_TRUE(response->was_npn_negotiated); - ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data)); - EXPECT_EQ("hello!", response_data); - - HttpStreamFactory::SetNextProtos(std::vector<std::string>()); - HttpStreamFactory::set_use_alternate_protocols(false); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, ReadPipelineEvictionFallback) { - MockRead data_reads1[] = { - MockRead(SYNCHRONOUS, ERR_PIPELINE_EVICTION), - }; - MockRead data_reads2[] = { - MockRead("HTTP/1.0 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1), NULL, 0); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), NULL, 0); - StaticSocketDataProvider* data[] = { &data1, &data2 }; - - SimpleGetHelperResult out = SimpleGetHelperForData(data, arraysize(data)); - - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); - EXPECT_EQ("hello world", out.response_data); -} - -TEST_F(HttpNetworkTransactionSpdy21Test, SendPipelineEvictionFallback) { - MockWrite data_writes1[] = { - MockWrite(SYNCHRONOUS, ERR_PIPELINE_EVICTION), - }; - MockWrite data_writes2[] = { - MockWrite("GET / HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Connection: keep-alive\r\n\r\n"), - }; - MockRead data_reads2[] = { - MockRead("HTTP/1.0 200 OK\r\n\r\n"), - MockRead("hello world"), - MockRead(SYNCHRONOUS, OK), - }; - StaticSocketDataProvider data1(NULL, 0, - data_writes1, arraysize(data_writes1)); - StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2), - data_writes2, arraysize(data_writes2)); - StaticSocketDataProvider* data[] = { &data1, &data2 }; - - SimpleGetHelperResult out = SimpleGetHelperForData(data, arraysize(data)); - - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.0 200 OK", out.status_line); - EXPECT_EQ("hello world", out.response_data); -} - -} // namespace net diff --git a/net/http/http_network_transaction_spdy3_unittest.cc b/net/http/http_network_transaction_spdy3_unittest.cc index 5255c4d..86a81e4 100644 --- a/net/http/http_network_transaction_spdy3_unittest.cc +++ b/net/http/http_network_transaction_spdy3_unittest.cc @@ -98,7 +98,7 @@ std::vector<std::string> MakeNextProtos(const char* a, ...) { // SpdyNextProtos returns a vector of NPN protocol strings for negotiating // SPDY. std::vector<std::string> SpdyNextProtos() { - return MakeNextProtos("http/1.1", "spdy/2", "spdy/2.1", "spdy/3", NULL); + return MakeNextProtos("http/1.1", "spdy/2", "spdy/3", NULL); } int GetIdleSocketCountInTransportSocketPool(net::HttpNetworkSession* session) { @@ -8453,7 +8453,7 @@ TEST_F(HttpNetworkTransactionSpdy3Test, SpdyAlternateProtocolThroughProxy) { HttpStreamFactory::set_use_alternate_protocols(true); HttpStreamFactory::SetNextProtos( MakeNextProtos( - "http/1.1", "http1.1", "spdy/2", "spdy/2.1", "spdy/3", "spdy", NULL)); + "http/1.1", "http1.1", "spdy/2", "spdy/3", "spdy", NULL)); SessionDependencies session_deps(ProxyService::CreateFixed("myproxy:70")); HttpAuthHandlerMock::Factory* auth_factory = diff --git a/net/http/http_pipelined_host_forced_unittest.cc b/net/http/http_pipelined_host_forced_unittest.cc index 2d3e4ba..04d2158 100644 --- a/net/http/http_pipelined_host_forced_unittest.cc +++ b/net/http/http_pipelined_host_forced_unittest.cc @@ -37,7 +37,7 @@ class HttpPipelinedHostForcedTest : public testing::Test { MatchesOrigin(key_.origin()), Ref(ssl_config_), Ref(proxy_info_), Ref(net_log_), true, - kProtoSPDY21)) + kProtoSPDY2)) .Times(1) .WillOnce(Return(pipeline)); EXPECT_CALL(*pipeline, CreateNewStream()) @@ -45,7 +45,7 @@ class HttpPipelinedHostForcedTest : public testing::Test { .WillOnce(Return(kDummyStream)); EXPECT_EQ(kDummyStream, host_->CreateStreamOnNewPipeline( &connection_, ssl_config_, proxy_info_, net_log_, true, - kProtoSPDY21)); + kProtoSPDY2)); return pipeline; } diff --git a/net/http/http_pipelined_host_impl_unittest.cc b/net/http/http_pipelined_host_impl_unittest.cc index 6fc3a6a..2764edf 100644 --- a/net/http/http_pipelined_host_impl_unittest.cc +++ b/net/http/http_pipelined_host_impl_unittest.cc @@ -48,7 +48,7 @@ class HttpPipelinedHostImplTest : public testing::Test { MatchesOrigin(key_.origin()), Ref(ssl_config_), Ref(proxy_info_), Ref(net_log_), true, - kProtoSPDY21)) + kProtoSPDY2)) .Times(1) .WillOnce(Return(pipeline)); EXPECT_CALL(*pipeline, CreateNewStream()) @@ -56,7 +56,7 @@ class HttpPipelinedHostImplTest : public testing::Test { .WillOnce(Return(kDummyStream)); EXPECT_EQ(kDummyStream, host_->CreateStreamOnNewPipeline( kDummyConnection, ssl_config_, proxy_info_, net_log_, true, - kProtoSPDY21)); + kProtoSPDY2)); return pipeline; } @@ -208,7 +208,7 @@ TEST_F(HttpPipelinedHostImplTest, ShutsDownOnOldVersion) { ClearTestPipeline(pipeline); EXPECT_EQ(NULL, host_->CreateStreamOnNewPipeline( kDummyConnection, ssl_config_, proxy_info_, net_log_, true, - kProtoSPDY21)); + kProtoSPDY2)); } TEST_F(HttpPipelinedHostImplTest, ShutsDownOnAuthenticationRequired) { diff --git a/net/http/http_proxy_client_socket_pool_spdy21_unittest.cc b/net/http/http_proxy_client_socket_pool_spdy21_unittest.cc deleted file mode 100644 index 761cd78..0000000 --- a/net/http/http_proxy_client_socket_pool_spdy21_unittest.cc +++ /dev/null @@ -1,542 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/http/http_proxy_client_socket_pool.h" - -#include "base/callback.h" -#include "base/compiler_specific.h" -#include "base/string_util.h" -#include "base/utf_string_conversions.h" -#include "net/base/mock_host_resolver.h" -#include "net/base/net_errors.h" -#include "net/base/ssl_config_service_defaults.h" -#include "net/base/test_completion_callback.h" -#include "net/http/http_auth_handler_factory.h" -#include "net/http/http_network_session.h" -#include "net/http/http_proxy_client_socket.h" -#include "net/http/http_server_properties_impl.h" -#include "net/proxy/proxy_service.h" -#include "net/socket/client_socket_handle.h" -#include "net/socket/client_socket_pool_histograms.h" -#include "net/socket/socket_test_util.h" -#include "net/spdy/spdy_protocol.h" -#include "net/spdy/spdy_test_util_spdy2.h" -#include "testing/gtest/include/gtest/gtest.h" - -using namespace net::test_spdy2; - -namespace net { - -namespace { - -const int kMaxSockets = 32; -const int kMaxSocketsPerGroup = 6; -const char * const kAuthHeaders[] = { - "proxy-authorization", "Basic Zm9vOmJhcg==" -}; -const int kAuthHeadersSize = arraysize(kAuthHeaders) / 2; - -enum HttpProxyType { - HTTP, - HTTPS, - SPDY -}; - -typedef ::testing::TestWithParam<HttpProxyType> TestWithHttpParam; - -} // namespace - -class HttpProxyClientSocketPoolSpdy21Test : public TestWithHttpParam { - protected: - HttpProxyClientSocketPoolSpdy21Test() - : ssl_config_(), - ignored_transport_socket_params_(new TransportSocketParams( - HostPortPair("proxy", 80), LOWEST, false, false)), - ignored_ssl_socket_params_(new SSLSocketParams( - ignored_transport_socket_params_, NULL, NULL, - ProxyServer::SCHEME_DIRECT, HostPortPair("www.google.com", 443), - ssl_config_, 0, false, false)), - tcp_histograms_("MockTCP"), - transport_socket_pool_( - kMaxSockets, kMaxSocketsPerGroup, - &tcp_histograms_, - &socket_factory_), - ssl_histograms_("MockSSL"), - cert_verifier_(CertVerifier::CreateDefault()), - proxy_service_(ProxyService::CreateDirect()), - ssl_config_service_(new SSLConfigServiceDefaults), - ssl_socket_pool_(kMaxSockets, kMaxSocketsPerGroup, - &ssl_histograms_, - &host_resolver_, - cert_verifier_.get(), - NULL /* server_bound_cert_store */, - NULL /* transport_security_state */, - NULL /* ssl_host_info_factory */, - "" /* ssl_session_cache_shard */, - &socket_factory_, - &transport_socket_pool_, - NULL, - NULL, - ssl_config_service_.get(), - BoundNetLog().net_log()), - http_auth_handler_factory_( - HttpAuthHandlerFactory::CreateDefault(&host_resolver_)), - session_(CreateNetworkSession()), - http_proxy_histograms_("HttpProxyUnitTest"), - ssl_data_(NULL), - data_(NULL), - pool_(kMaxSockets, kMaxSocketsPerGroup, - &http_proxy_histograms_, - NULL, - &transport_socket_pool_, - &ssl_socket_pool_, - NULL) { - } - - virtual ~HttpProxyClientSocketPoolSpdy21Test() { - } - - void AddAuthToCache() { - const string16 kFoo(ASCIIToUTF16("foo")); - const string16 kBar(ASCIIToUTF16("bar")); - GURL proxy_url(GetParam() == HTTP ? "http://proxy" : "https://proxy:80"); - session_->http_auth_cache()->Add(proxy_url, - "MyRealm1", - HttpAuth::AUTH_SCHEME_BASIC, - "Basic realm=MyRealm1", - AuthCredentials(kFoo, kBar), - "/"); - } - - scoped_refptr<TransportSocketParams> GetTcpParams() { - if (GetParam() != HTTP) - return scoped_refptr<TransportSocketParams>(); - return ignored_transport_socket_params_; - } - - scoped_refptr<SSLSocketParams> GetSslParams() { - if (GetParam() == HTTP) - return scoped_refptr<SSLSocketParams>(); - return ignored_ssl_socket_params_; - } - - // Returns the a correctly constructed HttpProxyParms - // for the HTTP or HTTPS proxy. - scoped_refptr<HttpProxySocketParams> GetParams(bool tunnel) { - return scoped_refptr<HttpProxySocketParams>( - new HttpProxySocketParams( - GetTcpParams(), - GetSslParams(), - GURL(tunnel ? "https://www.google.com/" : "http://www.google.com"), - "", - HostPortPair("www.google.com", tunnel ? 443 : 80), - session_->http_auth_cache(), - session_->http_auth_handler_factory(), - session_->spdy_session_pool(), - tunnel)); - } - - scoped_refptr<HttpProxySocketParams> GetTunnelParams() { - return GetParams(true); - } - - scoped_refptr<HttpProxySocketParams> GetNoTunnelParams() { - return GetParams(false); - } - - DeterministicMockClientSocketFactory& socket_factory() { - return socket_factory_; - } - - void Initialize(MockRead* reads, size_t reads_count, - MockWrite* writes, size_t writes_count, - MockRead* spdy_reads, size_t spdy_reads_count, - MockWrite* spdy_writes, size_t spdy_writes_count) { - if (GetParam() == SPDY) - data_ = new DeterministicSocketData(spdy_reads, spdy_reads_count, - spdy_writes, spdy_writes_count); - else - data_ = new DeterministicSocketData(reads, reads_count, writes, - writes_count); - - data_->set_connect_data(MockConnect(SYNCHRONOUS, OK)); - data_->StopAfter(2); // Request / Response - - socket_factory_.AddSocketDataProvider(data_.get()); - - if (GetParam() != HTTP) { - ssl_data_.reset(new SSLSocketDataProvider(SYNCHRONOUS, OK)); - if (GetParam() == SPDY) { - InitializeSpdySsl(); - } - socket_factory_.AddSSLSocketDataProvider(ssl_data_.get()); - } - } - - void InitializeSpdySsl() { - ssl_data_->SetNextProto(kProtoSPDY21); - } - - HttpNetworkSession* CreateNetworkSession() { - HttpNetworkSession::Params params; - params.host_resolver = &host_resolver_; - params.cert_verifier = cert_verifier_.get(); - params.proxy_service = proxy_service_.get(); - params.client_socket_factory = &socket_factory_; - params.ssl_config_service = ssl_config_service_; - params.http_auth_handler_factory = http_auth_handler_factory_.get(); - params.http_server_properties = &http_server_properties_; - return new HttpNetworkSession(params); - } - - private: - SSLConfig ssl_config_; - - scoped_refptr<TransportSocketParams> ignored_transport_socket_params_; - scoped_refptr<SSLSocketParams> ignored_ssl_socket_params_; - ClientSocketPoolHistograms tcp_histograms_; - DeterministicMockClientSocketFactory socket_factory_; - MockTransportClientSocketPool transport_socket_pool_; - ClientSocketPoolHistograms ssl_histograms_; - MockHostResolver host_resolver_; - scoped_ptr<CertVerifier> cert_verifier_; - const scoped_ptr<ProxyService> proxy_service_; - const scoped_refptr<SSLConfigService> ssl_config_service_; - SSLClientSocketPool ssl_socket_pool_; - - const scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_; - HttpServerPropertiesImpl http_server_properties_; - const scoped_refptr<HttpNetworkSession> session_; - ClientSocketPoolHistograms http_proxy_histograms_; - SpdyTestStateHelper spdy_state_; - - protected: - scoped_ptr<SSLSocketDataProvider> ssl_data_; - scoped_refptr<DeterministicSocketData> data_; - HttpProxyClientSocketPool pool_; - ClientSocketHandle handle_; - TestCompletionCallback callback_; -}; - -//----------------------------------------------------------------------------- -// All tests are run with three different proxy types: HTTP, HTTPS (non-SPDY) -// and SPDY. -INSTANTIATE_TEST_CASE_P(HttpProxyClientSocketPoolSpdy21Tests, - HttpProxyClientSocketPoolSpdy21Test, - ::testing::Values(HTTP, HTTPS, SPDY)); - -TEST_P(HttpProxyClientSocketPoolSpdy21Test, NoTunnel) { - Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0); - - int rv = handle_.Init("a", GetNoTunnelParams(), LOW, CompletionCallback(), - &pool_, BoundNetLog()); - EXPECT_EQ(OK, rv); - EXPECT_TRUE(handle_.is_initialized()); - ASSERT_TRUE(handle_.socket()); - HttpProxyClientSocket* tunnel_socket = - static_cast<HttpProxyClientSocket*>(handle_.socket()); - EXPECT_TRUE(tunnel_socket->IsConnected()); -} - -TEST_P(HttpProxyClientSocketPoolSpdy21Test, NeedAuth) { - MockWrite writes[] = { - MockWrite(ASYNC, 0, "CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"), - }; - MockRead reads[] = { - // No credentials. - MockRead(ASYNC, 1, "HTTP/1.1 407 Proxy Authentication Required\r\n"), - MockRead(ASYNC, 2, "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"), - MockRead(ASYNC, 3, "Content-Length: 10\r\n\r\n"), - MockRead(ASYNC, 4, "0123456789"), - }; - scoped_ptr<SpdyFrame> req(ConstructSpdyConnect(NULL, 0, 1)); - scoped_ptr<SpdyFrame> rst(ConstructSpdyRstStream(1, CANCEL)); - MockWrite spdy_writes[] = { - CreateMockWrite(*req, 0, ASYNC), - CreateMockWrite(*rst, 2, ASYNC), - }; - static const char* const kAuthChallenge[] = { - "status", "407 Proxy Authentication Required", - "version", "HTTP/1.1", - "proxy-authenticate", "Basic realm=\"MyRealm1\"", - }; - scoped_ptr<SpdyFrame> resp( - - ConstructSpdyControlFrame(NULL, - 0, - false, - 1, - LOWEST, - SYN_REPLY, - CONTROL_FLAG_NONE, - kAuthChallenge, - arraysize(kAuthChallenge))); - MockRead spdy_reads[] = { - CreateMockWrite(*resp, 1, ASYNC), - MockRead(ASYNC, 0, 3) - }; - - Initialize(reads, arraysize(reads), writes, arraysize(writes), - spdy_reads, arraysize(spdy_reads), spdy_writes, - arraysize(spdy_writes)); - - data_->StopAfter(4); - int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(), - &pool_, BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); - - data_->RunFor(GetParam() == SPDY ? 2 : 4); - rv = callback_.WaitForResult(); - EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, rv); - EXPECT_TRUE(handle_.is_initialized()); - ASSERT_TRUE(handle_.socket()); - ProxyClientSocket* tunnel_socket = - static_cast<ProxyClientSocket*>(handle_.socket()); - if (GetParam() == SPDY) { - EXPECT_TRUE(tunnel_socket->IsConnected()); - EXPECT_TRUE(tunnel_socket->IsUsingSpdy()); - } else { - EXPECT_FALSE(tunnel_socket->IsConnected()); - EXPECT_FALSE(tunnel_socket->IsUsingSpdy()); - EXPECT_FALSE(tunnel_socket->IsUsingSpdy()); - } -} - -TEST_P(HttpProxyClientSocketPoolSpdy21Test, HaveAuth) { - // It's pretty much impossible to make the SPDY case behave synchronously - // so we skip this test for SPDY - if (GetParam() == SPDY) - return; - MockWrite writes[] = { - MockWrite(SYNCHRONOUS, 0, - "CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - MockRead reads[] = { - MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"), - }; - - Initialize(reads, arraysize(reads), writes, arraysize(writes), NULL, 0, - NULL, 0); - AddAuthToCache(); - - int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(), - &pool_, BoundNetLog()); - EXPECT_EQ(OK, rv); - EXPECT_TRUE(handle_.is_initialized()); - ASSERT_TRUE(handle_.socket()); - HttpProxyClientSocket* tunnel_socket = - static_cast<HttpProxyClientSocket*>(handle_.socket()); - EXPECT_TRUE(tunnel_socket->IsConnected()); -} - -TEST_P(HttpProxyClientSocketPoolSpdy21Test, AsyncHaveAuth) { - MockWrite writes[] = { - MockWrite("CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - MockRead reads[] = { - MockRead(SYNCHRONOUS, "HTTP/1.1 200 Connection Established\r\n\r\n"), - }; - - scoped_ptr<SpdyFrame> req(ConstructSpdyConnect(kAuthHeaders, - kAuthHeadersSize, 1)); - MockWrite spdy_writes[] = { - CreateMockWrite(*req, 0, ASYNC) - }; - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead spdy_reads[] = { - CreateMockRead(*resp, 1, ASYNC), - MockRead(ASYNC, 0, 2) - }; - - Initialize(reads, arraysize(reads), writes, arraysize(writes), - spdy_reads, arraysize(spdy_reads), spdy_writes, - arraysize(spdy_writes)); - AddAuthToCache(); - - int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(), - &pool_, BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); - - data_->RunFor(2); - EXPECT_EQ(OK, callback_.WaitForResult()); - EXPECT_TRUE(handle_.is_initialized()); - ASSERT_TRUE(handle_.socket()); - HttpProxyClientSocket* tunnel_socket = - static_cast<HttpProxyClientSocket*>(handle_.socket()); - EXPECT_TRUE(tunnel_socket->IsConnected()); -} - -TEST_P(HttpProxyClientSocketPoolSpdy21Test, TCPError) { - if (GetParam() == SPDY) return; - data_ = new DeterministicSocketData(NULL, 0, NULL, 0); - data_->set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_CLOSED)); - - socket_factory().AddSocketDataProvider(data_.get()); - - int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(), - &pool_, BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); - - EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback_.WaitForResult()); - - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); -} - -TEST_P(HttpProxyClientSocketPoolSpdy21Test, SSLError) { - if (GetParam() == HTTP) return; - data_ = new DeterministicSocketData(NULL, 0, NULL, 0); - data_->set_connect_data(MockConnect(ASYNC, OK)); - socket_factory().AddSocketDataProvider(data_.get()); - - ssl_data_.reset(new SSLSocketDataProvider(ASYNC, - ERR_CERT_AUTHORITY_INVALID)); - if (GetParam() == SPDY) { - InitializeSpdySsl(); - } - socket_factory().AddSSLSocketDataProvider(ssl_data_.get()); - - int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(), - &pool_, BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); - - EXPECT_EQ(ERR_PROXY_CERTIFICATE_INVALID, callback_.WaitForResult()); - - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); -} - -TEST_P(HttpProxyClientSocketPoolSpdy21Test, SslClientAuth) { - if (GetParam() == HTTP) return; - data_ = new DeterministicSocketData(NULL, 0, NULL, 0); - data_->set_connect_data(MockConnect(ASYNC, OK)); - socket_factory().AddSocketDataProvider(data_.get()); - - ssl_data_.reset(new SSLSocketDataProvider(ASYNC, - ERR_SSL_CLIENT_AUTH_CERT_NEEDED)); - if (GetParam() == SPDY) { - InitializeSpdySsl(); - } - socket_factory().AddSSLSocketDataProvider(ssl_data_.get()); - - int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(), - &pool_, BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); - - EXPECT_EQ(ERR_SSL_CLIENT_AUTH_CERT_NEEDED, callback_.WaitForResult()); - - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); -} - -TEST_P(HttpProxyClientSocketPoolSpdy21Test, TunnelUnexpectedClose) { - MockWrite writes[] = { - MockWrite(ASYNC, 0, - "CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - MockRead reads[] = { - MockRead(ASYNC, 1, "HTTP/1.1 200 Conn"), - MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2), - }; - scoped_ptr<SpdyFrame> req(ConstructSpdyConnect(kAuthHeaders, - kAuthHeadersSize, 1)); - MockWrite spdy_writes[] = { - CreateMockWrite(*req, 0, ASYNC) - }; - MockRead spdy_reads[] = { - MockRead(ASYNC, ERR_CONNECTION_CLOSED, 1), - }; - - Initialize(reads, arraysize(reads), writes, arraysize(writes), - spdy_reads, arraysize(spdy_reads), spdy_writes, - arraysize(spdy_writes)); - AddAuthToCache(); - - int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(), - &pool_, BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); - - data_->RunFor(3); - EXPECT_EQ(ERR_CONNECTION_CLOSED, callback_.WaitForResult()); - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); -} - -TEST_P(HttpProxyClientSocketPoolSpdy21Test, TunnelSetupError) { - MockWrite writes[] = { - MockWrite(ASYNC, 0, - "CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n" - "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"), - }; - MockRead reads[] = { - MockRead(ASYNC, 1, "HTTP/1.1 304 Not Modified\r\n\r\n"), - }; - scoped_ptr<SpdyFrame> req(ConstructSpdyConnect(kAuthHeaders, - kAuthHeadersSize, 1)); - scoped_ptr<SpdyFrame> rst(ConstructSpdyRstStream(1, CANCEL)); - MockWrite spdy_writes[] = { - CreateMockWrite(*req, 0, ASYNC), - CreateMockWrite(*rst, 2, ASYNC), - }; - scoped_ptr<SpdyFrame> resp(ConstructSpdySynReplyError(1)); - MockRead spdy_reads[] = { - CreateMockRead(*resp, 1, ASYNC), - MockRead(ASYNC, 0, 3), - }; - - Initialize(reads, arraysize(reads), writes, arraysize(writes), - spdy_reads, arraysize(spdy_reads), spdy_writes, - arraysize(spdy_writes)); - AddAuthToCache(); - - int rv = handle_.Init("a", GetTunnelParams(), LOW, callback_.callback(), - &pool_, BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); - - data_->RunFor(2); - - rv = callback_.WaitForResult(); - if (GetParam() == HTTP) { - // HTTP Proxy CONNECT responses are not trustworthy - EXPECT_EQ(ERR_TUNNEL_CONNECTION_FAILED, rv); - EXPECT_FALSE(handle_.is_initialized()); - EXPECT_FALSE(handle_.socket()); - } else { - // HTTPS or SPDY Proxy CONNECT responses are trustworthy - EXPECT_EQ(ERR_HTTPS_PROXY_TUNNEL_RESPONSE, rv); - EXPECT_TRUE(handle_.is_initialized()); - EXPECT_TRUE(handle_.socket()); - } -} - -// It would be nice to also test the timeouts in HttpProxyClientSocketPool. - -} // namespace net diff --git a/net/http/http_server_properties.cc b/net/http/http_server_properties.cc index 5dfcebc..128bf66 100644 --- a/net/http/http_server_properties.cc +++ b/net/http/http_server_properties.cc @@ -13,7 +13,6 @@ const char kAlternateProtocolHeader[] = "Alternate-Protocol"; const char* const kAlternateProtocolStrings[] = { "npn-spdy/1", "npn-spdy/2", - "npn-spdy/2.1", "npn-spdy/3", }; @@ -21,7 +20,6 @@ static const char* AlternateProtocolToString(AlternateProtocol protocol) { switch (protocol) { case NPN_SPDY_1: case NPN_SPDY_2: - case NPN_SPDY_21: case NPN_SPDY_3: return kAlternateProtocolStrings[protocol]; case ALTERNATE_PROTOCOL_BROKEN: diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h index e61be5e..ea80eee 100644 --- a/net/http/http_server_properties.h +++ b/net/http/http_server_properties.h @@ -18,7 +18,6 @@ namespace net { enum AlternateProtocol { NPN_SPDY_1 = 0, NPN_SPDY_2, - NPN_SPDY_21, NPN_SPDY_3, NUM_ALTERNATE_PROTOCOLS, ALTERNATE_PROTOCOL_BROKEN, // The alternate protocol is known to be broken. diff --git a/net/http/http_server_properties_impl_unittest.cc b/net/http/http_server_properties_impl_unittest.cc index f3129e8..8dc9de3 100644 --- a/net/http/http_server_properties_impl_unittest.cc +++ b/net/http/http_server_properties_impl_unittest.cc @@ -209,7 +209,7 @@ TEST_F(AlternateProtocolServerPropertiesTest, Initialize) { AlternateProtocolMap alternate_protocol_map; PortAlternateProtocolPair port_alternate_protocol_pair; port_alternate_protocol_pair.port = 123; - port_alternate_protocol_pair.protocol = NPN_SPDY_21; + port_alternate_protocol_pair.protocol = NPN_SPDY_2; alternate_protocol_map[test_host_port_pair2] = port_alternate_protocol_pair; impl_.InitializeAlternateProtocolServers(&alternate_protocol_map); @@ -221,7 +221,7 @@ TEST_F(AlternateProtocolServerPropertiesTest, Initialize) { port_alternate_protocol_pair = impl_.GetAlternateProtocol(test_host_port_pair2); EXPECT_EQ(123, port_alternate_protocol_pair.port); - EXPECT_EQ(NPN_SPDY_21, port_alternate_protocol_pair.protocol); + EXPECT_EQ(NPN_SPDY_2, port_alternate_protocol_pair.protocol); } TEST_F(AlternateProtocolServerPropertiesTest, SetBroken) { @@ -246,7 +246,7 @@ TEST_F(AlternateProtocolServerPropertiesTest, Forced) { PortAlternateProtocolPair default_protocol; default_protocol.port = 1234; - default_protocol.protocol = NPN_SPDY_21; + default_protocol.protocol = NPN_SPDY_2; HttpServerPropertiesImpl::ForceAlternateProtocol(default_protocol); // Verify the forced protocol. diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc index aff2d09..2d87bc7 100644 --- a/net/http/http_stream_factory.cc +++ b/net/http/http_stream_factory.cc @@ -169,20 +169,10 @@ void HttpStreamFactory::EnableNpnHttpOnly() { } // static -void HttpStreamFactory::EnableFlowControl() { - std::vector<std::string> next_protos; - next_protos.push_back("http/1.1"); - next_protos.push_back("spdy/2"); - next_protos.push_back("spdy/2.1"); - SetNextProtos(next_protos); -} - -// static void HttpStreamFactory::EnableNpnSpdy3() { std::vector<std::string> next_protos; next_protos.push_back("http/1.1"); next_protos.push_back("spdy/2"); - next_protos.push_back("spdy/2.1"); next_protos.push_back("spdy/3"); SetNextProtos(next_protos); } @@ -204,8 +194,6 @@ void HttpStreamFactory::SetNextProtos(const std::vector<std::string>& value) { enabled_protocols_[NPN_SPDY_1] = true; } else if (value[i] == "spdy/2") { enabled_protocols_[NPN_SPDY_2] = true; - } else if (value[i] == "spdy/2.1") { - enabled_protocols_[NPN_SPDY_21] = true; } else if (value[i] == "spdy/3") { enabled_protocols_[NPN_SPDY_3] = true; } diff --git a/net/http/http_stream_factory.h b/net/http/http_stream_factory.h index f767844..58efdf3 100644 --- a/net/http/http_stream_factory.h +++ b/net/http/http_stream_factory.h @@ -230,21 +230,14 @@ class NET_EXPORT HttpStreamFactory { // Check if a HostPortPair is excluded from using spdy. static bool HasSpdyExclusion(const HostPortPair& endpoint); - // Sets http/1.1 and spdy/2 (the default spdy protocol) as the protocols - // supported. - static void EnableNpnSpdy(); - - // Sets http/1.1 as the protocols supported. + // Sets http/1.1 as the only protocol supported via NPN. static void EnableNpnHttpOnly(); - // Sets http/1.1, spdy/2 and spdy/2.1 as the protocols supported. - // If flow-control is enabled, received WINDOW_UPDATE and SETTINGS messages - // are processed and outstanding window size is actually obeyed when sending - // data frames, and WINDOW_UPDATE messages are generated when data is - // consumed. - static void EnableFlowControl(); + // Sets http/1.1 and spdy/2 (the default spdy protocol) as the protocols + // supported via NPN. + static void EnableNpnSpdy(); - // Sets http/1.1, spdy/2, spdy/2.1 and spdy/3 as the protocols supported. + // Sets http/1.1, spdy/2, and spdy/3 as the protocols supported via NPN. static void EnableNpnSpdy3(); // Sets the protocols supported by NPN (next protocol negotiation) during the diff --git a/net/net.gyp b/net/net.gyp index 15690c0..eb8ce22 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -1156,7 +1156,6 @@ 'http/http_content_disposition_unittest.cc', 'http/http_network_layer_unittest.cc', 'http/http_network_transaction_spdy3_unittest.cc', - 'http/http_network_transaction_spdy21_unittest.cc', 'http/http_network_transaction_spdy2_unittest.cc', 'http/http_pipelined_connection_impl_unittest.cc', 'http/http_pipelined_host_forced_unittest.cc', @@ -1166,7 +1165,6 @@ 'http/http_pipelined_host_test_util.h', 'http/http_pipelined_network_transaction_unittest.cc', 'http/http_proxy_client_socket_pool_spdy2_unittest.cc', - 'http/http_proxy_client_socket_pool_spdy21_unittest.cc', 'http/http_proxy_client_socket_pool_spdy3_unittest.cc', 'http/http_request_headers_unittest.cc', 'http/http_response_body_drainer_unittest.cc', @@ -1230,7 +1228,6 @@ 'spdy/spdy_http_stream_spdy3_unittest.cc', 'spdy/spdy_http_stream_spdy2_unittest.cc', 'spdy/spdy_network_transaction_spdy3_unittest.cc', - 'spdy/spdy_network_transaction_spdy21_unittest.cc', 'spdy/spdy_network_transaction_spdy2_unittest.cc', 'spdy/spdy_protocol_test.cc', 'spdy/spdy_proxy_client_socket_spdy3_unittest.cc', diff --git a/net/socket/next_proto.h b/net/socket/next_proto.h index 77b1b7d..df49e84 100644 --- a/net/socket/next_proto.h +++ b/net/socket/next_proto.h @@ -17,7 +17,6 @@ enum NextProto { kProtoHTTP11 = 1, kProtoSPDY1 = 2, kProtoSPDY2 = 3, - kProtoSPDY21 = 4, kProtoSPDY3 = 5, }; diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc index 9f49425..77002d0 100644 --- a/net/socket/ssl_client_socket.cc +++ b/net/socket/ssl_client_socket.cc @@ -24,8 +24,6 @@ NextProto SSLClientSocket::NextProtoFromString( return kProtoSPDY1; } else if (proto_string == "spdy/2") { return kProtoSPDY2; - } else if (proto_string == "spdy/2.1") { - return kProtoSPDY21; } else if (proto_string == "spdy/3") { return kProtoSPDY3; } else { @@ -42,8 +40,6 @@ const char* SSLClientSocket::NextProtoToString(NextProto next_proto) { return "spdy/1"; case kProtoSPDY2: return "spdy/2"; - case kProtoSPDY21: - return "spdy/2.1"; case kProtoSPDY3: return "spdy/3"; default: diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc index e3af1592..fb2973f 100644 --- a/net/socket/ssl_client_socket_pool.cc +++ b/net/socket/ssl_client_socket_pool.cc @@ -303,7 +303,6 @@ int SSLConnectJob::DoSSLConnectComplete(int result) { // TODO(mbelshe): verify it was a protocol we advertised? if (protocol_negotiated == kProtoSPDY1 || protocol_negotiated == kProtoSPDY2 || - protocol_negotiated == kProtoSPDY21 || protocol_negotiated == kProtoSPDY3) { ssl_socket_->set_was_spdy_negotiated(true); } diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc index 77c8bc8..168365d 100644 --- a/net/socket/ssl_client_socket_pool_unittest.cc +++ b/net/socket/ssl_client_socket_pool_unittest.cc @@ -360,7 +360,7 @@ TEST_F(SSLClientSocketPoolTest, DirectGotSPDY) { StaticSocketDataProvider data; socket_factory_.AddSocketDataProvider(&data); SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); + ssl.SetNextProto(kProtoSPDY2); socket_factory_.AddSSLSocketDataProvider(&ssl); CreatePool(true /* tcp pool */, false, false); @@ -385,14 +385,14 @@ TEST_F(SSLClientSocketPoolTest, DirectGotSPDY) { std::string server_protos; ssl_socket->GetNextProto(&proto, &server_protos); EXPECT_EQ(SSLClientSocket::NextProtoFromString(proto), - kProtoSPDY21); + kProtoSPDY2); } TEST_F(SSLClientSocketPoolTest, DirectGotBonusSPDY) { StaticSocketDataProvider data; socket_factory_.AddSocketDataProvider(&data); SSLSocketDataProvider ssl(ASYNC, OK); - ssl.SetNextProto(kProtoSPDY21); + ssl.SetNextProto(kProtoSPDY2); socket_factory_.AddSSLSocketDataProvider(&ssl); CreatePool(true /* tcp pool */, false, false); @@ -417,7 +417,7 @@ TEST_F(SSLClientSocketPoolTest, DirectGotBonusSPDY) { std::string server_protos; ssl_socket->GetNextProto(&proto, &server_protos); EXPECT_EQ(SSLClientSocket::NextProtoFromString(proto), - kProtoSPDY21); + kProtoSPDY2); } TEST_F(SSLClientSocketPoolTest, SOCKSFail) { @@ -692,7 +692,7 @@ TEST_F(SSLClientSocketPoolTest, IPPooling) { SSLSocketDataProvider ssl(ASYNC, OK); ssl.cert = X509Certificate::CreateFromBytes( reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der)); - ssl.SetNextProto(kProtoSPDY21); + ssl.SetNextProto(kProtoSPDY2); socket_factory_.AddSSLSocketDataProvider(&ssl); CreatePool(true /* tcp pool */, false, false); @@ -717,7 +717,7 @@ TEST_F(SSLClientSocketPoolTest, IPPooling) { std::string server_protos; ssl_socket->GetNextProto(&proto, &server_protos); EXPECT_EQ(SSLClientSocket::NextProtoFromString(proto), - kProtoSPDY21); + kProtoSPDY2); // TODO(rtenneti): MockClientSocket::GetPeerAddress returns 0 as the port // number. Fix it to return port 80 and then use GetPeerAddress to AddAlias. @@ -779,7 +779,7 @@ TEST_F(SSLClientSocketPoolTest, IPPoolingClientCert) { ssl.cert = X509Certificate::CreateFromBytes( reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der)); ssl.client_cert_sent = true; - ssl.SetNextProto(kProtoSPDY21); + ssl.SetNextProto(kProtoSPDY2); socket_factory_.AddSSLSocketDataProvider(&ssl); CreatePool(true /* tcp pool */, false, false); @@ -803,7 +803,7 @@ TEST_F(SSLClientSocketPoolTest, IPPoolingClientCert) { std::string server_protos; ssl_socket->GetNextProto(&proto, &server_protos); EXPECT_EQ(SSLClientSocket::NextProtoFromString(proto), - kProtoSPDY21); + kProtoSPDY2); // TODO(rtenneti): MockClientSocket::GetPeerAddress returns 0 as the port // number. Fix it to return port 80 and then use GetPeerAddress to AddAlias. diff --git a/net/spdy/spdy_http_stream.h b/net/spdy/spdy_http_stream.h index e3f5132..42c612d 100644 --- a/net/spdy/spdy_http_stream.h +++ b/net/spdy/spdy_http_stream.h @@ -88,8 +88,6 @@ class NET_EXPORT_PRIVATE SpdyHttpStream : public SpdyStream::Delegate, private: FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy2Test, FlowControlStallResume); - FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy21Test, - FlowControlStallResume); FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy3Test, FlowControlStallResume); diff --git a/net/spdy/spdy_network_transaction_spdy21_unittest.cc b/net/spdy/spdy_network_transaction_spdy21_unittest.cc deleted file mode 100644 index c81f30a..0000000 --- a/net/spdy/spdy_network_transaction_spdy21_unittest.cc +++ /dev/null @@ -1,5939 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/http/http_network_transaction.h" - -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "net/base/auth.h" -#include "net/base/net_log_unittest.h" -#include "net/http/http_network_session_peer.h" -#include "net/http/http_transaction_unittest.h" -#include "net/socket/client_socket_pool_base.h" -#include "net/spdy/buffered_spdy_framer.h" -#include "net/spdy/spdy_http_stream.h" -#include "net/spdy/spdy_http_utils.h" -#include "net/spdy/spdy_session.h" -#include "net/spdy/spdy_session_pool.h" -#include "net/spdy/spdy_test_util_spdy2.h" -#include "net/url_request/url_request_test_util.h" -#include "testing/platform_test.h" - -using namespace net::test_spdy2; - -//----------------------------------------------------------------------------- - -namespace net { - -enum SpdyNetworkTransactionSpdy21TestTypes { - SPDYNPN, - SPDYNOSSL, - SPDYSSL, -}; -class SpdyNetworkTransactionSpdy21Test - : public ::testing::TestWithParam<SpdyNetworkTransactionSpdy21TestTypes> { - protected: - - virtual void SetUp() { - SpdySession::set_default_protocol(kProtoSPDY21); - google_get_request_initialized_ = false; - google_post_request_initialized_ = false; - google_chunked_post_request_initialized_ = false; - } - - virtual void TearDown() { - // Empty the current queue. - MessageLoop::current()->RunAllPending(); - } - - struct TransactionHelperResult { - int rv; - std::string status_line; - std::string response_data; - HttpResponseInfo response_info; - }; - - // A helper class that handles all the initial npn/ssl setup. - class NormalSpdyTransactionHelper { - public: - NormalSpdyTransactionHelper(const HttpRequestInfo& request, - const BoundNetLog& log, - SpdyNetworkTransactionSpdy21TestTypes test_type) - : request_(request), - session_deps_(new SpdySessionDependencies()), - session_(SpdySessionDependencies::SpdyCreateSession( - session_deps_.get())), - log_(log), - test_type_(test_type), - deterministic_(false), - spdy_enabled_(true) { - switch (test_type_) { - case SPDYNOSSL: - case SPDYSSL: - port_ = 80; - break; - case SPDYNPN: - port_ = 443; - break; - default: - NOTREACHED(); - } - } - - ~NormalSpdyTransactionHelper() { - // Any test which doesn't close the socket by sending it an EOF will - // have a valid session left open, which leaks the entire session pool. - // This is just fine - in fact, some of our tests intentionally do this - // so that we can check consistency of the SpdySessionPool as the test - // finishes. If we had put an EOF on the socket, the SpdySession would - // have closed and we wouldn't be able to check the consistency. - - // Forcefully close existing sessions here. - session()->spdy_session_pool()->CloseAllSessions(); - } - - void SetDeterministic() { - session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic( - session_deps_.get()); - deterministic_ = true; - } - - void SetSpdyDisabled() { - spdy_enabled_ = false; - } - - void RunPreTestSetup() { - if (!session_deps_.get()) - session_deps_.reset(new SpdySessionDependencies()); - if (!session_.get()) - session_ = SpdySessionDependencies::SpdyCreateSession( - session_deps_.get()); - HttpStreamFactory::set_use_alternate_protocols(false); - HttpStreamFactory::set_force_spdy_over_ssl(false); - HttpStreamFactory::set_force_spdy_always(false); - - std::vector<std::string> next_protos; - next_protos.push_back("http/1.1"); - next_protos.push_back("spdy/2"); - next_protos.push_back("spdy/2.1"); - - switch (test_type_) { - case SPDYNPN: - session_->http_server_properties()->SetAlternateProtocol( - HostPortPair("www.google.com", 80), 443, - NPN_SPDY_21); - HttpStreamFactory::set_use_alternate_protocols(true); - HttpStreamFactory::SetNextProtos(next_protos); - break; - case SPDYNOSSL: - HttpStreamFactory::set_force_spdy_over_ssl(false); - HttpStreamFactory::set_force_spdy_always(true); - break; - case SPDYSSL: - HttpStreamFactory::set_force_spdy_over_ssl(true); - HttpStreamFactory::set_force_spdy_always(true); - break; - default: - NOTREACHED(); - } - - // We're now ready to use SSL-npn SPDY. - trans_.reset(new HttpNetworkTransaction(session_)); - } - - // Start the transaction, read some data, finish. - void RunDefaultTest() { - output_.rv = trans_->Start(&request_, callback.callback(), log_); - - // We expect an IO Pending or some sort of error. - EXPECT_LT(output_.rv, 0); - if (output_.rv != ERR_IO_PENDING) - return; - - output_.rv = callback.WaitForResult(); - if (output_.rv != OK) { - session_->spdy_session_pool()->CloseCurrentSessions(); - return; - } - - // Verify responses. - const HttpResponseInfo* response = trans_->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_EQ(spdy_enabled_, response->was_fetched_via_spdy); - if (test_type_ == SPDYNPN && spdy_enabled_) { - EXPECT_TRUE(response->was_npn_negotiated); - } else { - EXPECT_TRUE(!response->was_npn_negotiated); - } - // If SPDY is not enabled, a HTTP request should not be diverted - // over a SSL session. - if (!spdy_enabled_) { - EXPECT_EQ(request_.url.SchemeIs("https"), - response->was_npn_negotiated); - } - EXPECT_EQ("192.0.2.33", response->socket_address.host()); - EXPECT_EQ(0, response->socket_address.port()); - output_.status_line = response->headers->GetStatusLine(); - output_.response_info = *response; // Make a copy so we can verify. - output_.rv = ReadTransaction(trans_.get(), &output_.response_data); - } - - // Most tests will want to call this function. In particular, the MockReads - // should end with an empty read, and that read needs to be processed to - // ensure proper deletion of the spdy_session_pool. - void VerifyDataConsumed() { - for (DataVector::iterator it = data_vector_.begin(); - it != data_vector_.end(); ++it) { - EXPECT_TRUE((*it)->at_read_eof()) << "Read count: " - << (*it)->read_count() - << " Read index: " - << (*it)->read_index(); - EXPECT_TRUE((*it)->at_write_eof()) << "Write count: " - << (*it)->write_count() - << " Write index: " - << (*it)->write_index(); - } - } - - // Occasionally a test will expect to error out before certain reads are - // processed. In that case we want to explicitly ensure that the reads were - // not processed. - void VerifyDataNotConsumed() { - for (DataVector::iterator it = data_vector_.begin(); - it != data_vector_.end(); ++it) { - EXPECT_TRUE(!(*it)->at_read_eof()) << "Read count: " - << (*it)->read_count() - << " Read index: " - << (*it)->read_index(); - EXPECT_TRUE(!(*it)->at_write_eof()) << "Write count: " - << (*it)->write_count() - << " Write index: " - << (*it)->write_index(); - } - } - - void RunToCompletion(StaticSocketDataProvider* data) { - RunPreTestSetup(); - AddData(data); - RunDefaultTest(); - VerifyDataConsumed(); - } - - void AddData(StaticSocketDataProvider* data) { - DCHECK(!deterministic_); - data_vector_.push_back(data); - linked_ptr<SSLSocketDataProvider> ssl_( - new SSLSocketDataProvider(ASYNC, OK)); - if (test_type_ == SPDYNPN) { - ssl_->SetNextProto(kProtoSPDY21); - } - ssl_vector_.push_back(ssl_); - if (test_type_ == SPDYNPN || test_type_ == SPDYSSL) - session_deps_->socket_factory->AddSSLSocketDataProvider(ssl_.get()); - session_deps_->socket_factory->AddSocketDataProvider(data); - if (test_type_ == SPDYNPN) { - MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); - linked_ptr<StaticSocketDataProvider> - hanging_non_alternate_protocol_socket( - new StaticSocketDataProvider(NULL, 0, NULL, 0)); - hanging_non_alternate_protocol_socket->set_connect_data( - never_finishing_connect); - session_deps_->socket_factory->AddSocketDataProvider( - hanging_non_alternate_protocol_socket.get()); - alternate_vector_.push_back(hanging_non_alternate_protocol_socket); - } - } - - void AddDeterministicData(DeterministicSocketData* data) { - DCHECK(deterministic_); - data_vector_.push_back(data); - linked_ptr<SSLSocketDataProvider> ssl_( - new SSLSocketDataProvider(ASYNC, OK)); - if (test_type_ == SPDYNPN) { - ssl_->SetNextProto(kProtoSPDY21); - } - ssl_vector_.push_back(ssl_); - if (test_type_ == SPDYNPN || test_type_ == SPDYSSL) { - session_deps_->deterministic_socket_factory-> - AddSSLSocketDataProvider(ssl_.get()); - } - session_deps_->deterministic_socket_factory->AddSocketDataProvider(data); - if (test_type_ == SPDYNPN) { - MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); - scoped_refptr<DeterministicSocketData> - hanging_non_alternate_protocol_socket( - new DeterministicSocketData(NULL, 0, NULL, 0)); - hanging_non_alternate_protocol_socket->set_connect_data( - never_finishing_connect); - session_deps_->deterministic_socket_factory->AddSocketDataProvider( - hanging_non_alternate_protocol_socket); - alternate_deterministic_vector_.push_back( - hanging_non_alternate_protocol_socket); - } - } - - // This can only be called after RunPreTestSetup. It adds a Data Provider, - // but not a corresponding SSL data provider - void AddDataNoSSL(StaticSocketDataProvider* data) { - DCHECK(!deterministic_); - session_deps_->socket_factory->AddSocketDataProvider(data); - } - void AddDataNoSSL(DeterministicSocketData* data) { - DCHECK(deterministic_); - session_deps_->deterministic_socket_factory->AddSocketDataProvider(data); - } - - void SetSession(const scoped_refptr<HttpNetworkSession>& session) { - session_ = session; - } - HttpNetworkTransaction* trans() { return trans_.get(); } - void ResetTrans() { trans_.reset(); } - TransactionHelperResult& output() { return output_; } - const HttpRequestInfo& request() const { return request_; } - const scoped_refptr<HttpNetworkSession>& session() const { - return session_; - } - scoped_ptr<SpdySessionDependencies>& session_deps() { - return session_deps_; - } - int port() const { return port_; } - SpdyNetworkTransactionSpdy21TestTypes test_type() const { - return test_type_; - } - - private: - typedef std::vector<StaticSocketDataProvider*> DataVector; - typedef std::vector<linked_ptr<SSLSocketDataProvider> > SSLVector; - typedef std::vector<linked_ptr<StaticSocketDataProvider> > AlternateVector; - typedef std::vector<scoped_refptr<DeterministicSocketData> > - AlternateDeterministicVector; - HttpRequestInfo request_; - scoped_ptr<SpdySessionDependencies> session_deps_; - scoped_refptr<HttpNetworkSession> session_; - TransactionHelperResult output_; - scoped_ptr<StaticSocketDataProvider> first_transaction_; - SSLVector ssl_vector_; - TestCompletionCallback callback; - scoped_ptr<HttpNetworkTransaction> trans_; - scoped_ptr<HttpNetworkTransaction> trans_http_; - DataVector data_vector_; - AlternateVector alternate_vector_; - AlternateDeterministicVector alternate_deterministic_vector_; - const BoundNetLog& log_; - SpdyNetworkTransactionSpdy21TestTypes test_type_; - int port_; - bool deterministic_; - bool spdy_enabled_; - }; - - void ConnectStatusHelperWithExpectedStatus(const MockRead& status, - int expected_status); - - void ConnectStatusHelper(const MockRead& status); - - const HttpRequestInfo& CreateGetPushRequest() { - google_get_push_request_.method = "GET"; - google_get_push_request_.url = GURL("http://www.google.com/foo.dat"); - google_get_push_request_.load_flags = 0; - return google_get_push_request_; - } - - const HttpRequestInfo& CreateGetRequest() { - if (!google_get_request_initialized_) { - google_get_request_.method = "GET"; - google_get_request_.url = GURL(kDefaultURL); - google_get_request_.load_flags = 0; - google_get_request_initialized_ = true; - } - return google_get_request_; - } - - const HttpRequestInfo& CreateGetRequestWithUserAgent() { - if (!google_get_request_initialized_) { - google_get_request_.method = "GET"; - google_get_request_.url = GURL(kDefaultURL); - google_get_request_.load_flags = 0; - google_get_request_.extra_headers.SetHeader("User-Agent", "Chrome"); - google_get_request_initialized_ = true; - } - return google_get_request_; - } - - const HttpRequestInfo& CreatePostRequest() { - if (!google_post_request_initialized_) { - google_post_request_.method = "POST"; - google_post_request_.url = GURL(kDefaultURL); - google_post_request_.upload_data = new UploadData(); - google_post_request_.upload_data->AppendBytes(kUploadData, - kUploadDataSize); - google_post_request_initialized_ = true; - } - return google_post_request_; - } - - const HttpRequestInfo& CreateChunkedPostRequest() { - if (!google_chunked_post_request_initialized_) { - google_chunked_post_request_.method = "POST"; - google_chunked_post_request_.url = GURL(kDefaultURL); - google_chunked_post_request_.upload_data = new UploadData(); - google_chunked_post_request_.upload_data->set_is_chunked(true); - google_chunked_post_request_.upload_data->AppendChunk( - kUploadData, kUploadDataSize, false); - google_chunked_post_request_.upload_data->AppendChunk( - kUploadData, kUploadDataSize, true); - google_chunked_post_request_initialized_ = true; - } - return google_chunked_post_request_; - } - - // Read the result of a particular transaction, knowing that we've got - // multiple transactions in the read pipeline; so as we read, we may have - // to skip over data destined for other transactions while we consume - // the data for |trans|. - int ReadResult(HttpNetworkTransaction* trans, - StaticSocketDataProvider* data, - std::string* result) { - const int kSize = 3000; - - int bytes_read = 0; - scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(kSize)); - TestCompletionCallback callback; - while (true) { - int rv = trans->Read(buf, kSize, callback.callback()); - if (rv == ERR_IO_PENDING) { - // Multiple transactions may be in the data set. Keep pulling off - // reads until we complete our callback. - while (!callback.have_result()) { - data->CompleteRead(); - MessageLoop::current()->RunAllPending(); - } - rv = callback.WaitForResult(); - } else if (rv <= 0) { - break; - } - result->append(buf->data(), rv); - bytes_read += rv; - } - return bytes_read; - } - - void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) { - // This lengthy block is reaching into the pool to dig out the active - // session. Once we have the session, we verify that the streams are - // all closed and not leaked at this point. - const GURL& url = helper.request().url; - int port = helper.test_type() == SPDYNPN ? 443 : 80; - HostPortPair host_port_pair(url.host(), port); - HostPortProxyPair pair(host_port_pair, ProxyServer::Direct()); - BoundNetLog log; - const scoped_refptr<HttpNetworkSession>& session = helper.session(); - SpdySessionPool* pool(session->spdy_session_pool()); - EXPECT_TRUE(pool->HasSession(pair)); - scoped_refptr<SpdySession> spdy_session(pool->Get(pair, log)); - ASSERT_TRUE(spdy_session.get() != NULL); - EXPECT_EQ(0u, spdy_session->num_active_streams()); - EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams()); - } - - void RunServerPushTest(OrderedSocketData* data, - HttpResponseInfo* response, - HttpResponseInfo* push_response, - std::string& expected) { - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data); - - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - - // Request the pushed path. - scoped_ptr<HttpNetworkTransaction> trans2( - new HttpNetworkTransaction(helper.session())); - rv = trans2->Start( - &CreateGetPushRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - MessageLoop::current()->RunAllPending(); - - // The data for the pushed path may be coming in more than 1 packet. Compile - // the results into a single string. - - // Read the server push body. - std::string result2; - ReadResult(trans2.get(), data, &result2); - // Read the response body. - std::string result; - ReadResult(trans, data, &result); - - // Verify that we consumed all test data. - EXPECT_TRUE(data->at_read_eof()); - EXPECT_TRUE(data->at_write_eof()); - - // Verify that the received push data is same as the expected push data. - EXPECT_EQ(result2.compare(expected), 0) << "Received data: " - << result2 - << "||||| Expected data: " - << expected; - - // Verify the SYN_REPLY. - // Copy the response info, because trans goes away. - *response = *trans->GetResponseInfo(); - *push_response = *trans2->GetResponseInfo(); - - VerifyStreamsClosed(helper); - } - - static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper, - int result) { - helper->ResetTrans(); - } - - static void StartTransactionCallback( - const scoped_refptr<HttpNetworkSession>& session, - int result) { - scoped_ptr<HttpNetworkTransaction> trans( - new HttpNetworkTransaction(session)); - TestCompletionCallback callback; - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL("http://www.google.com/"); - request.load_flags = 0; - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - callback.WaitForResult(); - } - - private: - bool google_get_request_initialized_; - bool google_post_request_initialized_; - bool google_chunked_post_request_initialized_; - HttpRequestInfo google_get_request_; - HttpRequestInfo google_post_request_; - HttpRequestInfo google_chunked_post_request_; - HttpRequestInfo google_get_push_request_; - SpdyTestStateHelper spdy_state_; -}; - -//----------------------------------------------------------------------------- -// All tests are run with three different connection types: SPDY after NPN -// negotiation, SPDY without SSL, and SPDY with SSL. -INSTANTIATE_TEST_CASE_P(Spdy, - SpdyNetworkTransactionSpdy21Test, - ::testing::Values(SPDYNOSSL, SPDYSSL, SPDYNPN)); - - -// Verify HttpNetworkTransaction constructor. -TEST_P(SpdyNetworkTransactionSpdy21Test, Constructor) { - SpdySessionDependencies session_deps; - scoped_refptr<HttpNetworkSession> session( - SpdySessionDependencies::SpdyCreateSession(&session_deps)); - scoped_ptr<HttpTransaction> trans(new HttpNetworkTransaction(session)); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, Get) { - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, GetAtEachPriority) { - for (RequestPriority p = HIGHEST; p < NUM_PRIORITIES; - p = RequestPriority(p+1)) { - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, p)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - const int spdy_prio = reinterpret_cast<SpdySynStreamControlFrame*>( - req.get())->priority(); - // this repeats the RequestPriority-->SpdyPriority mapping from - // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make - // sure it's being done right. - switch(p) { - case HIGHEST: - EXPECT_EQ(0, spdy_prio); - break; - case MEDIUM: - EXPECT_EQ(1, spdy_prio); - break; - case LOW: - case LOWEST: - EXPECT_EQ(2, spdy_prio); - break; - case IDLE: - EXPECT_EQ(3, spdy_prio); - break; - default: - FAIL(); - } - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - HttpRequestInfo http_req = CreateGetRequest(); - http_req.priority = p; - - NormalSpdyTransactionHelper helper(http_req, BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); - } -} - -// Start three gets simultaniously; making sure that multiplexed -// streams work properly. - -// This can't use the TransactionHelper method, since it only -// handles a single transaction, and finishes them as soon -// as it launches them. - -// TODO(gavinp): create a working generalized TransactionHelper that -// can allow multiple streams in flight. - -TEST_P(SpdyNetworkTransactionSpdy21Test, ThreeGets) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); - scoped_ptr<SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); - - scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); - scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); - scoped_ptr<SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); - - scoped_ptr<SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 5, LOWEST)); - scoped_ptr<SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 5)); - scoped_ptr<SpdyFrame> body3(ConstructSpdyBodyFrame(5, false)); - scoped_ptr<SpdyFrame> fbody3(ConstructSpdyBodyFrame(5, true)); - - MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*req2), - CreateMockWrite(*req3), - }; - MockRead reads[] = { - CreateMockRead(*resp, 1), - CreateMockRead(*body), - CreateMockRead(*resp2, 4), - CreateMockRead(*body2), - CreateMockRead(*resp3, 7), - CreateMockRead(*body3), - - CreateMockRead(*fbody), - CreateMockRead(*fbody2), - CreateMockRead(*fbody3), - - MockRead(ASYNC, 0, 0), // EOF - }; - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - scoped_ptr<OrderedSocketData> data_placeholder( - new OrderedSocketData(NULL, 0, NULL, 0)); - - BoundNetLog log; - TransactionHelperResult out; - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - // We require placeholder data because three get requests are sent out, so - // there needs to be three sets of SSL connection data. - helper.AddData(data_placeholder.get()); - helper.AddData(data_placeholder.get()); - scoped_ptr<HttpNetworkTransaction> trans1( - new HttpNetworkTransaction(helper.session())); - scoped_ptr<HttpNetworkTransaction> trans2( - new HttpNetworkTransaction(helper.session())); - scoped_ptr<HttpNetworkTransaction> trans3( - new HttpNetworkTransaction(helper.session())); - - TestCompletionCallback callback1; - TestCompletionCallback callback2; - TestCompletionCallback callback3; - - HttpRequestInfo httpreq1 = CreateGetRequest(); - HttpRequestInfo httpreq2 = CreateGetRequest(); - HttpRequestInfo httpreq3 = CreateGetRequest(); - - out.rv = trans1->Start(&httpreq1, callback1.callback(), log); - ASSERT_EQ(ERR_IO_PENDING, out.rv); - out.rv = trans2->Start(&httpreq2, callback2.callback(), log); - ASSERT_EQ(ERR_IO_PENDING, out.rv); - out.rv = trans3->Start(&httpreq3, callback3.callback(), log); - ASSERT_EQ(ERR_IO_PENDING, out.rv); - - out.rv = callback1.WaitForResult(); - ASSERT_EQ(OK, out.rv); - out.rv = callback3.WaitForResult(); - ASSERT_EQ(OK, out.rv); - - const HttpResponseInfo* response1 = trans1->GetResponseInfo(); - EXPECT_TRUE(response1->headers != NULL); - EXPECT_TRUE(response1->was_fetched_via_spdy); - out.status_line = response1->headers->GetStatusLine(); - out.response_info = *response1; - - trans2->GetResponseInfo(); - - out.rv = ReadTransaction(trans1.get(), &out.response_data); - helper.VerifyDataConsumed(); - EXPECT_EQ(OK, out.rv); - - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, TwoGetsLateBinding) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); - scoped_ptr<SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); - - scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); - scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); - scoped_ptr<SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); - - MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*req2), - }; - MockRead reads[] = { - CreateMockRead(*resp, 1), - CreateMockRead(*body), - CreateMockRead(*resp2, 4), - CreateMockRead(*body2), - CreateMockRead(*fbody), - CreateMockRead(*fbody2), - MockRead(ASYNC, 0, 0), // EOF - }; - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - - MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); - - scoped_ptr<OrderedSocketData> data_placeholder( - new OrderedSocketData(NULL, 0, NULL, 0)); - data_placeholder->set_connect_data(never_finishing_connect); - - BoundNetLog log; - TransactionHelperResult out; - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - // We require placeholder data because two get requests are sent out, so - // there needs to be two sets of SSL connection data. - helper.AddData(data_placeholder.get()); - scoped_ptr<HttpNetworkTransaction> trans1( - new HttpNetworkTransaction(helper.session())); - scoped_ptr<HttpNetworkTransaction> trans2( - new HttpNetworkTransaction(helper.session())); - - TestCompletionCallback callback1; - TestCompletionCallback callback2; - - HttpRequestInfo httpreq1 = CreateGetRequest(); - HttpRequestInfo httpreq2 = CreateGetRequest(); - - out.rv = trans1->Start(&httpreq1, callback1.callback(), log); - ASSERT_EQ(ERR_IO_PENDING, out.rv); - out.rv = trans2->Start(&httpreq2, callback2.callback(), log); - ASSERT_EQ(ERR_IO_PENDING, out.rv); - - out.rv = callback1.WaitForResult(); - ASSERT_EQ(OK, out.rv); - out.rv = callback2.WaitForResult(); - ASSERT_EQ(OK, out.rv); - - const HttpResponseInfo* response1 = trans1->GetResponseInfo(); - EXPECT_TRUE(response1->headers != NULL); - EXPECT_TRUE(response1->was_fetched_via_spdy); - out.status_line = response1->headers->GetStatusLine(); - out.response_info = *response1; - out.rv = ReadTransaction(trans1.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - - const HttpResponseInfo* response2 = trans2->GetResponseInfo(); - EXPECT_TRUE(response2->headers != NULL); - EXPECT_TRUE(response2->was_fetched_via_spdy); - out.status_line = response2->headers->GetStatusLine(); - out.response_info = *response2; - out.rv = ReadTransaction(trans2.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - - helper.VerifyDataConsumed(); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, TwoGetsLateBindingFromPreconnect) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); - scoped_ptr<SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); - - scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); - scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); - scoped_ptr<SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); - - MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*req2), - }; - MockRead reads[] = { - CreateMockRead(*resp, 1), - CreateMockRead(*body), - CreateMockRead(*resp2, 4), - CreateMockRead(*body2), - CreateMockRead(*fbody), - CreateMockRead(*fbody2), - MockRead(ASYNC, 0, 0), // EOF - }; - scoped_ptr<OrderedSocketData> preconnect_data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - - MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING); - - scoped_ptr<OrderedSocketData> data_placeholder( - new OrderedSocketData(NULL, 0, NULL, 0)); - data_placeholder->set_connect_data(never_finishing_connect); - - BoundNetLog log; - TransactionHelperResult out; - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(preconnect_data.get()); - // We require placeholder data because 3 connections are attempted (first is - // the preconnect, 2nd and 3rd are the never finished connections. - helper.AddData(data_placeholder.get()); - helper.AddData(data_placeholder.get()); - - scoped_ptr<HttpNetworkTransaction> trans1( - new HttpNetworkTransaction(helper.session())); - scoped_ptr<HttpNetworkTransaction> trans2( - new HttpNetworkTransaction(helper.session())); - - TestCompletionCallback callback1; - TestCompletionCallback callback2; - - HttpRequestInfo httpreq = CreateGetRequest(); - - // Preconnect the first. - SSLConfig preconnect_ssl_config; - helper.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config); - HttpStreamFactory* http_stream_factory = - helper.session()->http_stream_factory(); - if (http_stream_factory->has_next_protos()) { - preconnect_ssl_config.next_protos = http_stream_factory->next_protos(); - } - - http_stream_factory->PreconnectStreams( - 1, httpreq, preconnect_ssl_config, preconnect_ssl_config); - - out.rv = trans1->Start(&httpreq, callback1.callback(), log); - ASSERT_EQ(ERR_IO_PENDING, out.rv); - out.rv = trans2->Start(&httpreq, callback2.callback(), log); - ASSERT_EQ(ERR_IO_PENDING, out.rv); - - out.rv = callback1.WaitForResult(); - ASSERT_EQ(OK, out.rv); - out.rv = callback2.WaitForResult(); - ASSERT_EQ(OK, out.rv); - - const HttpResponseInfo* response1 = trans1->GetResponseInfo(); - EXPECT_TRUE(response1->headers != NULL); - EXPECT_TRUE(response1->was_fetched_via_spdy); - out.status_line = response1->headers->GetStatusLine(); - out.response_info = *response1; - out.rv = ReadTransaction(trans1.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - - const HttpResponseInfo* response2 = trans2->GetResponseInfo(); - EXPECT_TRUE(response2->headers != NULL); - EXPECT_TRUE(response2->was_fetched_via_spdy); - out.status_line = response2->headers->GetStatusLine(); - out.response_info = *response2; - out.rv = ReadTransaction(trans2.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - - helper.VerifyDataConsumed(); -} - -// Similar to ThreeGets above, however this test adds a SETTINGS -// frame. The SETTINGS frame is read during the IO loop waiting on -// the first transaction completion, and sets a maximum concurrent -// stream limit of 1. This means that our IO loop exists after the -// second transaction completes, so we can assert on read_index(). -TEST_P(SpdyNetworkTransactionSpdy21Test, ThreeGetsWithMaxConcurrent) { - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); - scoped_ptr<SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); - - scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); - scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); - scoped_ptr<SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); - - scoped_ptr<SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 5, LOWEST)); - scoped_ptr<SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 5)); - scoped_ptr<SpdyFrame> body3(ConstructSpdyBodyFrame(5, false)); - scoped_ptr<SpdyFrame> fbody3(ConstructSpdyBodyFrame(5, true)); - - SpdySettings settings; - SettingsFlagsAndId id(SETTINGS_FLAG_NONE, SETTINGS_MAX_CONCURRENT_STREAMS); - const size_t max_concurrent_streams = 1; - - settings.push_back(SpdySetting(id, max_concurrent_streams)); - scoped_ptr<SpdyFrame> settings_frame(ConstructSpdySettings(settings)); - - MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*req2), - CreateMockWrite(*req3), - }; - - MockRead reads[] = { - CreateMockRead(*settings_frame, 1), - CreateMockRead(*resp), - CreateMockRead(*body), - CreateMockRead(*fbody), - CreateMockRead(*resp2, 7), - CreateMockRead(*body2), - CreateMockRead(*fbody2), - CreateMockRead(*resp3, 12), - CreateMockRead(*body3), - CreateMockRead(*fbody3), - - MockRead(ASYNC, 0, 0), // EOF - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - scoped_ptr<OrderedSocketData> data_placeholder( - new OrderedSocketData(NULL, 0, NULL, 0)); - - BoundNetLog log; - TransactionHelperResult out; - { - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - // We require placeholder data because three get requests are sent out, so - // there needs to be three sets of SSL connection data. - helper.AddData(data_placeholder.get()); - helper.AddData(data_placeholder.get()); - scoped_ptr<HttpNetworkTransaction> trans1( - new HttpNetworkTransaction(helper.session())); - scoped_ptr<HttpNetworkTransaction> trans2( - new HttpNetworkTransaction(helper.session())); - scoped_ptr<HttpNetworkTransaction> trans3( - new HttpNetworkTransaction(helper.session())); - - TestCompletionCallback callback1; - TestCompletionCallback callback2; - TestCompletionCallback callback3; - - HttpRequestInfo httpreq1 = CreateGetRequest(); - HttpRequestInfo httpreq2 = CreateGetRequest(); - HttpRequestInfo httpreq3 = CreateGetRequest(); - - out.rv = trans1->Start(&httpreq1, callback1.callback(), log); - ASSERT_EQ(out.rv, ERR_IO_PENDING); - // run transaction 1 through quickly to force a read of our SETTINGS - // frame - out.rv = callback1.WaitForResult(); - ASSERT_EQ(OK, out.rv); - - out.rv = trans2->Start(&httpreq2, callback2.callback(), log); - ASSERT_EQ(out.rv, ERR_IO_PENDING); - out.rv = trans3->Start(&httpreq3, callback3.callback(), log); - ASSERT_EQ(out.rv, ERR_IO_PENDING); - out.rv = callback2.WaitForResult(); - ASSERT_EQ(OK, out.rv); - EXPECT_EQ(7U, data->read_index()); // i.e. the third trans was queued - - out.rv = callback3.WaitForResult(); - ASSERT_EQ(OK, out.rv); - - const HttpResponseInfo* response1 = trans1->GetResponseInfo(); - ASSERT_TRUE(response1 != NULL); - EXPECT_TRUE(response1->headers != NULL); - EXPECT_TRUE(response1->was_fetched_via_spdy); - out.status_line = response1->headers->GetStatusLine(); - out.response_info = *response1; - out.rv = ReadTransaction(trans1.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - - const HttpResponseInfo* response2 = trans2->GetResponseInfo(); - out.status_line = response2->headers->GetStatusLine(); - out.response_info = *response2; - out.rv = ReadTransaction(trans2.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - - const HttpResponseInfo* response3 = trans3->GetResponseInfo(); - out.status_line = response3->headers->GetStatusLine(); - out.response_info = *response3; - out.rv = ReadTransaction(trans3.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - - helper.VerifyDataConsumed(); - } - EXPECT_EQ(OK, out.rv); -} - -// Similar to ThreeGetsWithMaxConcurrent above, however this test adds -// a fourth transaction. The third and fourth transactions have -// different data ("hello!" vs "hello!hello!") and because of the -// user specified priority, we expect to see them inverted in -// the response from the server. -TEST_P(SpdyNetworkTransactionSpdy21Test, FourGetsWithMaxConcurrentPriority) { - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); - scoped_ptr<SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); - - scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); - scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); - scoped_ptr<SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); - - scoped_ptr<SpdyFrame> req4( - ConstructSpdyGet(NULL, 0, false, 5, HIGHEST)); - scoped_ptr<SpdyFrame> resp4(ConstructSpdyGetSynReply(NULL, 0, 5)); - scoped_ptr<SpdyFrame> fbody4(ConstructSpdyBodyFrame(5, true)); - - scoped_ptr<SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 7, LOWEST)); - scoped_ptr<SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 7)); - scoped_ptr<SpdyFrame> body3(ConstructSpdyBodyFrame(7, false)); - scoped_ptr<SpdyFrame> fbody3(ConstructSpdyBodyFrame(7, true)); - - SpdySettings settings; - SettingsFlagsAndId id(SETTINGS_FLAG_NONE, SETTINGS_MAX_CONCURRENT_STREAMS); - const size_t max_concurrent_streams = 1; - - settings.push_back(SpdySetting(id, max_concurrent_streams)); - scoped_ptr<SpdyFrame> settings_frame(ConstructSpdySettings(settings)); - - MockWrite writes[] = { CreateMockWrite(*req), - CreateMockWrite(*req2), - CreateMockWrite(*req4), - CreateMockWrite(*req3), - }; - MockRead reads[] = { - CreateMockRead(*settings_frame, 1), - CreateMockRead(*resp), - CreateMockRead(*body), - CreateMockRead(*fbody), - CreateMockRead(*resp2, 7), - CreateMockRead(*body2), - CreateMockRead(*fbody2), - CreateMockRead(*resp4, 13), - CreateMockRead(*fbody4), - CreateMockRead(*resp3, 16), - CreateMockRead(*body3), - CreateMockRead(*fbody3), - - MockRead(ASYNC, 0, 0), // EOF - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - scoped_ptr<OrderedSocketData> data_placeholder( - new OrderedSocketData(NULL, 0, NULL, 0)); - - BoundNetLog log; - TransactionHelperResult out; - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - // We require placeholder data because four get requests are sent out, so - // there needs to be four sets of SSL connection data. - helper.AddData(data_placeholder.get()); - helper.AddData(data_placeholder.get()); - helper.AddData(data_placeholder.get()); - scoped_ptr<HttpNetworkTransaction> trans1( - new HttpNetworkTransaction(helper.session())); - scoped_ptr<HttpNetworkTransaction> trans2( - new HttpNetworkTransaction(helper.session())); - scoped_ptr<HttpNetworkTransaction> trans3( - new HttpNetworkTransaction(helper.session())); - scoped_ptr<HttpNetworkTransaction> trans4( - new HttpNetworkTransaction(helper.session())); - - TestCompletionCallback callback1; - TestCompletionCallback callback2; - TestCompletionCallback callback3; - TestCompletionCallback callback4; - - HttpRequestInfo httpreq1 = CreateGetRequest(); - HttpRequestInfo httpreq2 = CreateGetRequest(); - HttpRequestInfo httpreq3 = CreateGetRequest(); - HttpRequestInfo httpreq4 = CreateGetRequest(); - httpreq4.priority = HIGHEST; - - out.rv = trans1->Start(&httpreq1, callback1.callback(), log); - ASSERT_EQ(ERR_IO_PENDING, out.rv); - // Run transaction 1 through quickly to force a read of our SETTINGS frame. - out.rv = callback1.WaitForResult(); - ASSERT_EQ(OK, out.rv); - - out.rv = trans2->Start(&httpreq2, callback2.callback(), log); - ASSERT_EQ(ERR_IO_PENDING, out.rv); - out.rv = trans3->Start(&httpreq3, callback3.callback(), log); - ASSERT_EQ(ERR_IO_PENDING, out.rv); - out.rv = trans4->Start(&httpreq4, callback4.callback(), log); - ASSERT_EQ(ERR_IO_PENDING, out.rv); - - out.rv = callback2.WaitForResult(); - ASSERT_EQ(OK, out.rv); - EXPECT_EQ(data->read_index(), 7U); // i.e. the third & fourth trans queued - - out.rv = callback3.WaitForResult(); - ASSERT_EQ(OK, out.rv); - - const HttpResponseInfo* response1 = trans1->GetResponseInfo(); - EXPECT_TRUE(response1->headers != NULL); - EXPECT_TRUE(response1->was_fetched_via_spdy); - out.status_line = response1->headers->GetStatusLine(); - out.response_info = *response1; - out.rv = ReadTransaction(trans1.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - - const HttpResponseInfo* response2 = trans2->GetResponseInfo(); - out.status_line = response2->headers->GetStatusLine(); - out.response_info = *response2; - out.rv = ReadTransaction(trans2.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - - // notice: response3 gets two hellos, response4 gets one - // hello, so we know dequeuing priority was respected. - const HttpResponseInfo* response3 = trans3->GetResponseInfo(); - out.status_line = response3->headers->GetStatusLine(); - out.response_info = *response3; - out.rv = ReadTransaction(trans3.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - - out.rv = callback4.WaitForResult(); - EXPECT_EQ(OK, out.rv); - const HttpResponseInfo* response4 = trans4->GetResponseInfo(); - out.status_line = response4->headers->GetStatusLine(); - out.response_info = *response4; - out.rv = ReadTransaction(trans4.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); - helper.VerifyDataConsumed(); - EXPECT_EQ(OK, out.rv); -} - -// Similar to ThreeGetsMaxConcurrrent above, however, this test -// deletes a session in the middle of the transaction to insure -// that we properly remove pendingcreatestream objects from -// the spdy_session -TEST_P(SpdyNetworkTransactionSpdy21Test, ThreeGetsWithMaxConcurrentDelete) { - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); - scoped_ptr<SpdyFrame> fbody(ConstructSpdyBodyFrame(1, true)); - - scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); - scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(3, false)); - scoped_ptr<SpdyFrame> fbody2(ConstructSpdyBodyFrame(3, true)); - - SpdySettings settings; - SettingsFlagsAndId id(SETTINGS_FLAG_NONE, SETTINGS_MAX_CONCURRENT_STREAMS); - const size_t max_concurrent_streams = 1; - - settings.push_back(SpdySetting(id, max_concurrent_streams)); - scoped_ptr<SpdyFrame> settings_frame(ConstructSpdySettings(settings)); - - MockWrite writes[] = { CreateMockWrite(*req), - CreateMockWrite(*req2), - }; - MockRead reads[] = { - CreateMockRead(*settings_frame, 1), - CreateMockRead(*resp), - CreateMockRead(*body), - CreateMockRead(*fbody), - CreateMockRead(*resp2, 7), - CreateMockRead(*body2), - CreateMockRead(*fbody2), - MockRead(ASYNC, 0, 0), // EOF - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - scoped_ptr<OrderedSocketData> data_placeholder( - new OrderedSocketData(NULL, 0, NULL, 0)); - - BoundNetLog log; - TransactionHelperResult out; - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - // We require placeholder data because three get requests are sent out, so - // there needs to be three sets of SSL connection data. - helper.AddData(data_placeholder.get()); - helper.AddData(data_placeholder.get()); - scoped_ptr<HttpNetworkTransaction> trans1( - new HttpNetworkTransaction(helper.session())); - scoped_ptr<HttpNetworkTransaction> trans2( - new HttpNetworkTransaction(helper.session())); - scoped_ptr<HttpNetworkTransaction> trans3( - new HttpNetworkTransaction(helper.session())); - - TestCompletionCallback callback1; - TestCompletionCallback callback2; - TestCompletionCallback callback3; - - HttpRequestInfo httpreq1 = CreateGetRequest(); - HttpRequestInfo httpreq2 = CreateGetRequest(); - HttpRequestInfo httpreq3 = CreateGetRequest(); - - out.rv = trans1->Start(&httpreq1, callback1.callback(), log); - ASSERT_EQ(out.rv, ERR_IO_PENDING); - // Run transaction 1 through quickly to force a read of our SETTINGS frame. - out.rv = callback1.WaitForResult(); - ASSERT_EQ(OK, out.rv); - - out.rv = trans2->Start(&httpreq2, callback2.callback(), log); - ASSERT_EQ(out.rv, ERR_IO_PENDING); - out.rv = trans3->Start(&httpreq3, callback3.callback(), log); - delete trans3.release(); - ASSERT_EQ(out.rv, ERR_IO_PENDING); - out.rv = callback2.WaitForResult(); - ASSERT_EQ(OK, out.rv); - - EXPECT_EQ(8U, data->read_index()); - - const HttpResponseInfo* response1 = trans1->GetResponseInfo(); - ASSERT_TRUE(response1 != NULL); - EXPECT_TRUE(response1->headers != NULL); - EXPECT_TRUE(response1->was_fetched_via_spdy); - out.status_line = response1->headers->GetStatusLine(); - out.response_info = *response1; - out.rv = ReadTransaction(trans1.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - - const HttpResponseInfo* response2 = trans2->GetResponseInfo(); - ASSERT_TRUE(response2 != NULL); - out.status_line = response2->headers->GetStatusLine(); - out.response_info = *response2; - out.rv = ReadTransaction(trans2.get(), &out.response_data); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); - helper.VerifyDataConsumed(); - EXPECT_EQ(OK, out.rv); -} - -namespace { - -// The KillerCallback will delete the transaction on error as part of the -// callback. -class KillerCallback : public TestCompletionCallbackBase { - public: - explicit KillerCallback(HttpNetworkTransaction* transaction) - : transaction_(transaction), - ALLOW_THIS_IN_INITIALIZER_LIST(callback_( - base::Bind(&KillerCallback::OnComplete, base::Unretained(this)))) { - } - - virtual ~KillerCallback() {} - - const CompletionCallback& callback() const { return callback_; } - - private: - void OnComplete(int result) { - if (result < 0) - delete transaction_; - - SetResult(result); - } - - HttpNetworkTransaction* transaction_; - CompletionCallback callback_; -}; - -} // namespace - -// Similar to ThreeGetsMaxConcurrrentDelete above, however, this test -// closes the socket while we have a pending transaction waiting for -// a pending stream creation. http://crbug.com/52901 -TEST_P(SpdyNetworkTransactionSpdy21Test, - ThreeGetsWithMaxConcurrentSocketClose) { - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, false)); - scoped_ptr<SpdyFrame> fin_body(ConstructSpdyBodyFrame(1, true)); - - scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); - scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); - - SpdySettings settings; - SettingsFlagsAndId id(SETTINGS_FLAG_NONE, SETTINGS_MAX_CONCURRENT_STREAMS); - const size_t max_concurrent_streams = 1; - - settings.push_back(SpdySetting(id, max_concurrent_streams)); - scoped_ptr<SpdyFrame> settings_frame(ConstructSpdySettings(settings)); - - MockWrite writes[] = { CreateMockWrite(*req), - CreateMockWrite(*req2), - }; - MockRead reads[] = { - CreateMockRead(*settings_frame, 1), - CreateMockRead(*resp), - CreateMockRead(*body), - CreateMockRead(*fin_body), - CreateMockRead(*resp2, 7), - MockRead(ASYNC, ERR_CONNECTION_RESET, 0), // Abort! - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - scoped_ptr<OrderedSocketData> data_placeholder( - new OrderedSocketData(NULL, 0, NULL, 0)); - - BoundNetLog log; - TransactionHelperResult out; - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - // We require placeholder data because three get requests are sent out, so - // there needs to be three sets of SSL connection data. - helper.AddData(data_placeholder.get()); - helper.AddData(data_placeholder.get()); - HttpNetworkTransaction trans1(helper.session()); - HttpNetworkTransaction trans2(helper.session()); - HttpNetworkTransaction* trans3(new HttpNetworkTransaction(helper.session())); - - TestCompletionCallback callback1; - TestCompletionCallback callback2; - KillerCallback callback3(trans3); - - HttpRequestInfo httpreq1 = CreateGetRequest(); - HttpRequestInfo httpreq2 = CreateGetRequest(); - HttpRequestInfo httpreq3 = CreateGetRequest(); - - out.rv = trans1.Start(&httpreq1, callback1.callback(), log); - ASSERT_EQ(out.rv, ERR_IO_PENDING); - // Run transaction 1 through quickly to force a read of our SETTINGS frame. - out.rv = callback1.WaitForResult(); - ASSERT_EQ(OK, out.rv); - - out.rv = trans2.Start(&httpreq2, callback2.callback(), log); - ASSERT_EQ(out.rv, ERR_IO_PENDING); - out.rv = trans3->Start(&httpreq3, callback3.callback(), log); - ASSERT_EQ(out.rv, ERR_IO_PENDING); - out.rv = callback3.WaitForResult(); - ASSERT_EQ(ERR_ABORTED, out.rv); - - EXPECT_EQ(6U, data->read_index()); - - const HttpResponseInfo* response1 = trans1.GetResponseInfo(); - ASSERT_TRUE(response1 != NULL); - EXPECT_TRUE(response1->headers != NULL); - EXPECT_TRUE(response1->was_fetched_via_spdy); - out.status_line = response1->headers->GetStatusLine(); - out.response_info = *response1; - out.rv = ReadTransaction(&trans1, &out.response_data); - EXPECT_EQ(OK, out.rv); - - const HttpResponseInfo* response2 = trans2.GetResponseInfo(); - ASSERT_TRUE(response2 != NULL); - out.status_line = response2->headers->GetStatusLine(); - out.response_info = *response2; - out.rv = ReadTransaction(&trans2, &out.response_data); - EXPECT_EQ(ERR_CONNECTION_RESET, out.rv); - - helper.VerifyDataConsumed(); -} - -// Test that a simple PUT request works. -TEST_P(SpdyNetworkTransactionSpdy21Test, Put) { - // Setup the request - HttpRequestInfo request; - request.method = "PUT"; - request.url = GURL("http://www.google.com/"); - - const SpdyHeaderInfo kSynStartHeader = { - SYN_STREAM, // Kind = Syn - 1, // Stream ID - 0, // Associated stream ID - net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority - CONTROL_FLAG_FIN, // Control Flags - false, // Compressed - INVALID, // Status - NULL, // Data - 0, // Length - DATA_FLAG_NONE // Data Flags - }; - const char* const kPutHeaders[] = { - "method", "PUT", - "url", "/", - "host", "www.google.com", - "scheme", "http", - "version", "HTTP/1.1", - "content-length", "0" - }; - scoped_ptr<SpdyFrame> req(ConstructSpdyPacket(kSynStartHeader, NULL, 0, - kPutHeaders, arraysize(kPutHeaders) / 2)); - MockWrite writes[] = { - CreateMockWrite(*req) - }; - - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - const SpdyHeaderInfo kSynReplyHeader = { - SYN_REPLY, // Kind = SynReply - 1, // Stream ID - 0, // Associated stream ID - net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority - CONTROL_FLAG_NONE, // Control Flags - false, // Compressed - INVALID, // Status - NULL, // Data - 0, // Length - DATA_FLAG_NONE // Data Flags - }; - static const char* const kStandardGetHeaders[] = { - "status", "200", - "version", "HTTP/1.1" - "content-length", "1234" - }; - scoped_ptr<SpdyFrame> resp(ConstructSpdyPacket(kSynReplyHeader, - NULL, 0, kStandardGetHeaders, arraysize(kStandardGetHeaders) / 2)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(request, - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); -} - -// Test that a simple HEAD request works. -TEST_P(SpdyNetworkTransactionSpdy21Test, Head) { - // Setup the request - HttpRequestInfo request; - request.method = "HEAD"; - request.url = GURL("http://www.google.com/"); - - const SpdyHeaderInfo kSynStartHeader = { - SYN_STREAM, // Kind = Syn - 1, // Stream ID - 0, // Associated stream ID - net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority - CONTROL_FLAG_FIN, // Control Flags - false, // Compressed - INVALID, // Status - NULL, // Data - 0, // Length - DATA_FLAG_NONE // Data Flags - }; - const char* const kHeadHeaders[] = { - "method", "HEAD", - "url", "/", - "host", "www.google.com", - "scheme", "http", - "version", "HTTP/1.1", - "content-length", "0" - }; - scoped_ptr<SpdyFrame> req(ConstructSpdyPacket(kSynStartHeader, NULL, 0, - kHeadHeaders, arraysize(kHeadHeaders) / 2)); - MockWrite writes[] = { - CreateMockWrite(*req) - }; - - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - const SpdyHeaderInfo kSynReplyHeader = { - SYN_REPLY, // Kind = SynReply - 1, // Stream ID - 0, // Associated stream ID - net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority - CONTROL_FLAG_NONE, // Control Flags - false, // Compressed - INVALID, // Status - NULL, // Data - 0, // Length - DATA_FLAG_NONE // Data Flags - }; - static const char* const kStandardGetHeaders[] = { - "status", "200", - "version", "HTTP/1.1" - "content-length", "1234" - }; - scoped_ptr<SpdyFrame> resp(ConstructSpdyPacket(kSynReplyHeader, - NULL, 0, kStandardGetHeaders, arraysize(kStandardGetHeaders) / 2)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(request, - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); -} - -// Test that a simple POST works. -TEST_P(SpdyNetworkTransactionSpdy21Test, Post) { - scoped_ptr<SpdyFrame> req(ConstructSpdyPost(kUploadDataSize, NULL, 0)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*body), // POST upload frame - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(2, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreatePostRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); -} - -// Test that a chunked POST works. -TEST_P(SpdyNetworkTransactionSpdy21Test, ChunkedPost) { - UploadDataStream::set_merge_chunks(false); - scoped_ptr<SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0)); - scoped_ptr<SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, false)); - scoped_ptr<SpdyFrame> chunk2(ConstructSpdyBodyFrame(1, true)); - MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*chunk1), - CreateMockWrite(*chunk2), - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*chunk1), - CreateMockRead(*chunk2), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(2, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); -} - -// Test that a POST without any post data works. -TEST_P(SpdyNetworkTransactionSpdy21Test, NullPost) { - // Setup the request - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.google.com/"); - // Create an empty UploadData. - request.upload_data = NULL; - - // When request.upload_data is NULL for post, content-length is - // expected to be 0. - scoped_ptr<SpdyFrame> req(ConstructSpdyPost(0, NULL, 0)); - // Set the FIN bit since there will be no body. - req->set_flags(CONTROL_FLAG_FIN); - MockWrite writes[] = { - CreateMockWrite(*req), - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - - NormalSpdyTransactionHelper helper(request, - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); -} - -// Test that a simple POST works. -TEST_P(SpdyNetworkTransactionSpdy21Test, EmptyPost) { - // Setup the request - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.google.com/"); - // Create an empty UploadData. - request.upload_data = new UploadData(); - - // Http POST Content-Length is using UploadDataStream::size(). - // It is the same as request.upload_data->GetContentLengthSync(). - scoped_ptr<UploadDataStream> stream( - new UploadDataStream(request.upload_data)); - ASSERT_EQ(OK, stream->Init()); - ASSERT_EQ(request.upload_data->GetContentLengthSync(), - stream->size()); - - scoped_ptr<SpdyFrame> - req(ConstructSpdyPost( - request.upload_data->GetContentLengthSync(), NULL, 0)); - // Set the FIN bit since there will be no body. - req->set_flags(CONTROL_FLAG_FIN); - MockWrite writes[] = { - CreateMockWrite(*req), - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - - NormalSpdyTransactionHelper helper(request, - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); -} - -// While we're doing a post, the server sends back a SYN_REPLY. -TEST_P(SpdyNetworkTransactionSpdy21Test, PostWithEarlySynReply) { - static const char upload[] = { "hello!" }; - - // Setup the request - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.google.com/"); - request.upload_data = new UploadData(); - request.upload_data->AppendBytes(upload, sizeof(upload)); - - // Http POST Content-Length is using UploadDataStream::size(). - // It is the same as request.upload_data->GetContentLengthSync(). - scoped_ptr<UploadDataStream> stream( - new UploadDataStream(request.upload_data)); - ASSERT_EQ(OK, stream->Init()); - ASSERT_EQ(request.upload_data->GetContentLengthSync(), - stream->size()); - scoped_ptr<SpdyFrame> stream_reply(ConstructSpdyPostSynReply(NULL, 0)); - scoped_ptr<SpdyFrame> stream_body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*stream_reply, 2), - CreateMockRead(*stream_body, 3), - MockRead(SYNCHRONOUS, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(0, reads, arraysize(reads), NULL, 0)); - NormalSpdyTransactionHelper helper(request, - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - helper.RunDefaultTest(); - helper.VerifyDataConsumed(); - - TransactionHelperResult out = helper.output(); - EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv); -} - -// The client upon cancellation tries to send a RST_STREAM frame. The mock -// socket causes the TCP write to return zero. This test checks that the client -// tries to queue up the RST_STREAM frame again. -TEST_P(SpdyNetworkTransactionSpdy21Test, SocketWriteReturnsZero) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> rst( - ConstructSpdyRstStream(1, CANCEL)); - MockWrite writes[] = { - CreateMockWrite(*req.get(), 0, SYNCHRONOUS), - MockWrite(SYNCHRONOUS, 0, 0, 2), - CreateMockWrite(*rst.get(), 3, SYNCHRONOUS), - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*resp.get(), 1, ASYNC), - MockRead(ASYNC, 0, 0, 4) // EOF - }; - - scoped_refptr<DeterministicSocketData> data( - new DeterministicSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.SetDeterministic(); - helper.RunPreTestSetup(); - helper.AddDeterministicData(data.get()); - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - data->SetStop(2); - data->Run(); - helper.ResetTrans(); - data->SetStop(20); - data->Run(); - - helper.VerifyDataConsumed(); -} - -// Test that the transaction doesn't crash when we don't have a reply. -TEST_P(SpdyNetworkTransactionSpdy21Test, ResponseWithoutSynReply) { - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), NULL, 0)); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(ERR_SYN_REPLY_NOT_RECEIVED, out.rv); -} - -// Test that the transaction doesn't crash when we get two replies on the same -// stream ID. See http://crbug.com/45639. -TEST_P(SpdyNetworkTransactionSpdy21Test, ResponseWithTwoSynReplies) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->headers != NULL); - EXPECT_TRUE(response->was_fetched_via_spdy); - std::string response_data; - rv = ReadTransaction(trans, &response_data); - EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv); - - helper.VerifyDataConsumed(); -} - -// Test that sent data frames and received WINDOW_UPDATE frames change -// the send_window_size_ correctly. - -// WINDOW_UPDATE is different than most other frames in that it can arrive -// while the client is still sending the request body. In order to enforce -// this scenario, we feed a couple of dummy frames and give a delay of 0 to -// socket data provider, so that initial read that is done as soon as the -// stream is created, succeeds and schedules another read. This way reads -// and writes are interleaved; after doing a full frame write, SpdyStream -// will break out of DoLoop and will read and process a WINDOW_UPDATE. -// Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away -// since request has not been completely written, therefore we feed -// enough number of WINDOW_UPDATEs to finish the first read and cause a -// write, leading to a complete write of request body; after that we send -// a reply with a body, to cause a graceful shutdown. - -// TODO(agayev): develop a socket data provider where both, reads and -// writes are ordered so that writing tests like these are easy and rewrite -// all these tests using it. Right now we are working around the -// limitations as described above and it's not deterministic, tests may -// fail under specific circumstances. -TEST_P(SpdyNetworkTransactionSpdy21Test, WindowUpdateReceived) { - static int kFrameCount = 2; - scoped_ptr<std::string> content( - new std::string(kMaxSpdyFrameChunkSize, 'a')); - scoped_ptr<SpdyFrame> req(ConstructSpdyPost( - kMaxSpdyFrameChunkSize * kFrameCount, NULL, 0)); - scoped_ptr<SpdyFrame> body( - ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false)); - scoped_ptr<SpdyFrame> body_end( - ConstructSpdyBodyFrame(1, content->c_str(), content->size(), true)); - - MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*body), - CreateMockWrite(*body_end), - }; - - static const int32 kDeltaWindowSize = 0xff; - static const int kDeltaCount = 4; - scoped_ptr<SpdyFrame> window_update( - ConstructSpdyWindowUpdate(1, kDeltaWindowSize)); - scoped_ptr<SpdyFrame> window_update_dummy( - ConstructSpdyWindowUpdate(2, kDeltaWindowSize)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0)); - MockRead reads[] = { - CreateMockRead(*window_update_dummy), - CreateMockRead(*window_update_dummy), - CreateMockRead(*window_update_dummy), - CreateMockRead(*window_update), // Four updates, therefore window - CreateMockRead(*window_update), // size should increase by - CreateMockRead(*window_update), // kDeltaWindowSize * 4 - CreateMockRead(*window_update), - CreateMockRead(*resp), - CreateMockRead(*body_end), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(0, reads, arraysize(reads), - writes, arraysize(writes))); - - // Setup the request - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL(kDefaultURL); - request.upload_data = new UploadData(); - for (int i = 0; i < kFrameCount; ++i) - request.upload_data->AppendBytes(content->c_str(), content->size()); - - NormalSpdyTransactionHelper helper(request, BoundNetLog(), GetParam()); - helper.AddData(data.get()); - helper.RunPreTestSetup(); - - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); - - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); - ASSERT_TRUE(stream != NULL); - ASSERT_TRUE(stream->stream() != NULL); - EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize) + - kDeltaWindowSize * kDeltaCount - - kMaxSpdyFrameChunkSize * kFrameCount, - stream->stream()->send_window_size()); - helper.VerifyDataConsumed(); -} - -// Test that received data frames and sent WINDOW_UPDATE frames change -// the recv_window_size_ correctly. -TEST_P(SpdyNetworkTransactionSpdy21Test, WindowUpdateSent) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> window_update( - ConstructSpdyWindowUpdate(1, kUploadDataSize)); - - MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*window_update), - }; - - scoped_ptr<SpdyFrame> resp( - ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body_no_fin( - ConstructSpdyBodyFrame(1, false)); - scoped_ptr<SpdyFrame> body_fin( - ConstructSpdyBodyFrame(1, NULL, 0, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body_no_fin), - MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause - CreateMockRead(*body_fin), - MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.AddData(data.get()); - helper.RunPreTestSetup(); - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); - - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - SpdyHttpStream* stream = - static_cast<SpdyHttpStream*>(trans->stream_.get()); - ASSERT_TRUE(stream != NULL); - ASSERT_TRUE(stream->stream() != NULL); - - EXPECT_EQ( - static_cast<int>(kSpdyStreamInitialWindowSize) - kUploadDataSize, - stream->stream()->recv_window_size()); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - ASSERT_TRUE(response->headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_TRUE(response->was_fetched_via_spdy); - - // Force sending of WINDOW_UPDATE by setting initial_recv_window_size to a - // small value. - stream->stream()->set_initial_recv_window_size(kUploadDataSize / 2); - - // Issue a read which will cause a WINDOW_UPDATE to be sent and window - // size increased to default. - scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kUploadDataSize)); - rv = trans->Read(buf, kUploadDataSize, CompletionCallback()); - EXPECT_EQ(kUploadDataSize, rv); - std::string content(buf->data(), buf->data()+kUploadDataSize); - EXPECT_STREQ(kUploadData, content.c_str()); - - // Schedule the reading of empty data frame with FIN - data->CompleteRead(); - - // Force write of WINDOW_UPDATE which was scheduled during the above - // read. - MessageLoop::current()->RunAllPending(); - - // Read EOF. - data->CompleteRead(); - - helper.VerifyDataConsumed(); -} - -// Test that WINDOW_UPDATE frame causing overflow is handled correctly. We -// use the same trick as in the above test to enforce our scenario. -TEST_P(SpdyNetworkTransactionSpdy21Test, WindowUpdateOverflow) { - // number of full frames we hope to write (but will not, used to - // set content-length header correctly) - static int kFrameCount = 3; - - scoped_ptr<std::string> content( - new std::string(kMaxSpdyFrameChunkSize, 'a')); - scoped_ptr<SpdyFrame> req(ConstructSpdyPost( - kMaxSpdyFrameChunkSize * kFrameCount, NULL, 0)); - scoped_ptr<SpdyFrame> body( - ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false)); - scoped_ptr<SpdyFrame> rst( - ConstructSpdyRstStream(1, FLOW_CONTROL_ERROR)); - - // We're not going to write a data frame with FIN, we'll receive a bad - // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame. - MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*body), - CreateMockWrite(*rst), - }; - - static const int32 kDeltaWindowSize = 0x7fffffff; // cause an overflow - scoped_ptr<SpdyFrame> window_update( - ConstructSpdyWindowUpdate(1, kDeltaWindowSize)); - scoped_ptr<SpdyFrame> window_update2( - ConstructSpdyWindowUpdate(2, kDeltaWindowSize)); - scoped_ptr<SpdyFrame> reply(ConstructSpdyPostSynReply(NULL, 0)); - - MockRead reads[] = { - CreateMockRead(*window_update2), - CreateMockRead(*window_update2), - CreateMockRead(*window_update), - CreateMockRead(*window_update), - CreateMockRead(*window_update), - MockRead(ASYNC, ERR_IO_PENDING, 0), // Wait for the RST to be written. - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(0, reads, arraysize(reads), - writes, arraysize(writes))); - - // Setup the request - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.google.com/"); - request.upload_data = new UploadData(); - for (int i = 0; i < kFrameCount; ++i) - request.upload_data->AppendBytes(content->c_str(), content->size()); - - NormalSpdyTransactionHelper helper(request, - BoundNetLog(), GetParam()); - helper.AddData(data.get()); - helper.RunPreTestSetup(); - - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); - - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv); - - data->CompleteRead(); - - ASSERT_TRUE(helper.session() != NULL); - ASSERT_TRUE(helper.session()->spdy_session_pool() != NULL); - helper.session()->spdy_session_pool()->CloseAllSessions(); - helper.VerifyDataConsumed(); -} - -// Test that after hitting a send window size of 0, the write process -// stalls and upon receiving WINDOW_UPDATE frame write resumes. - -// This test constructs a POST request followed by enough data frames -// containing 'a' that would make the window size 0, followed by another -// data frame containing default content (which is "hello!") and this frame -// also contains a FIN flag. DelayedSocketData is used to enforce all -// writes go through before a read could happen. However, the last frame -// ("hello!") is not supposed to go through since by the time its turn -// arrives, window size is 0. At this point MessageLoop::Run() called via -// callback would block. Therefore we call MessageLoop::RunAllPending() -// which returns after performing all possible writes. We use DCHECKS to -// ensure that last data frame is still there and stream has stalled. -// After that, next read is artifically enforced, which causes a -// WINDOW_UPDATE to be read and I/O process resumes. -TEST_P(SpdyNetworkTransactionSpdy21Test, FlowControlStallResume) { - // Number of frames we need to send to zero out the window size: data - // frames plus SYN_STREAM plus the last data frame; also we need another - // data frame that we will send once the WINDOW_UPDATE is received, - // therefore +3. - size_t nwrites = - kSpdyStreamInitialWindowSize / kMaxSpdyFrameChunkSize + 3; - - // Calculate last frame's size; 0 size data frame is legal. - size_t last_frame_size = - kSpdyStreamInitialWindowSize % kMaxSpdyFrameChunkSize; - - // Construct content for a data frame of maximum size. - scoped_ptr<std::string> content( - new std::string(kMaxSpdyFrameChunkSize, 'a')); - - scoped_ptr<SpdyFrame> req(ConstructSpdyPost( - kSpdyStreamInitialWindowSize + kUploadDataSize, NULL, 0)); - - // Full frames. - scoped_ptr<SpdyFrame> body1( - ConstructSpdyBodyFrame(1, content->c_str(), content->size(), false)); - - // Last frame to zero out the window size. - scoped_ptr<SpdyFrame> body2( - ConstructSpdyBodyFrame(1, content->c_str(), last_frame_size, false)); - - // Data frame to be sent once WINDOW_UPDATE frame is received. - scoped_ptr<SpdyFrame> body3(ConstructSpdyBodyFrame(1, true)); - - // Fill in mock writes. - scoped_array<MockWrite> writes(new MockWrite[nwrites]); - size_t i = 0; - writes[i] = CreateMockWrite(*req); - for (i = 1; i < nwrites-2; i++) - writes[i] = CreateMockWrite(*body1); - writes[i++] = CreateMockWrite(*body2); - writes[i] = CreateMockWrite(*body3); - - // Construct read frame, give enough space to upload the rest of the - // data. - scoped_ptr<SpdyFrame> window_update( - ConstructSpdyWindowUpdate(1, kUploadDataSize)); - scoped_ptr<SpdyFrame> reply(ConstructSpdyPostSynReply(NULL, 0)); - MockRead reads[] = { - CreateMockRead(*window_update), - CreateMockRead(*window_update), - CreateMockRead(*reply), - CreateMockRead(*body2), - CreateMockRead(*body3), - MockRead(ASYNC, 0, 0) // EOF - }; - - // Force all writes to happen before any read, last write will not - // actually queue a frame, due to window size being 0. - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(nwrites, reads, arraysize(reads), - writes.get(), nwrites)); - - HttpRequestInfo request; - request.method = "POST"; - request.url = GURL("http://www.google.com/"); - request.upload_data = new UploadData(); - scoped_ptr<std::string> upload_data( - new std::string(kSpdyStreamInitialWindowSize, 'a')); - upload_data->append(kUploadData, kUploadDataSize); - request.upload_data->AppendBytes(upload_data->c_str(), upload_data->size()); - NormalSpdyTransactionHelper helper(request, - BoundNetLog(), GetParam()); - helper.AddData(data.get()); - helper.RunPreTestSetup(); - - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - MessageLoop::current()->RunAllPending(); // Write as much as we can. - - SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); - ASSERT_TRUE(stream != NULL); - ASSERT_TRUE(stream->stream() != NULL); - EXPECT_EQ(0, stream->stream()->send_window_size()); - // All the body data should have been read. - // TODO(satorux): This is because of the weirdness in reading the request - // body in OnSendBodyComplete(). See crbug.com/113107. - EXPECT_TRUE(stream->request_body_stream_->IsEOF()); - // But the body is not yet fully sent ("hello!" is not yet sent). - EXPECT_FALSE(stream->stream()->body_sent()); - - data->ForceNextRead(); // Read in WINDOW_UPDATE frame. - rv = callback.WaitForResult(); - helper.VerifyDataConsumed(); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ResetReplyWithTransferEncoding) { - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> rst(ConstructSpdyRstStream(1, PROTOCOL_ERROR)); - MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*rst), - }; - - const char* const headers[] = { - "transfer-encoding", "chuncked" - }; - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(headers, 1, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); - - helper.session()->spdy_session_pool()->CloseAllSessions(); - helper.VerifyDataConsumed(); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ResetPushWithTransferEncoding) { - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> rst(ConstructSpdyRstStream(2, PROTOCOL_ERROR)); - MockWrite writes[] = { - CreateMockWrite(*req), - CreateMockWrite(*rst), - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - const char* const headers[] = {"url", "http://www.google.com/1", - "transfer-encoding", "chunked"}; - scoped_ptr<SpdyFrame> push(ConstructSpdyPush(headers, arraysize(headers) / 2, - 2, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*push), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); - - helper.session()->spdy_session_pool()->CloseAllSessions(); - helper.VerifyDataConsumed(); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, CancelledTransaction) { - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { - CreateMockWrite(*req), - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*resp), - // This following read isn't used by the test, except during the - // RunAllPending() call at the end since the SpdySession survives the - // HttpNetworkTransaction and still tries to continue Read()'ing. Any - // MockRead will do here. - MockRead(ASYNC, 0, 0) // EOF - }; - - StaticSocketDataProvider data(reads, arraysize(reads), - writes, arraysize(writes)); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(&data); - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - helper.ResetTrans(); // Cancel the transaction. - - // Flush the MessageLoop while the SpdySessionDependencies (in particular, the - // MockClientSocketFactory) are still alive. - MessageLoop::current()->RunAllPending(); - helper.VerifyDataNotConsumed(); -} - -// Verify that the client sends a Rst Frame upon cancelling the stream. -TEST_P(SpdyNetworkTransactionSpdy21Test, CancelledTransactionSendRst) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> rst( - ConstructSpdyRstStream(1, CANCEL)); - MockWrite writes[] = { - CreateMockWrite(*req, 0, SYNCHRONOUS), - CreateMockWrite(*rst, 2, SYNCHRONOUS), - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*resp, 1, ASYNC), - MockRead(ASYNC, 0, 0, 3) // EOF - }; - - scoped_refptr<DeterministicSocketData> data( - new DeterministicSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), - GetParam()); - helper.SetDeterministic(); - helper.RunPreTestSetup(); - helper.AddDeterministicData(data.get()); - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - data->SetStop(2); - data->Run(); - helper.ResetTrans(); - data->SetStop(20); - data->Run(); - - helper.VerifyDataConsumed(); -} - -// Verify that the client can correctly deal with the user callback attempting -// to start another transaction on a session that is closing down. See -// http://crbug.com/47455 -TEST_P(SpdyNetworkTransactionSpdy21Test, StartTransactionOnReadCallback) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - MockWrite writes2[] = { CreateMockWrite(*req) }; - - // The indicated length of this packet is longer than its actual length. When - // the session receives an empty packet after this one, it shuts down the - // session, and calls the read callback with the incomplete data. - const uint8 kGetBodyFrame2[] = { - 0x00, 0x00, 0x00, 0x01, - 0x01, 0x00, 0x00, 0x07, - 'h', 'e', 'l', 'l', 'o', '!', - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*resp, 2), - MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause - MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2), - arraysize(kGetBodyFrame2), 4), - MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause - MockRead(ASYNC, 0, 0, 6), // EOF - }; - MockRead reads2[] = { - CreateMockRead(*resp, 2), - MockRead(ASYNC, 0, 0, 3), // EOF - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - scoped_ptr<DelayedSocketData> data2( - new DelayedSocketData(1, reads2, arraysize(reads2), - writes2, arraysize(writes2))); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - helper.AddData(data2.get()); - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - - const int kSize = 3000; - scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); - rv = trans->Read( - buf, kSize, - base::Bind(&SpdyNetworkTransactionSpdy21Test::StartTransactionCallback, - helper.session())); - // This forces an err_IO_pending, which sets the callback. - data->CompleteRead(); - // This finishes the read. - data->CompleteRead(); - helper.VerifyDataConsumed(); -} - -// Verify that the client can correctly deal with the user callback deleting the -// transaction. Failures will usually be valgrind errors. See -// http://crbug.com/46925 -TEST_P(SpdyNetworkTransactionSpdy21Test, DeleteSessionOnReadCallback) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp.get(), 2), - MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause - CreateMockRead(*body.get(), 4), - MockRead(ASYNC, 0, 0, 5), // EOF - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - - // Setup a user callback which will delete the session, and clear out the - // memory holding the stream object. Note that the callback deletes trans. - const int kSize = 3000; - scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); - rv = trans->Read( - buf, kSize, - base::Bind(&SpdyNetworkTransactionSpdy21Test::DeleteSessionCallback, - base::Unretained(&helper))); - ASSERT_EQ(ERR_IO_PENDING, rv); - data->CompleteRead(); - - // Finish running rest of tasks. - MessageLoop::current()->RunAllPending(); - helper.VerifyDataConsumed(); -} - -// Send a spdy request to www.google.com that gets redirected to www.foo.com. -TEST_P(SpdyNetworkTransactionSpdy21Test, RedirectGetRequest) { - // These are headers which the net::URLRequest tacks on. - const char* const kExtraHeaders[] = { - "accept-encoding", - "gzip,deflate", - }; - const SpdyHeaderInfo kSynStartHeader = MakeSpdyHeader(SYN_STREAM); - const char* const kStandardGetHeaders[] = { - "host", - "www.google.com", - "method", - "GET", - "scheme", - "http", - "url", - "/", - "user-agent", - "", - "version", - "HTTP/1.1" - }; - const char* const kStandardGetHeaders2[] = { - "host", - "www.foo.com", - "method", - "GET", - "scheme", - "http", - "url", - "/index.php", - "user-agent", - "", - "version", - "HTTP/1.1" - }; - - // Setup writes/reads to www.google.com - scoped_ptr<SpdyFrame> req(ConstructSpdyPacket( - kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders) / 2, - kStandardGetHeaders, arraysize(kStandardGetHeaders) / 2)); - scoped_ptr<SpdyFrame> req2(ConstructSpdyPacket( - kSynStartHeader, kExtraHeaders, arraysize(kExtraHeaders) / 2, - kStandardGetHeaders2, arraysize(kStandardGetHeaders2) / 2)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReplyRedirect(1)); - MockWrite writes[] = { - CreateMockWrite(*req, 1), - }; - MockRead reads[] = { - CreateMockRead(*resp, 2), - MockRead(ASYNC, 0, 0, 3) // EOF - }; - - // Setup writes/reads to www.foo.com - scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(1, true)); - MockWrite writes2[] = { - CreateMockWrite(*req2, 1), - }; - MockRead reads2[] = { - CreateMockRead(*resp2, 2), - CreateMockRead(*body2, 3), - MockRead(ASYNC, 0, 0, 4) // EOF - }; - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - scoped_ptr<OrderedSocketData> data2( - new OrderedSocketData(reads2, arraysize(reads2), - writes2, arraysize(writes2))); - - // TODO(erikchen): Make test support SPDYSSL, SPDYNPN - HttpStreamFactory::set_force_spdy_over_ssl(false); - HttpStreamFactory::set_force_spdy_always(true); - TestDelegate d; - { - net::URLRequest r(GURL("http://www.google.com/"), &d); - SpdyURLRequestContext* spdy_url_request_context = - new SpdyURLRequestContext(); - r.set_context(spdy_url_request_context); - spdy_url_request_context->socket_factory(). - AddSocketDataProvider(data.get()); - spdy_url_request_context->socket_factory(). - AddSocketDataProvider(data2.get()); - - d.set_quit_on_redirect(true); - r.Start(); - MessageLoop::current()->Run(); - - EXPECT_EQ(1, d.received_redirect_count()); - - r.FollowDeferredRedirect(); - MessageLoop::current()->Run(); - EXPECT_EQ(1, d.response_started_count()); - EXPECT_FALSE(d.received_data_before_response()); - EXPECT_EQ(net::URLRequestStatus::SUCCESS, r.status().status()); - std::string contents("hello!"); - EXPECT_EQ(contents, d.data_received()); - } - EXPECT_TRUE(data->at_read_eof()); - EXPECT_TRUE(data->at_write_eof()); - EXPECT_TRUE(data2->at_read_eof()); - EXPECT_TRUE(data2->at_write_eof()); -} - -// Detect response with upper case headers and reset the stream. -TEST_P(SpdyNetworkTransactionSpdy21Test, UpperCaseHeaders) { - scoped_ptr<SpdyFrame> - syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - rst(ConstructSpdyRstStream(1, PROTOCOL_ERROR)); - MockWrite writes[] = { - CreateMockWrite(*syn, 0), - CreateMockWrite(*rst, 2), - }; - - const char* const kExtraHeaders[] = {"X-UpperCase", "yes"}; - scoped_ptr<SpdyFrame> - reply(ConstructSpdyGetSynReply(kExtraHeaders, 1, 1)); - MockRead reads[] = { - CreateMockRead(*reply, 1), - MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause - }; - - HttpResponseInfo response; - HttpResponseInfo response2; - scoped_ptr<OrderedSocketData> data(new OrderedSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); -} - -// Detect response with upper case headers in a HEADERS frame and reset the -// stream. -TEST_P(SpdyNetworkTransactionSpdy21Test, UpperCaseHeadersInHeadersFrame) { - scoped_ptr<SpdyFrame> - syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - rst(ConstructSpdyRstStream(1, PROTOCOL_ERROR)); - MockWrite writes[] = { - CreateMockWrite(*syn, 0), - CreateMockWrite(*rst, 2), - }; - - static const char* const kInitialHeaders[] = { - "status", "200 OK", - "version", "HTTP/1.1" - }; - static const char* const kLateHeaders[] = { - "X-UpperCase", "yes", - }; - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyControlFrame(kInitialHeaders, - arraysize(kInitialHeaders) / 2, - false, - 1, - LOWEST, - SYN_REPLY, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - scoped_ptr<SpdyFrame> - stream1_headers(ConstructSpdyControlFrame(kLateHeaders, - arraysize(kLateHeaders) / 2, - false, - 1, - LOWEST, - HEADERS, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - scoped_ptr<SpdyFrame> stream1_body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*stream1_reply), - CreateMockRead(*stream1_headers), - CreateMockRead(*stream1_body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); -} - -// Detect push stream with upper case headers and reset the stream. -TEST_P(SpdyNetworkTransactionSpdy21Test, UpperCaseHeadersOnPush) { - scoped_ptr<SpdyFrame> - syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - rst(ConstructSpdyRstStream(2, PROTOCOL_ERROR)); - MockWrite writes[] = { - CreateMockWrite(*syn, 0), - CreateMockWrite(*rst, 2), - }; - - scoped_ptr<SpdyFrame> - reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - const char* const extra_headers[] = {"X-UpperCase", "yes"}; - scoped_ptr<SpdyFrame> - push(ConstructSpdyPush(extra_headers, 1, 2, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*reply, 1), - CreateMockRead(*push, 1), - CreateMockRead(*body, 1), - MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause - }; - - HttpResponseInfo response; - HttpResponseInfo response2; - scoped_ptr<OrderedSocketData> data(new OrderedSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); -} - -// Send a spdy request to www.google.com. Get a pushed stream that redirects to -// www.foo.com. -TEST_P(SpdyNetworkTransactionSpdy21Test, RedirectServerPush) { - // These are headers which the net::URLRequest tacks on. - const char* const kExtraHeaders[] = { - "accept-encoding", - "gzip,deflate", - }; - const SpdyHeaderInfo kSynStartHeader = MakeSpdyHeader(SYN_STREAM); - const char* const kStandardGetHeaders[] = { - "host", - "www.google.com", - "method", - "GET", - "scheme", - "http", - "url", - "/", - "user-agent", - "", - "version", - "HTTP/1.1" - }; - - // Setup writes/reads to www.google.com - scoped_ptr<SpdyFrame> req( - ConstructSpdyPacket(kSynStartHeader, - kExtraHeaders, - arraysize(kExtraHeaders) / 2, - kStandardGetHeaders, - arraysize(kStandardGetHeaders) / 2)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> rep( - ConstructSpdyPush(NULL, - 0, - 2, - 1, - "http://www.google.com/foo.dat", - "301 Moved Permanently", - "http://www.foo.com/index.php")); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> rst(ConstructSpdyRstStream(2, CANCEL)); - MockWrite writes[] = { - CreateMockWrite(*req, 1), - CreateMockWrite(*rst, 6), - }; - MockRead reads[] = { - CreateMockRead(*resp, 2), - CreateMockRead(*rep, 3), - CreateMockRead(*body, 4), - MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause - MockRead(ASYNC, 0, 0, 7) // EOF - }; - - // Setup writes/reads to www.foo.com - const char* const kStandardGetHeaders2[] = { - "host", - "www.foo.com", - "method", - "GET", - "scheme", - "http", - "url", - "/index.php", - "user-agent", - "", - "version", - "HTTP/1.1" - }; - scoped_ptr<SpdyFrame> req2( - ConstructSpdyPacket(kSynStartHeader, - kExtraHeaders, - arraysize(kExtraHeaders) / 2, - kStandardGetHeaders2, - arraysize(kStandardGetHeaders2) / 2)); - scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(1, true)); - MockWrite writes2[] = { - CreateMockWrite(*req2, 1), - }; - MockRead reads2[] = { - CreateMockRead(*resp2, 2), - CreateMockRead(*body2, 3), - MockRead(ASYNC, 0, 0, 5) // EOF - }; - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - scoped_ptr<OrderedSocketData> data2( - new OrderedSocketData(reads2, arraysize(reads2), - writes2, arraysize(writes2))); - - // TODO(erikchen): Make test support SPDYSSL, SPDYNPN - HttpStreamFactory::set_force_spdy_over_ssl(false); - HttpStreamFactory::set_force_spdy_always(true); - TestDelegate d; - TestDelegate d2; - scoped_refptr<SpdyURLRequestContext> spdy_url_request_context( - new SpdyURLRequestContext()); - { - net::URLRequest r(GURL("http://www.google.com/"), &d); - r.set_context(spdy_url_request_context); - spdy_url_request_context->socket_factory(). - AddSocketDataProvider(data.get()); - - r.Start(); - MessageLoop::current()->Run(); - - EXPECT_EQ(0, d.received_redirect_count()); - std::string contents("hello!"); - EXPECT_EQ(contents, d.data_received()); - - net::URLRequest r2(GURL("http://www.google.com/foo.dat"), &d2); - r2.set_context(spdy_url_request_context); - spdy_url_request_context->socket_factory(). - AddSocketDataProvider(data2.get()); - - d2.set_quit_on_redirect(true); - r2.Start(); - MessageLoop::current()->Run(); - EXPECT_EQ(1, d2.received_redirect_count()); - - r2.FollowDeferredRedirect(); - MessageLoop::current()->Run(); - EXPECT_EQ(1, d2.response_started_count()); - EXPECT_FALSE(d2.received_data_before_response()); - EXPECT_EQ(net::URLRequestStatus::SUCCESS, r2.status().status()); - std::string contents2("hello!"); - EXPECT_EQ(contents2, d2.data_received()); - } - data->CompleteRead(); - data2->CompleteRead(); - EXPECT_TRUE(data->at_read_eof()); - EXPECT_TRUE(data->at_write_eof()); - EXPECT_TRUE(data2->at_read_eof()); - EXPECT_TRUE(data2->at_write_eof()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushSingleDataFrame) { - static const unsigned char kPushBodyFrame[] = { - 0x00, 0x00, 0x00, 0x02, // header, ID - 0x01, 0x00, 0x00, 0x06, // FIN, length - 'p', 'u', 's', 'h', 'e', 'd' // "pushed" - }; - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 1, - "http://www.google.com/foo.dat")); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream1_body, 4, SYNCHRONOUS), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), - arraysize(kPushBodyFrame), 5), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause - }; - - HttpResponseInfo response; - HttpResponseInfo response2; - std::string expected_push_result("pushed"); - scoped_ptr<OrderedSocketData> data(new OrderedSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - RunServerPushTest(data.get(), - &response, - &response2, - expected_push_result); - - // Verify the SYN_REPLY. - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); - - // Verify the pushed stream. - EXPECT_TRUE(response2.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushBeforeSynReply) { - static const unsigned char kPushBodyFrame[] = { - 0x00, 0x00, 0x00, 0x02, // header, ID - 0x01, 0x00, 0x00, 0x06, // FIN, length - 'p', 'u', 's', 'h', 'e', 'd' // "pushed" - }; - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 1, - "http://www.google.com/foo.dat")); - MockRead reads[] = { - CreateMockRead(*stream2_syn, 2), - CreateMockRead(*stream1_reply, 3), - CreateMockRead(*stream1_body, 4, SYNCHRONOUS), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), - arraysize(kPushBodyFrame), 5), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause - }; - - HttpResponseInfo response; - HttpResponseInfo response2; - std::string expected_push_result("pushed"); - scoped_ptr<OrderedSocketData> data(new OrderedSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - RunServerPushTest(data.get(), - &response, - &response2, - expected_push_result); - - // Verify the SYN_REPLY. - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); - - // Verify the pushed stream. - EXPECT_TRUE(response2.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushSingleDataFrame2) { - static const unsigned char kPushBodyFrame[] = { - 0x00, 0x00, 0x00, 0x02, // header, ID - 0x01, 0x00, 0x00, 0x06, // FIN, length - 'p', 'u', 's', 'h', 'e', 'd' // "pushed" - }; - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 1, - "http://www.google.com/foo.dat")); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), - arraysize(kPushBodyFrame), 5), - CreateMockRead(*stream1_body, 4, SYNCHRONOUS), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause - }; - - HttpResponseInfo response; - HttpResponseInfo response2; - std::string expected_push_result("pushed"); - scoped_ptr<OrderedSocketData> data(new OrderedSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - RunServerPushTest(data.get(), - &response, - &response2, - expected_push_result); - - // Verify the SYN_REPLY. - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); - - // Verify the pushed stream. - EXPECT_TRUE(response2.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushServerAborted) { - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 1, - "http://www.google.com/foo.dat")); - scoped_ptr<SpdyFrame> - stream2_rst(ConstructSpdyRstStream(2, PROTOCOL_ERROR)); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream2_rst, 4), - CreateMockRead(*stream1_body, 5, SYNCHRONOUS), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - - helper.RunPreTestSetup(); - helper.AddData(data.get()); - - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - // Verify that we consumed all test data. - EXPECT_TRUE(data->at_read_eof()) << "Read count: " - << data->read_count() - << " Read index: " - << data->read_index(); - EXPECT_TRUE(data->at_write_eof()) << "Write count: " - << data->write_count() - << " Write index: " - << data->write_index(); - - // Verify the SYN_REPLY. - HttpResponseInfo response = *trans->GetResponseInfo(); - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushDuplicate) { - // Verify that we don't leak streams and that we properly send a reset - // if the server pushes the same stream twice. - static const unsigned char kPushBodyFrame[] = { - 0x00, 0x00, 0x00, 0x02, // header, ID - 0x01, 0x00, 0x00, 0x06, // FIN, length - 'p', 'u', 's', 'h', 'e', 'd' // "pushed" - }; - - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> - stream3_rst(ConstructSpdyRstStream(4, PROTOCOL_ERROR)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - CreateMockWrite(*stream3_rst, 5), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 1, - "http://www.google.com/foo.dat")); - scoped_ptr<SpdyFrame> - stream3_syn(ConstructSpdyPush(NULL, - 0, - 4, - 1, - "http://www.google.com/foo.dat")); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream3_syn, 4), - CreateMockRead(*stream1_body, 6, SYNCHRONOUS), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), - arraysize(kPushBodyFrame), 7), - MockRead(ASYNC, ERR_IO_PENDING, 8), // Force a pause - }; - - HttpResponseInfo response; - HttpResponseInfo response2; - std::string expected_push_result("pushed"); - scoped_ptr<OrderedSocketData> data(new OrderedSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - RunServerPushTest(data.get(), - &response, - &response2, - expected_push_result); - - // Verify the SYN_REPLY. - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); - - // Verify the pushed stream. - EXPECT_TRUE(response2.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushMultipleDataFrame) { - static const unsigned char kPushBodyFrame1[] = { - 0x00, 0x00, 0x00, 0x02, // header, ID - 0x01, 0x00, 0x00, 0x1F, // FIN, length - 'p', 'u', 's', 'h', 'e', 'd' // "pushed" - }; - static const char kPushBodyFrame2[] = " my darling"; - static const char kPushBodyFrame3[] = " hello"; - static const char kPushBodyFrame4[] = " my baby"; - - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 1, - "http://www.google.com/foo.dat")); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame1), - arraysize(kPushBodyFrame1), 4), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame2), - arraysize(kPushBodyFrame2) - 1, 5), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame3), - arraysize(kPushBodyFrame3) - 1, 6), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame4), - arraysize(kPushBodyFrame4) - 1, 7), - CreateMockRead(*stream1_body, 8, SYNCHRONOUS), - MockRead(ASYNC, ERR_IO_PENDING, 9), // Force a pause - }; - - HttpResponseInfo response; - HttpResponseInfo response2; - std::string expected_push_result("pushed my darling hello my baby"); - scoped_ptr<OrderedSocketData> data(new OrderedSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - RunServerPushTest(data.get(), - &response, - &response2, - expected_push_result); - - // Verify the SYN_REPLY. - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); - - // Verify the pushed stream. - EXPECT_TRUE(response2.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, - ServerPushMultipleDataFrameInterrupted) { - static const unsigned char kPushBodyFrame1[] = { - 0x00, 0x00, 0x00, 0x02, // header, ID - 0x01, 0x00, 0x00, 0x1F, // FIN, length - 'p', 'u', 's', 'h', 'e', 'd' // "pushed" - }; - static const char kPushBodyFrame2[] = " my darling"; - static const char kPushBodyFrame3[] = " hello"; - static const char kPushBodyFrame4[] = " my baby"; - - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 1, - "http://www.google.com/foo.dat")); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame1), - arraysize(kPushBodyFrame1), 4), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame2), - arraysize(kPushBodyFrame2) - 1, 5), - MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame3), - arraysize(kPushBodyFrame3) - 1, 7), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame4), - arraysize(kPushBodyFrame4) - 1, 8), - CreateMockRead(*stream1_body.get(), 9, SYNCHRONOUS), - MockRead(ASYNC, ERR_IO_PENDING, 10) // Force a pause. - }; - - HttpResponseInfo response; - HttpResponseInfo response2; - std::string expected_push_result("pushed my darling hello my baby"); - scoped_ptr<OrderedSocketData> data(new OrderedSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - RunServerPushTest(data.get(), - &response, - &response2, - expected_push_result); - - // Verify the SYN_REPLY. - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); - - // Verify the pushed stream. - EXPECT_TRUE(response2.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushInvalidAssociatedStreamID0) { - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> - stream2_rst(ConstructSpdyRstStream(2, INVALID_STREAM)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - CreateMockWrite(*stream2_rst, 4), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 0, - "http://www.google.com/foo.dat")); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream1_body, 4), - MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - - helper.RunPreTestSetup(); - helper.AddData(data.get()); - - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - // Verify that we consumed all test data. - EXPECT_TRUE(data->at_read_eof()) << "Read count: " - << data->read_count() - << " Read index: " - << data->read_index(); - EXPECT_TRUE(data->at_write_eof()) << "Write count: " - << data->write_count() - << " Write index: " - << data->write_index(); - - // Verify the SYN_REPLY. - HttpResponseInfo response = *trans->GetResponseInfo(); - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushInvalidAssociatedStreamID9) { - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> - stream2_rst(ConstructSpdyRstStream(2, INVALID_ASSOCIATED_STREAM)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - CreateMockWrite(*stream2_rst, 4), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 9, - "http://www.google.com/foo.dat")); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream1_body, 4), - MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - - helper.RunPreTestSetup(); - helper.AddData(data.get()); - - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - // Verify that we consumed all test data. - EXPECT_TRUE(data->at_read_eof()) << "Read count: " - << data->read_count() - << " Read index: " - << data->read_index(); - EXPECT_TRUE(data->at_write_eof()) << "Write count: " - << data->write_count() - << " Write index: " - << data->write_index(); - - // Verify the SYN_REPLY. - HttpResponseInfo response = *trans->GetResponseInfo(); - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushNoURL) { - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> - stream2_rst(ConstructSpdyRstStream(2, PROTOCOL_ERROR)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - CreateMockWrite(*stream2_rst, 4), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, 0, 2, 1)); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream1_body, 4), - MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - - helper.RunPreTestSetup(); - helper.AddData(data.get()); - - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - // Verify that we consumed all test data. - EXPECT_TRUE(data->at_read_eof()) << "Read count: " - << data->read_count() - << " Read index: " - << data->read_index(); - EXPECT_TRUE(data->at_write_eof()) << "Write count: " - << data->write_count() - << " Write index: " - << data->write_index(); - - // Verify the SYN_REPLY. - HttpResponseInfo response = *trans->GetResponseInfo(); - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); -} - -// Verify that various SynReply headers parse correctly through the -// HTTP layer. -TEST_P(SpdyNetworkTransactionSpdy21Test, SynReplyHeaders) { - struct SynReplyHeadersTests { - int num_headers; - const char* extra_headers[5]; - const char* expected_headers; - } test_cases[] = { - // This uses a multi-valued cookie header. - { 2, - { "cookie", "val1", - "cookie", "val2", // will get appended separated by NULL - NULL - }, - "cookie: val1\n" - "cookie: val2\n" - "hello: bye\n" - "status: 200\n" - "version: HTTP/1.1\n" - }, - // This is the minimalist set of headers. - { 0, - { NULL }, - "hello: bye\n" - "status: 200\n" - "version: HTTP/1.1\n" - }, - // Headers with a comma separated list. - { 1, - { "cookie", "val1,val2", - NULL - }, - "cookie: val1,val2\n" - "hello: bye\n" - "status: 200\n" - "version: HTTP/1.1\n" - } - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { - scoped_ptr<SpdyFrame> req( - ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> resp( - ConstructSpdyGetSynReply(test_cases[i].extra_headers, - test_cases[i].num_headers, - 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); - - scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers; - EXPECT_TRUE(headers.get() != NULL); - void* iter = NULL; - std::string name, value, lines; - while (headers->EnumerateHeaderLines(&iter, &name, &value)) { - lines.append(name); - lines.append(": "); - lines.append(value); - lines.append("\n"); - } - EXPECT_EQ(std::string(test_cases[i].expected_headers), lines); - } -} - -// Verify that various SynReply headers parse vary fields correctly -// through the HTTP layer, and the response matches the request. -TEST_P(SpdyNetworkTransactionSpdy21Test, SynReplyHeadersVary) { - static const SpdyHeaderInfo syn_reply_info = { - SYN_REPLY, // Syn Reply - 1, // Stream ID - 0, // Associated Stream ID - net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority - CONTROL_FLAG_NONE, // Control Flags - false, // Compressed - INVALID, // Status - NULL, // Data - 0, // Data Length - DATA_FLAG_NONE // Data Flags - }; - // Modify the following data to change/add test cases: - struct SynReplyTests { - const SpdyHeaderInfo* syn_reply; - bool vary_matches; - int num_headers[2]; - const char* extra_headers[2][16]; - } test_cases[] = { - // Test the case of a multi-valued cookie. When the value is delimited - // with NUL characters, it needs to be unfolded into multiple headers. - { - &syn_reply_info, - true, - { 1, 4 }, - { { "cookie", "val1,val2", - NULL - }, - { "vary", "cookie", - "status", "200", - "url", "/index.php", - "version", "HTTP/1.1", - NULL - } - } - }, { // Multiple vary fields. - &syn_reply_info, - true, - { 2, 5 }, - { { "friend", "barney", - "enemy", "snaggletooth", - NULL - }, - { "vary", "friend", - "vary", "enemy", - "status", "200", - "url", "/index.php", - "version", "HTTP/1.1", - NULL - } - } - }, { // Test a '*' vary field. - &syn_reply_info, - false, - { 1, 4 }, - { { "cookie", "val1,val2", - NULL - }, - { "vary", "*", - "status", "200", - "url", "/index.php", - "version", "HTTP/1.1", - NULL - } - } - }, { // Multiple comma-separated vary fields. - &syn_reply_info, - true, - { 2, 4 }, - { { "friend", "barney", - "enemy", "snaggletooth", - NULL - }, - { "vary", "friend,enemy", - "status", "200", - "url", "/index.php", - "version", "HTTP/1.1", - NULL - } - } - } - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { - // Construct the request. - scoped_ptr<SpdyFrame> frame_req( - ConstructSpdyGet(test_cases[i].extra_headers[0], - test_cases[i].num_headers[0], - false, 1, LOWEST)); - - MockWrite writes[] = { - CreateMockWrite(*frame_req), - }; - - // Construct the reply. - scoped_ptr<SpdyFrame> frame_reply( - ConstructSpdyPacket(*test_cases[i].syn_reply, - test_cases[i].extra_headers[1], - test_cases[i].num_headers[1], - NULL, - 0)); - - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*frame_reply), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - // Attach the headers to the request. - int header_count = test_cases[i].num_headers[0]; - - HttpRequestInfo request = CreateGetRequest(); - for (int ct = 0; ct < header_count; ct++) { - const char* header_key = test_cases[i].extra_headers[0][ct * 2]; - const char* header_value = test_cases[i].extra_headers[0][ct * 2 + 1]; - request.extra_headers.SetHeader(header_key, header_value); - } - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(request, - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - - EXPECT_EQ(OK, out.rv) << i; - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line) << i; - EXPECT_EQ("hello!", out.response_data) << i; - - // Test the response information. - EXPECT_TRUE(out.response_info.response_time > - out.response_info.request_time) << i; - base::TimeDelta test_delay = out.response_info.response_time - - out.response_info.request_time; - base::TimeDelta min_expected_delay; - min_expected_delay.FromMilliseconds(10); - EXPECT_GT(test_delay.InMillisecondsF(), - min_expected_delay.InMillisecondsF()) << i; - EXPECT_EQ(out.response_info.vary_data.is_valid(), - test_cases[i].vary_matches) << i; - - // Check the headers. - scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers; - ASSERT_TRUE(headers.get() != NULL) << i; - void* iter = NULL; - std::string name, value, lines; - while (headers->EnumerateHeaderLines(&iter, &name, &value)) { - lines.append(name); - lines.append(": "); - lines.append(value); - lines.append("\n"); - } - - // Construct the expected header reply string. - char reply_buffer[256] = ""; - ConstructSpdyReplyString(test_cases[i].extra_headers[1], - test_cases[i].num_headers[1], - reply_buffer, - 256); - - EXPECT_EQ(std::string(reply_buffer), lines) << i; - } -} - -// Verify that we don't crash on invalid SynReply responses. -TEST_P(SpdyNetworkTransactionSpdy21Test, InvalidSynReply) { - const SpdyHeaderInfo kSynStartHeader = { - SYN_REPLY, // Kind = SynReply - 1, // Stream ID - 0, // Associated stream ID - net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority - CONTROL_FLAG_NONE, // Control Flags - false, // Compressed - INVALID, // Status - NULL, // Data - 0, // Length - DATA_FLAG_NONE // Data Flags - }; - - struct InvalidSynReplyTests { - int num_headers; - const char* headers[10]; - } test_cases[] = { - // SYN_REPLY missing status header - { 4, - { "cookie", "val1", - "cookie", "val2", - "url", "/index.php", - "version", "HTTP/1.1", - NULL - }, - }, - // SYN_REPLY missing version header - { 2, - { "status", "200", - "url", "/index.php", - NULL - }, - }, - // SYN_REPLY with no headers - { 0, { NULL }, }, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { - scoped_ptr<SpdyFrame> req( - ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { - CreateMockWrite(*req), - }; - - scoped_ptr<SpdyFrame> resp( - ConstructSpdyPacket(kSynStartHeader, - NULL, 0, - test_cases[i].headers, - test_cases[i].num_headers)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(ERR_INCOMPLETE_SPDY_HEADERS, out.rv); - } -} - -// Verify that we don't crash on some corrupt frames. -TEST_P(SpdyNetworkTransactionSpdy21Test, CorruptFrameSessionError) { - // This is the length field that's too short. - scoped_ptr<SpdyFrame> syn_reply_wrong_length( - ConstructSpdyGetSynReply(NULL, 0, 1)); - syn_reply_wrong_length->set_length(syn_reply_wrong_length->length() - 4); - - struct SynReplyTests { - const SpdyFrame* syn_reply; - } test_cases[] = { - { syn_reply_wrong_length.get(), }, - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { - scoped_ptr<SpdyFrame> req( - ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { - CreateMockWrite(*req), - MockWrite(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*test_cases[i].syn_reply), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); - } -} - -// Test that we shutdown correctly on write errors. -TEST_P(SpdyNetworkTransactionSpdy21Test, WriteError) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { - // We'll write 10 bytes successfully - MockWrite(ASYNC, req->data(), 10), - // Followed by ERROR! - MockWrite(ASYNC, ERR_FAILED), - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(2, NULL, 0, - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(ERR_FAILED, out.rv); - data->Reset(); -} - -// Test that partial writes work. -TEST_P(SpdyNetworkTransactionSpdy21Test, PartialWrite) { - // Chop the SYN_STREAM frame into 5 chunks. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - const int kChunks = 5; - scoped_array<MockWrite> writes(ChopWriteFrame(*req.get(), kChunks)); - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(kChunks, reads, arraysize(reads), - writes.get(), kChunks)); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); -} - -// In this test, we enable compression, but get a uncompressed SynReply from -// the server. Verify that teardown is all clean. -TEST_P(SpdyNetworkTransactionSpdy21Test, DecompressFailureOnSynReply) { - // For this test, we turn on the normal compression. - SpdyFramer::set_enable_compression_default(true); - - scoped_ptr<SpdyFrame> compressed( - ConstructSpdyGet(NULL, 0, true, 1, LOWEST)); - scoped_ptr<SpdyFrame> rst( - ConstructSpdyRstStream(1, PROTOCOL_ERROR)); - MockWrite writes[] = { - CreateMockWrite(*compressed), - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); - data->Reset(); -} - -// Test that the NetLog contains good data for a simple GET request. -TEST_P(SpdyNetworkTransactionSpdy21Test, NetLog) { - static const char* const kExtraHeaders[] = { - "user-agent", "Chrome", - }; - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(kExtraHeaders, 1, false, 1, - LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - net::CapturingBoundNetLog log(net::CapturingNetLog::kUnbounded); - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequestWithUserAgent(), - log.bound(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); - - // Check that the NetLog was filled reasonably. - // This test is intentionally non-specific about the exact ordering of the - // log; instead we just check to make sure that certain events exist, and that - // they are in the right order. - net::CapturingNetLog::EntryList entries; - log.GetEntries(&entries); - - EXPECT_LT(0u, entries.size()); - int pos = 0; - pos = net::ExpectLogContainsSomewhere(entries, 0, - net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, - net::NetLog::PHASE_BEGIN); - pos = net::ExpectLogContainsSomewhere(entries, pos + 1, - net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, - net::NetLog::PHASE_END); - pos = net::ExpectLogContainsSomewhere(entries, pos + 1, - net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, - net::NetLog::PHASE_BEGIN); - pos = net::ExpectLogContainsSomewhere(entries, pos + 1, - net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, - net::NetLog::PHASE_END); - pos = net::ExpectLogContainsSomewhere(entries, pos + 1, - net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, - net::NetLog::PHASE_BEGIN); - pos = net::ExpectLogContainsSomewhere(entries, pos + 1, - net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, - net::NetLog::PHASE_END); - - // Check that we logged all the headers correctly - pos = net::ExpectLogContainsSomewhere( - entries, 0, - net::NetLog::TYPE_SPDY_SESSION_SYN_STREAM, - net::NetLog::PHASE_NONE); - CapturingNetLog::Entry entry = entries[pos]; - NetLogSpdySynParameter* request_params = - static_cast<NetLogSpdySynParameter*>(entry.extra_parameters.get()); - SpdyHeaderBlock* headers = - request_params->GetHeaders().get(); - - SpdyHeaderBlock expected; - expected["host"] = "www.google.com"; - expected["url"] = "/"; - expected["scheme"] = "http"; - expected["version"] = "HTTP/1.1"; - expected["method"] = "GET"; - expected["user-agent"] = "Chrome"; - EXPECT_EQ(expected.size(), headers->size()); - SpdyHeaderBlock::const_iterator end = expected.end(); - for (SpdyHeaderBlock::const_iterator it = expected.begin(); - it != end; - ++it) { - EXPECT_EQ(it->second, (*headers)[it->first]); - } -} - -// Since we buffer the IO from the stream to the renderer, this test verifies -// that when we read out the maximum amount of data (e.g. we received 50 bytes -// on the network, but issued a Read for only 5 of those bytes) that the data -// flow still works correctly. -TEST_P(SpdyNetworkTransactionSpdy21Test, BufferFull) { - BufferedSpdyFramer framer(2); - - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - // 2 data frames in a single read. - scoped_ptr<SpdyFrame> data_frame_1( - framer.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE)); - scoped_ptr<SpdyFrame> data_frame_2( - framer.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE)); - const SpdyFrame* data_frames[2] = { - data_frame_1.get(), - data_frame_2.get(), - }; - char combined_data_frames[100]; - int combined_data_frames_len = - CombineFrames(data_frames, arraysize(data_frames), - combined_data_frames, arraysize(combined_data_frames)); - scoped_ptr<SpdyFrame> last_frame( - framer.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN)); - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*resp), - MockRead(ASYNC, ERR_IO_PENDING), // Force a pause - MockRead(ASYNC, combined_data_frames, combined_data_frames_len), - MockRead(ASYNC, ERR_IO_PENDING), // Force a pause - CreateMockRead(*last_frame), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - - - TestCompletionCallback callback; - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - HttpNetworkTransaction* trans = helper.trans(); - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - TransactionHelperResult out = helper.output(); - out.rv = callback.WaitForResult(); - EXPECT_EQ(out.rv, OK); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - EXPECT_TRUE(response->headers != NULL); - EXPECT_TRUE(response->was_fetched_via_spdy); - out.status_line = response->headers->GetStatusLine(); - out.response_info = *response; // Make a copy so we can verify. - - // Read Data - TestCompletionCallback read_callback; - - std::string content; - do { - // Read small chunks at a time. - const int kSmallReadSize = 3; - scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); - rv = trans->Read(buf, kSmallReadSize, read_callback.callback()); - if (rv == net::ERR_IO_PENDING) { - data->CompleteRead(); - rv = read_callback.WaitForResult(); - } - if (rv > 0) { - content.append(buf->data(), rv); - } else if (rv < 0) { - NOTREACHED(); - } - } while (rv > 0); - - out.response_data.swap(content); - - // Flush the MessageLoop while the SpdySessionDependencies (in particular, the - // MockClientSocketFactory) are still alive. - MessageLoop::current()->RunAllPending(); - - // Verify that we consumed all test data. - helper.VerifyDataConsumed(); - - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("goodbye world", out.response_data); -} - -// Verify that basic buffering works; when multiple data frames arrive -// at the same time, ensure that we don't notify a read completion for -// each data frame individually. -TEST_P(SpdyNetworkTransactionSpdy21Test, Buffering) { - BufferedSpdyFramer framer(2); - - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - // 4 data frames in a single read. - scoped_ptr<SpdyFrame> data_frame( - framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); - scoped_ptr<SpdyFrame> data_frame_fin( - framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN)); - const SpdyFrame* data_frames[4] = { - data_frame.get(), - data_frame.get(), - data_frame.get(), - data_frame_fin.get() - }; - char combined_data_frames[100]; - int combined_data_frames_len = - CombineFrames(data_frames, arraysize(data_frames), - combined_data_frames, arraysize(combined_data_frames)); - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*resp), - MockRead(ASYNC, ERR_IO_PENDING), // Force a pause - MockRead(ASYNC, combined_data_frames, combined_data_frames_len), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - TransactionHelperResult out = helper.output(); - out.rv = callback.WaitForResult(); - EXPECT_EQ(out.rv, OK); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - EXPECT_TRUE(response->headers != NULL); - EXPECT_TRUE(response->was_fetched_via_spdy); - out.status_line = response->headers->GetStatusLine(); - out.response_info = *response; // Make a copy so we can verify. - - // Read Data - TestCompletionCallback read_callback; - - std::string content; - int reads_completed = 0; - do { - // Read small chunks at a time. - const int kSmallReadSize = 14; - scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); - rv = trans->Read(buf, kSmallReadSize, read_callback.callback()); - if (rv == net::ERR_IO_PENDING) { - data->CompleteRead(); - rv = read_callback.WaitForResult(); - } - if (rv > 0) { - EXPECT_EQ(kSmallReadSize, rv); - content.append(buf->data(), rv); - } else if (rv < 0) { - FAIL() << "Unexpected read error: " << rv; - } - reads_completed++; - } while (rv > 0); - - EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes. - - out.response_data.swap(content); - - // Flush the MessageLoop while the SpdySessionDependencies (in particular, the - // MockClientSocketFactory) are still alive. - MessageLoop::current()->RunAllPending(); - - // Verify that we consumed all test data. - helper.VerifyDataConsumed(); - - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("messagemessagemessagemessage", out.response_data); -} - -// Verify the case where we buffer data but read it after it has been buffered. -TEST_P(SpdyNetworkTransactionSpdy21Test, BufferedAll) { - BufferedSpdyFramer framer(2); - - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - // 5 data frames in a single read. - scoped_ptr<SpdyFrame> syn_reply( - ConstructSpdyGetSynReply(NULL, 0, 1)); - syn_reply->set_flags(CONTROL_FLAG_NONE); // turn off FIN bit - scoped_ptr<SpdyFrame> data_frame( - framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); - scoped_ptr<SpdyFrame> data_frame_fin( - framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN)); - const SpdyFrame* frames[5] = { - syn_reply.get(), - data_frame.get(), - data_frame.get(), - data_frame.get(), - data_frame_fin.get() - }; - char combined_frames[200]; - int combined_frames_len = - CombineFrames(frames, arraysize(frames), - combined_frames, arraysize(combined_frames)); - - MockRead reads[] = { - MockRead(ASYNC, combined_frames, combined_frames_len), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - TransactionHelperResult out = helper.output(); - out.rv = callback.WaitForResult(); - EXPECT_EQ(out.rv, OK); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - EXPECT_TRUE(response->headers != NULL); - EXPECT_TRUE(response->was_fetched_via_spdy); - out.status_line = response->headers->GetStatusLine(); - out.response_info = *response; // Make a copy so we can verify. - - // Read Data - TestCompletionCallback read_callback; - - std::string content; - int reads_completed = 0; - do { - // Read small chunks at a time. - const int kSmallReadSize = 14; - scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); - rv = trans->Read(buf, kSmallReadSize, read_callback.callback()); - if (rv > 0) { - EXPECT_EQ(kSmallReadSize, rv); - content.append(buf->data(), rv); - } else if (rv < 0) { - FAIL() << "Unexpected read error: " << rv; - } - reads_completed++; - } while (rv > 0); - - EXPECT_EQ(3, reads_completed); - - out.response_data.swap(content); - - // Flush the MessageLoop while the SpdySessionDependencies (in particular, the - // MockClientSocketFactory) are still alive. - MessageLoop::current()->RunAllPending(); - - // Verify that we consumed all test data. - helper.VerifyDataConsumed(); - - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("messagemessagemessagemessage", out.response_data); -} - -// Verify the case where we buffer data and close the connection. -TEST_P(SpdyNetworkTransactionSpdy21Test, BufferedClosed) { - BufferedSpdyFramer framer(2); - - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - // All data frames in a single read. - // NOTE: We don't FIN the stream. - scoped_ptr<SpdyFrame> data_frame( - framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); - const SpdyFrame* data_frames[4] = { - data_frame.get(), - data_frame.get(), - data_frame.get(), - data_frame.get() - }; - char combined_data_frames[100]; - int combined_data_frames_len = - CombineFrames(data_frames, arraysize(data_frames), - combined_data_frames, arraysize(combined_data_frames)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*resp), - MockRead(ASYNC, ERR_IO_PENDING), // Force a wait - MockRead(ASYNC, combined_data_frames, combined_data_frames_len), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - TransactionHelperResult out = helper.output(); - out.rv = callback.WaitForResult(); - EXPECT_EQ(out.rv, OK); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - EXPECT_TRUE(response->headers != NULL); - EXPECT_TRUE(response->was_fetched_via_spdy); - out.status_line = response->headers->GetStatusLine(); - out.response_info = *response; // Make a copy so we can verify. - - // Read Data - TestCompletionCallback read_callback; - - std::string content; - int reads_completed = 0; - do { - // Read small chunks at a time. - const int kSmallReadSize = 14; - scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); - rv = trans->Read(buf, kSmallReadSize, read_callback.callback()); - if (rv == net::ERR_IO_PENDING) { - data->CompleteRead(); - rv = read_callback.WaitForResult(); - } - if (rv > 0) { - content.append(buf->data(), rv); - } else if (rv < 0) { - // This test intentionally closes the connection, and will get an error. - EXPECT_EQ(ERR_CONNECTION_CLOSED, rv); - break; - } - reads_completed++; - } while (rv > 0); - - EXPECT_EQ(0, reads_completed); - - out.response_data.swap(content); - - // Flush the MessageLoop while the SpdySessionDependencies (in particular, the - // MockClientSocketFactory) are still alive. - MessageLoop::current()->RunAllPending(); - - // Verify that we consumed all test data. - helper.VerifyDataConsumed(); -} - -// Verify the case where we buffer data and cancel the transaction. -TEST_P(SpdyNetworkTransactionSpdy21Test, BufferedCancelled) { - BufferedSpdyFramer framer(2); - - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - // NOTE: We don't FIN the stream. - scoped_ptr<SpdyFrame> data_frame( - framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*resp), - MockRead(ASYNC, ERR_IO_PENDING), // Force a wait - CreateMockRead(*data_frame), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - HttpNetworkTransaction* trans = helper.trans(); - TestCompletionCallback callback; - - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - TransactionHelperResult out = helper.output(); - out.rv = callback.WaitForResult(); - EXPECT_EQ(out.rv, OK); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - EXPECT_TRUE(response->headers != NULL); - EXPECT_TRUE(response->was_fetched_via_spdy); - out.status_line = response->headers->GetStatusLine(); - out.response_info = *response; // Make a copy so we can verify. - - // Read Data - TestCompletionCallback read_callback; - - do { - const int kReadSize = 256; - scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kReadSize)); - rv = trans->Read(buf, kReadSize, read_callback.callback()); - if (rv == net::ERR_IO_PENDING) { - // Complete the read now, which causes buffering to start. - data->CompleteRead(); - // Destroy the transaction, causing the stream to get cancelled - // and orphaning the buffered IO task. - helper.ResetTrans(); - break; - } - // We shouldn't get here in this test. - FAIL() << "Unexpected read: " << rv; - } while (rv > 0); - - // Flush the MessageLoop; this will cause the buffered IO task - // to run for the final time. - MessageLoop::current()->RunAllPending(); - - // Verify that we consumed all test data. - helper.VerifyDataConsumed(); -} - -// Test that if the server requests persistence of settings, that we save -// the settings in the SpdySettingsStorage. -TEST_P(SpdyNetworkTransactionSpdy21Test, SettingsSaved) { - static const SpdyHeaderInfo kSynReplyInfo = { - SYN_REPLY, // Syn Reply - 1, // Stream ID - 0, // Associated Stream ID - net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority - CONTROL_FLAG_NONE, // Control Flags - false, // Compressed - INVALID, // Status - NULL, // Data - 0, // Data Length - DATA_FLAG_NONE // Data Flags - }; - static const char* const kExtraHeaders[] = { - "status", "200", - "version", "HTTP/1.1" - }; - - BoundNetLog net_log; - NormalSpdyTransactionHelper helper(CreateGetRequest(), net_log, GetParam()); - helper.RunPreTestSetup(); - - // Verify that no settings exist initially. - HostPortPair host_port_pair("www.google.com", helper.port()); - SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); - EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings( - host_port_pair).empty()); - - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - // Construct the reply. - scoped_ptr<SpdyFrame> reply( - ConstructSpdyPacket(kSynReplyInfo, - kExtraHeaders, - arraysize(kExtraHeaders) / 2, - NULL, - 0)); - - const SpdySettingsIds kSampleId1 = SETTINGS_UPLOAD_BANDWIDTH; - unsigned int kSampleValue1 = 0x0a0a0a0a; - const SpdySettingsIds kSampleId2 = SETTINGS_DOWNLOAD_BANDWIDTH; - unsigned int kSampleValue2 = 0x0b0b0b0b; - const SpdySettingsIds kSampleId3 = SETTINGS_ROUND_TRIP_TIME; - unsigned int kSampleValue3 = 0x0c0c0c0c; - scoped_ptr<SpdyFrame> settings_frame; - { - // Construct the SETTINGS frame. - SpdySettings settings; - // First add a persisted setting. - SettingsFlagsAndId setting1(SETTINGS_FLAG_PLEASE_PERSIST, kSampleId1); - settings.push_back(std::make_pair(setting1, kSampleValue1)); - // Next add a non-persisted setting. - SettingsFlagsAndId setting2(SETTINGS_FLAG_NONE, kSampleId2); - settings.push_back(std::make_pair(setting2, kSampleValue2)); - // Next add another persisted setting. - SettingsFlagsAndId setting3(SETTINGS_FLAG_PLEASE_PERSIST, kSampleId3); - settings.push_back(std::make_pair(setting3, kSampleValue3)); - settings_frame.reset(ConstructSpdySettings(settings)); - } - - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*reply), - CreateMockRead(*body), - CreateMockRead(*settings_frame), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - helper.AddData(data.get()); - helper.RunDefaultTest(); - helper.VerifyDataConsumed(); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); - - { - // Verify we had two persisted settings. - const SettingsMap& settings_map = - spdy_session_pool->http_server_properties()->GetSpdySettings( - host_port_pair); - ASSERT_EQ(2u, settings_map.size()); - - // Verify the first persisted setting. - SettingsMap::const_iterator it1 = settings_map.find(kSampleId1); - EXPECT_TRUE(it1 != settings_map.end()); - SettingsFlagsAndValue flags_and_value1 = it1->second; - EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first); - EXPECT_EQ(kSampleValue1, flags_and_value1.second); - - // Verify the second persisted setting. - SettingsMap::const_iterator it3 = settings_map.find(kSampleId3); - EXPECT_TRUE(it3 != settings_map.end()); - SettingsFlagsAndValue flags_and_value3 = it3->second; - EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value3.first); - EXPECT_EQ(kSampleValue3, flags_and_value3.second); - } -} - -// Test that when there are settings saved that they are sent back to the -// server upon session establishment. -TEST_P(SpdyNetworkTransactionSpdy21Test, SettingsPlayback) { - static const SpdyHeaderInfo kSynReplyInfo = { - SYN_REPLY, // Syn Reply - 1, // Stream ID - 0, // Associated Stream ID - net::ConvertRequestPriorityToSpdyPriority(LOWEST), // Priority - CONTROL_FLAG_NONE, // Control Flags - false, // Compressed - INVALID, // Status - NULL, // Data - 0, // Data Length - DATA_FLAG_NONE // Data Flags - }; - static const char* kExtraHeaders[] = { - "status", "200", - "version", "HTTP/1.1" - }; - - BoundNetLog net_log; - NormalSpdyTransactionHelper helper(CreateGetRequest(), net_log, GetParam()); - helper.RunPreTestSetup(); - - // Verify that no settings exist initially. - HostPortPair host_port_pair("www.google.com", helper.port()); - SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); - EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings( - host_port_pair).empty()); - - const SpdySettingsIds kSampleId1 = SETTINGS_UPLOAD_BANDWIDTH; - unsigned int kSampleValue1 = 0x0a0a0a0a; - const SpdySettingsIds kSampleId2 = SETTINGS_ROUND_TRIP_TIME; - unsigned int kSampleValue2 = 0x0c0c0c0c; - - // First add a persisted setting. - spdy_session_pool->http_server_properties()->SetSpdySetting( - host_port_pair, - kSampleId1, - SETTINGS_FLAG_PLEASE_PERSIST, - kSampleValue1); - - // Next add another persisted setting. - spdy_session_pool->http_server_properties()->SetSpdySetting( - host_port_pair, - kSampleId2, - SETTINGS_FLAG_PLEASE_PERSIST, - kSampleValue2); - - EXPECT_EQ(2u, spdy_session_pool->http_server_properties()->GetSpdySettings( - host_port_pair).size()); - - // Construct the SETTINGS frame. - const SettingsMap& settings_map = - spdy_session_pool->http_server_properties()->GetSpdySettings( - host_port_pair); - - SpdySettings settings; - for (SettingsMap::const_iterator i = settings_map.begin(), - end = settings_map.end(); i != end; ++i) { - const SpdySettingsIds id = i->first; - const SpdySettingsFlags flags = i->second.first; - const uint32 val = i->second.second; - SettingsFlagsAndId flags_and_id(flags, id); - settings.push_back(SpdySetting(flags_and_id, val)); - } - - scoped_ptr<SpdyFrame> settings_frame(ConstructSpdySettings(settings)); - - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - - MockWrite writes[] = { - CreateMockWrite(*settings_frame), - CreateMockWrite(*req), - }; - - // Construct the reply. - scoped_ptr<SpdyFrame> reply( - ConstructSpdyPacket(kSynReplyInfo, - kExtraHeaders, - arraysize(kExtraHeaders) / 2, - NULL, - 0)); - - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*reply), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(2, reads, arraysize(reads), - writes, arraysize(writes))); - helper.AddData(data.get()); - helper.RunDefaultTest(); - helper.VerifyDataConsumed(); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); - - { - // Verify we had two persisted settings. - const SettingsMap& settings_map = - spdy_session_pool->http_server_properties()->GetSpdySettings( - host_port_pair); - ASSERT_EQ(2u, settings_map.size()); - - // Verify the first persisted setting. - SettingsMap::const_iterator it1 = settings_map.find(kSampleId1); - EXPECT_TRUE(it1 != settings_map.end()); - SettingsFlagsAndValue flags_and_value1 = it1->second; - EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first); - EXPECT_EQ(kSampleValue1, flags_and_value1.second); - - // Verify the second persisted setting. - SettingsMap::const_iterator it2 = settings_map.find(kSampleId2); - EXPECT_TRUE(it2 != settings_map.end()); - SettingsFlagsAndValue flags_and_value2 = it2->second; - EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value2.first); - EXPECT_EQ(kSampleValue2, flags_and_value2.second); - } -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, GoAwayWithActiveStream) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> go_away(ConstructSpdyGoAway()); - MockRead reads[] = { - CreateMockRead(*go_away), - MockRead(ASYNC, 0, 0), // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.AddData(data.get()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(ERR_ABORTED, out.rv); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, CloseWithActiveStream) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*resp), - MockRead(SYNCHRONOUS, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - BoundNetLog log; - NormalSpdyTransactionHelper helper(CreateGetRequest(), - log, GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - TransactionHelperResult out; - out.rv = trans->Start(&CreateGetRequest(), callback.callback(), log); - - EXPECT_EQ(out.rv, ERR_IO_PENDING); - out.rv = callback.WaitForResult(); - EXPECT_EQ(out.rv, OK); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - EXPECT_TRUE(response->headers != NULL); - EXPECT_TRUE(response->was_fetched_via_spdy); - out.rv = ReadTransaction(trans, &out.response_data); - EXPECT_EQ(ERR_CONNECTION_CLOSED, out.rv); - - // Verify that we consumed all test data. - helper.VerifyDataConsumed(); -} - -// Test to make sure we can correctly connect through a proxy. -TEST_P(SpdyNetworkTransactionSpdy21Test, ProxyConnect) { - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.session_deps().reset(new SpdySessionDependencies( - ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"))); - helper.SetSession(make_scoped_refptr( - SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get()))); - helper.RunPreTestSetup(); - HttpNetworkTransaction* trans = helper.trans(); - - const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"}; - const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"}; - const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"}; - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - - MockWrite writes_SPDYNPN[] = { - MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0), - CreateMockWrite(*req, 2), - }; - MockRead reads_SPDYNPN[] = { - MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), - CreateMockRead(*resp, 3), - CreateMockRead(*body.get(), 4), - MockRead(ASYNC, 0, 0, 5), - }; - - MockWrite writes_SPDYSSL[] = { - MockWrite(SYNCHRONOUS, kConnect80, arraysize(kConnect80) - 1, 0), - CreateMockWrite(*req, 2), - }; - MockRead reads_SPDYSSL[] = { - MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), - CreateMockRead(*resp, 3), - CreateMockRead(*body.get(), 4), - MockRead(ASYNC, 0, 0, 5), - }; - - MockWrite writes_SPDYNOSSL[] = { - CreateMockWrite(*req, 0), - }; - - MockRead reads_SPDYNOSSL[] = { - CreateMockRead(*resp, 1), - CreateMockRead(*body.get(), 2), - MockRead(ASYNC, 0, 0, 3), - }; - - scoped_ptr<OrderedSocketData> data; - switch(GetParam()) { - case SPDYNOSSL: - data.reset(new OrderedSocketData(reads_SPDYNOSSL, - arraysize(reads_SPDYNOSSL), - writes_SPDYNOSSL, - arraysize(writes_SPDYNOSSL))); - break; - case SPDYSSL: - data.reset(new OrderedSocketData(reads_SPDYSSL, - arraysize(reads_SPDYSSL), - writes_SPDYSSL, - arraysize(writes_SPDYSSL))); - break; - case SPDYNPN: - data.reset(new OrderedSocketData(reads_SPDYNPN, - arraysize(reads_SPDYNPN), - writes_SPDYNPN, - arraysize(writes_SPDYNPN))); - break; - default: - NOTREACHED(); - } - - helper.AddData(data.get()); - TestCompletionCallback callback; - - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - - rv = callback.WaitForResult(); - EXPECT_EQ(0, rv); - - // Verify the SYN_REPLY. - HttpResponseInfo response = *trans->GetResponseInfo(); - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans, &response_data)); - EXPECT_EQ("hello!", response_data); - helper.VerifyDataConsumed(); -} - -// Test to make sure we can correctly connect through a proxy to www.google.com, -// if there already exists a direct spdy connection to www.google.com. See -// http://crbug.com/49874 -TEST_P(SpdyNetworkTransactionSpdy21Test, DirectConnectProxyReconnect) { - // When setting up the first transaction, we store the SpdySessionPool so that - // we can use the same pool in the second transaction. - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - - // Use a proxy service which returns a proxy fallback list from DIRECT to - // myproxy:70. For this test there will be no fallback, so it is equivalent - // to simply DIRECT. The reason for appending the second proxy is to verify - // that the session pool key used does is just "DIRECT". - helper.session_deps().reset(new SpdySessionDependencies( - ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70"))); - helper.SetSession(make_scoped_refptr( - SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get()))); - - SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); - helper.RunPreTestSetup(); - - // Construct and send a simple GET request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { - CreateMockWrite(*req, 1), - }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp, 2), - CreateMockRead(*body, 3), - MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause - MockRead(ASYNC, 0, 5) // EOF - }; - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - helper.AddData(data.get()); - HttpNetworkTransaction* trans = helper.trans(); - - TestCompletionCallback callback; - TransactionHelperResult out; - out.rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - - EXPECT_EQ(out.rv, ERR_IO_PENDING); - out.rv = callback.WaitForResult(); - EXPECT_EQ(out.rv, OK); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - EXPECT_TRUE(response->headers != NULL); - EXPECT_TRUE(response->was_fetched_via_spdy); - out.rv = ReadTransaction(trans, &out.response_data); - EXPECT_EQ(OK, out.rv); - out.status_line = response->headers->GetStatusLine(); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); - - // Check that the SpdySession is still in the SpdySessionPool. - HostPortPair host_port_pair("www.google.com", helper.port()); - HostPortProxyPair session_pool_key_direct( - host_port_pair, ProxyServer::Direct()); - EXPECT_TRUE(spdy_session_pool->HasSession(session_pool_key_direct)); - HostPortProxyPair session_pool_key_proxy( - host_port_pair, - ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP)); - EXPECT_FALSE(spdy_session_pool->HasSession(session_pool_key_proxy)); - - // Set up data for the proxy connection. - const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"}; - const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n" - "Host: www.google.com\r\n" - "Proxy-Connection: keep-alive\r\n\r\n"}; - const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"}; - scoped_ptr<SpdyFrame> req2(ConstructSpdyGet( - "http://www.google.com/foo.dat", false, 1, LOWEST)); - scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(1, true)); - - MockWrite writes_SPDYNPN[] = { - MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0), - CreateMockWrite(*req2, 2), - }; - MockRead reads_SPDYNPN[] = { - MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), - CreateMockRead(*resp2, 3), - CreateMockRead(*body2, 4), - MockRead(ASYNC, 0, 5) // EOF - }; - - MockWrite writes_SPDYNOSSL[] = { - CreateMockWrite(*req2, 0), - }; - MockRead reads_SPDYNOSSL[] = { - CreateMockRead(*resp2, 1), - CreateMockRead(*body2, 2), - MockRead(ASYNC, 0, 3) // EOF - }; - - MockWrite writes_SPDYSSL[] = { - MockWrite(SYNCHRONOUS, kConnect80, arraysize(kConnect80) - 1, 0), - CreateMockWrite(*req2, 2), - }; - MockRead reads_SPDYSSL[] = { - MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), - CreateMockRead(*resp2, 3), - CreateMockRead(*body2, 4), - MockRead(ASYNC, 0, 0, 5), - }; - - scoped_ptr<OrderedSocketData> data_proxy; - switch(GetParam()) { - case SPDYNPN: - data_proxy.reset(new OrderedSocketData(reads_SPDYNPN, - arraysize(reads_SPDYNPN), - writes_SPDYNPN, - arraysize(writes_SPDYNPN))); - break; - case SPDYNOSSL: - data_proxy.reset(new OrderedSocketData(reads_SPDYNOSSL, - arraysize(reads_SPDYNOSSL), - writes_SPDYNOSSL, - arraysize(writes_SPDYNOSSL))); - break; - case SPDYSSL: - data_proxy.reset(new OrderedSocketData(reads_SPDYSSL, - arraysize(reads_SPDYSSL), - writes_SPDYSSL, - arraysize(writes_SPDYSSL))); - break; - default: - NOTREACHED(); - } - - // Create another request to www.google.com, but this time through a proxy. - HttpRequestInfo request_proxy; - request_proxy.method = "GET"; - request_proxy.url = GURL("http://www.google.com/foo.dat"); - request_proxy.load_flags = 0; - scoped_ptr<SpdySessionDependencies> ssd_proxy(new SpdySessionDependencies()); - // Ensure that this transaction uses the same SpdySessionPool. - scoped_refptr<HttpNetworkSession> session_proxy( - SpdySessionDependencies::SpdyCreateSession(ssd_proxy.get())); - NormalSpdyTransactionHelper helper_proxy(request_proxy, - BoundNetLog(), GetParam()); - HttpNetworkSessionPeer session_peer(session_proxy); - scoped_ptr<net::ProxyService> proxy_service( - ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); - session_peer.SetProxyService(proxy_service.get()); - helper_proxy.session_deps().swap(ssd_proxy); - helper_proxy.SetSession(session_proxy); - helper_proxy.RunPreTestSetup(); - helper_proxy.AddData(data_proxy.get()); - - HttpNetworkTransaction* trans_proxy = helper_proxy.trans(); - TestCompletionCallback callback_proxy; - int rv = trans_proxy->Start( - &request_proxy, callback_proxy.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback_proxy.WaitForResult(); - EXPECT_EQ(0, rv); - - HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo(); - EXPECT_TRUE(response_proxy.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response_proxy.headers->GetStatusLine()); - - std::string response_data; - ASSERT_EQ(OK, ReadTransaction(trans_proxy, &response_data)); - EXPECT_EQ("hello!", response_data); - - data->CompleteRead(); - helper_proxy.VerifyDataConsumed(); -} - -// When we get a TCP-level RST, we need to retry a HttpNetworkTransaction -// on a new connection, if the connection was previously known to be good. -// This can happen when a server reboots without saying goodbye, or when -// we're behind a NAT that masked the RST. -TEST_P(SpdyNetworkTransactionSpdy21Test, VerifyRetryOnConnectionReset) { - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, ERR_IO_PENDING), - MockRead(ASYNC, ERR_CONNECTION_RESET), - }; - - MockRead reads2[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - // This test has a couple of variants. - enum { - // Induce the RST while waiting for our transaction to send. - VARIANT_RST_DURING_SEND_COMPLETION, - // Induce the RST while waiting for our transaction to read. - // In this case, the send completed - everything copied into the SNDBUF. - VARIANT_RST_DURING_READ_COMPLETION - }; - - for (int variant = VARIANT_RST_DURING_SEND_COMPLETION; - variant <= VARIANT_RST_DURING_READ_COMPLETION; - ++variant) { - scoped_ptr<DelayedSocketData> data1( - new DelayedSocketData(1, reads, arraysize(reads), - NULL, 0)); - - scoped_ptr<DelayedSocketData> data2( - new DelayedSocketData(1, reads2, arraysize(reads2), - NULL, 0)); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.AddData(data1.get()); - helper.AddData(data2.get()); - helper.RunPreTestSetup(); - - for (int i = 0; i < 2; ++i) { - scoped_ptr<HttpNetworkTransaction> trans( - new HttpNetworkTransaction(helper.session())); - - TestCompletionCallback callback; - int rv = trans->Start( - &helper.request(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - // On the second transaction, we trigger the RST. - if (i == 1) { - if (variant == VARIANT_RST_DURING_READ_COMPLETION) { - // Writes to the socket complete asynchronously on SPDY by running - // through the message loop. Complete the write here. - MessageLoop::current()->RunAllPending(); - } - - // Now schedule the ERR_CONNECTION_RESET. - EXPECT_EQ(3u, data1->read_index()); - data1->CompleteRead(); - EXPECT_EQ(4u, data1->read_index()); - } - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - const HttpResponseInfo* response = trans->GetResponseInfo(); - ASSERT_TRUE(response != NULL); - EXPECT_TRUE(response->headers != NULL); - EXPECT_TRUE(response->was_fetched_via_spdy); - std::string response_data; - rv = ReadTransaction(trans.get(), &response_data); - EXPECT_EQ(OK, rv); - EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); - EXPECT_EQ("hello!", response_data); - } - - helper.VerifyDataConsumed(); - } -} - -// Test that turning SPDY on and off works properly. -TEST_P(SpdyNetworkTransactionSpdy21Test, SpdyOnOffToggle) { - net::HttpStreamFactory::set_spdy_enabled(true); - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite spdy_writes[] = { CreateMockWrite(*req) }; - - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(1, true)); - MockRead spdy_reads[] = { - CreateMockRead(*resp), - CreateMockRead(*body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, - spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); - - net::HttpStreamFactory::set_spdy_enabled(false); - MockRead http_reads[] = { - MockRead("HTTP/1.1 200 OK\r\n\r\n"), - MockRead("hello from http"), - MockRead(SYNCHRONOUS, OK), - }; - scoped_ptr<DelayedSocketData> data2( - new DelayedSocketData(1, http_reads, arraysize(http_reads), - NULL, 0)); - NormalSpdyTransactionHelper helper2(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper2.SetSpdyDisabled(); - helper2.RunToCompletion(data2.get()); - TransactionHelperResult out2 = helper2.output(); - EXPECT_EQ(OK, out2.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out2.status_line); - EXPECT_EQ("hello from http", out2.response_data); - - net::HttpStreamFactory::set_spdy_enabled(true); -} - -// Tests that Basic authentication works over SPDY -TEST_P(SpdyNetworkTransactionSpdy21Test, SpdyBasicAuth) { - net::HttpStreamFactory::set_spdy_enabled(true); - - // The first request will be a bare GET, the second request will be a - // GET with an Authorization header. - scoped_ptr<SpdyFrame> req_get( - ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - const char* const kExtraAuthorizationHeaders[] = { - "authorization", - "Basic Zm9vOmJhcg==", - }; - scoped_ptr<SpdyFrame> req_get_authorization( - ConstructSpdyGet( - kExtraAuthorizationHeaders, - arraysize(kExtraAuthorizationHeaders) / 2, - false, 3, LOWEST)); - MockWrite spdy_writes[] = { - CreateMockWrite(*req_get, 1), - CreateMockWrite(*req_get_authorization, 4), - }; - - // The first response is a 401 authentication challenge, and the second - // response will be a 200 response since the second request includes a valid - // Authorization header. - const char* const kExtraAuthenticationHeaders[] = { - "www-authenticate", - "Basic realm=\"MyRealm\"" - }; - scoped_ptr<SpdyFrame> resp_authentication( - ConstructSpdySynReplyError( - "401 Authentication Required", - kExtraAuthenticationHeaders, - arraysize(kExtraAuthenticationHeaders) / 2, - 1)); - scoped_ptr<SpdyFrame> body_authentication( - ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> resp_data(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> body_data(ConstructSpdyBodyFrame(3, true)); - MockRead spdy_reads[] = { - CreateMockRead(*resp_authentication, 2), - CreateMockRead(*body_authentication, 3), - CreateMockRead(*resp_data, 5), - CreateMockRead(*body_data, 6), - MockRead(ASYNC, 0, 7), - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(spdy_reads, arraysize(spdy_reads), - spdy_writes, arraysize(spdy_writes))); - HttpRequestInfo request(CreateGetRequest()); - BoundNetLog net_log; - NormalSpdyTransactionHelper helper(request, net_log, GetParam()); - - helper.RunPreTestSetup(); - helper.AddData(data.get()); - HttpNetworkTransaction* trans = helper.trans(); - TestCompletionCallback callback; - const int rv_start = trans->Start(&request, callback.callback(), net_log); - EXPECT_EQ(ERR_IO_PENDING, rv_start); - const int rv_start_complete = callback.WaitForResult(); - EXPECT_EQ(OK, rv_start_complete); - - // Make sure the response has an auth challenge. - const HttpResponseInfo* const response_start = trans->GetResponseInfo(); - ASSERT_TRUE(response_start != NULL); - ASSERT_TRUE(response_start->headers != NULL); - EXPECT_EQ(401, response_start->headers->response_code()); - EXPECT_TRUE(response_start->was_fetched_via_spdy); - AuthChallengeInfo* auth_challenge = response_start->auth_challenge.get(); - ASSERT_TRUE(auth_challenge != NULL); - EXPECT_FALSE(auth_challenge->is_proxy); - EXPECT_EQ("basic", auth_challenge->scheme); - EXPECT_EQ("MyRealm", auth_challenge->realm); - - // Restart with a username/password. - AuthCredentials credentials(ASCIIToUTF16("foo"), ASCIIToUTF16("bar")); - TestCompletionCallback callback_restart; - const int rv_restart = trans->RestartWithAuth( - credentials, callback_restart.callback()); - EXPECT_EQ(ERR_IO_PENDING, rv_restart); - const int rv_restart_complete = callback_restart.WaitForResult(); - EXPECT_EQ(OK, rv_restart_complete); - // TODO(cbentzel): This is actually the same response object as before, but - // data has changed. - const HttpResponseInfo* const response_restart = trans->GetResponseInfo(); - ASSERT_TRUE(response_restart != NULL); - ASSERT_TRUE(response_restart->headers != NULL); - EXPECT_EQ(200, response_restart->headers->response_code()); - EXPECT_TRUE(response_restart->auth_challenge.get() == NULL); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushWithHeaders) { - static const unsigned char kPushBodyFrame[] = { - 0x00, 0x00, 0x00, 0x02, // header, ID - 0x01, 0x00, 0x00, 0x06, // FIN, length - 'p', 'u', 's', 'h', 'e', 'd' // "pushed" - }; - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - }; - - static const char* const kInitialHeaders[] = { - "url", - "http://www.google.com/foo.dat", - }; - static const char* const kLateHeaders[] = { - "hello", - "bye", - "status", - "200", - "version", - "HTTP/1.1" - }; - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyControlFrame(kInitialHeaders, - arraysize(kInitialHeaders) / 2, - false, - 2, - LOWEST, - SYN_STREAM, - CONTROL_FLAG_NONE, - NULL, - 0, - 1)); - scoped_ptr<SpdyFrame> - stream2_headers(ConstructSpdyControlFrame(kLateHeaders, - arraysize(kLateHeaders) / 2, - false, - 2, - LOWEST, - HEADERS, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream2_headers, 4), - CreateMockRead(*stream1_body, 5, SYNCHRONOUS), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), - arraysize(kPushBodyFrame), 6), - MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause - }; - - HttpResponseInfo response; - HttpResponseInfo response2; - std::string expected_push_result("pushed"); - scoped_ptr<OrderedSocketData> data(new OrderedSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - RunServerPushTest(data.get(), - &response, - &response2, - expected_push_result); - - // Verify the SYN_REPLY. - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); - - // Verify the pushed stream. - EXPECT_TRUE(response2.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushClaimBeforeHeaders) { - // We push a stream and attempt to claim it before the headers come down. - static const unsigned char kPushBodyFrame[] = { - 0x00, 0x00, 0x00, 0x02, // header, ID - 0x01, 0x00, 0x00, 0x06, // FIN, length - 'p', 'u', 's', 'h', 'e', 'd' // "pushed" - }; - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS), - }; - - static const char* const kInitialHeaders[] = { - "url", - "http://www.google.com/foo.dat", - }; - static const char* const kLateHeaders[] = { - "hello", - "bye", - "status", - "200", - "version", - "HTTP/1.1" - }; - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyControlFrame(kInitialHeaders, - arraysize(kInitialHeaders) / 2, - false, - 2, - LOWEST, - SYN_STREAM, - CONTROL_FLAG_NONE, - NULL, - 0, - 1)); - scoped_ptr<SpdyFrame> - stream2_headers(ConstructSpdyControlFrame(kLateHeaders, - arraysize(kLateHeaders) / 2, - false, - 2, - LOWEST, - HEADERS, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 1), - CreateMockRead(*stream2_syn, 2), - CreateMockRead(*stream1_body, 3), - CreateMockRead(*stream2_headers, 4), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), - arraysize(kPushBodyFrame), 5), - MockRead(ASYNC, 0, 5), // EOF - }; - - HttpResponseInfo response; - HttpResponseInfo response2; - std::string expected_push_result("pushed"); - scoped_refptr<DeterministicSocketData> data(new DeterministicSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.SetDeterministic(); - helper.AddDeterministicData(static_cast<DeterministicSocketData*>(data)); - helper.RunPreTestSetup(); - - HttpNetworkTransaction* trans = helper.trans(); - - // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM, - // and the body of the primary stream, but before we've received the HEADERS - // for the pushed stream. - data->SetStop(3); - - // Start the transaction. - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - data->Run(); - rv = callback.WaitForResult(); - EXPECT_EQ(0, rv); - - // Request the pushed path. At this point, we've received the push, but the - // headers are not yet complete. - scoped_ptr<HttpNetworkTransaction> trans2( - new HttpNetworkTransaction(helper.session())); - rv = trans2->Start( - &CreateGetPushRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - data->RunFor(3); - MessageLoop::current()->RunAllPending(); - - // Read the server push body. - std::string result2; - ReadResult(trans2.get(), data.get(), &result2); - // Read the response body. - std::string result; - ReadResult(trans, data, &result); - - // Verify that we consumed all test data. - EXPECT_TRUE(data->at_read_eof()); - EXPECT_TRUE(data->at_write_eof()); - - // Verify that the received push data is same as the expected push data. - EXPECT_EQ(result2.compare(expected_push_result), 0) - << "Received data: " - << result2 - << "||||| Expected data: " - << expected_push_result; - - // Verify the SYN_REPLY. - // Copy the response info, because trans goes away. - response = *trans->GetResponseInfo(); - response2 = *trans2->GetResponseInfo(); - - VerifyStreamsClosed(helper); - - // Verify the SYN_REPLY. - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); - - // Verify the pushed stream. - EXPECT_TRUE(response2.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushWithTwoHeaderFrames) { - // We push a stream and attempt to claim it before the headers come down. - static const unsigned char kPushBodyFrame[] = { - 0x00, 0x00, 0x00, 0x02, // header, ID - 0x01, 0x00, 0x00, 0x06, // FIN, length - 'p', 'u', 's', 'h', 'e', 'd' // "pushed" - }; - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS), - }; - - static const char* const kInitialHeaders[] = { - "url", - "http://www.google.com/foo.dat", - }; - static const char* const kMiddleHeaders[] = { - "hello", - "bye", - }; - static const char* const kLateHeaders[] = { - "status", - "200", - "version", - "HTTP/1.1" - }; - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyControlFrame(kInitialHeaders, - arraysize(kInitialHeaders) / 2, - false, - 2, - LOWEST, - SYN_STREAM, - CONTROL_FLAG_NONE, - NULL, - 0, - 1)); - scoped_ptr<SpdyFrame> - stream2_headers1(ConstructSpdyControlFrame(kMiddleHeaders, - arraysize(kMiddleHeaders) / 2, - false, - 2, - LOWEST, - HEADERS, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - scoped_ptr<SpdyFrame> - stream2_headers2(ConstructSpdyControlFrame(kLateHeaders, - arraysize(kLateHeaders) / 2, - false, - 2, - LOWEST, - HEADERS, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - MockRead reads[] = { - CreateMockRead(*stream1_reply, 1), - CreateMockRead(*stream2_syn, 2), - CreateMockRead(*stream1_body, 3), - CreateMockRead(*stream2_headers1, 4), - CreateMockRead(*stream2_headers2, 5), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), - arraysize(kPushBodyFrame), 6), - MockRead(ASYNC, 0, 6), // EOF - }; - - HttpResponseInfo response; - HttpResponseInfo response2; - std::string expected_push_result("pushed"); - scoped_refptr<DeterministicSocketData> data(new DeterministicSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.SetDeterministic(); - helper.AddDeterministicData(static_cast<DeterministicSocketData*>(data)); - helper.RunPreTestSetup(); - - HttpNetworkTransaction* trans = helper.trans(); - - // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM, - // the first HEADERS frame, and the body of the primary stream, but before - // we've received the final HEADERS for the pushed stream. - data->SetStop(4); - - // Start the transaction. - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - data->Run(); - rv = callback.WaitForResult(); - EXPECT_EQ(0, rv); - - // Request the pushed path. At this point, we've received the push, but the - // headers are not yet complete. - scoped_ptr<HttpNetworkTransaction> trans2( - new HttpNetworkTransaction(helper.session())); - rv = trans2->Start( - &CreateGetPushRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - data->RunFor(3); - MessageLoop::current()->RunAllPending(); - - // Read the server push body. - std::string result2; - ReadResult(trans2.get(), data, &result2); - // Read the response body. - std::string result; - ReadResult(trans, data, &result); - - // Verify that we consumed all test data. - EXPECT_TRUE(data->at_read_eof()); - EXPECT_TRUE(data->at_write_eof()); - - // Verify that the received push data is same as the expected push data. - EXPECT_EQ(result2.compare(expected_push_result), 0) - << "Received data: " - << result2 - << "||||| Expected data: " - << expected_push_result; - - // Verify the SYN_REPLY. - // Copy the response info, because trans goes away. - response = *trans->GetResponseInfo(); - response2 = *trans2->GetResponseInfo(); - - VerifyStreamsClosed(helper); - - // Verify the SYN_REPLY. - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); - - // Verify the pushed stream. - EXPECT_TRUE(response2.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); - - // Verify we got all the headers - EXPECT_TRUE(response2.headers->HasHeaderValue( - "url", - "http://www.google.com/foo.dat")); - EXPECT_TRUE(response2.headers->HasHeaderValue("hello", "bye")); - EXPECT_TRUE(response2.headers->HasHeaderValue("status", "200")); - EXPECT_TRUE(response2.headers->HasHeaderValue("version", "HTTP/1.1")); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, SynReplyWithHeaders) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - static const char* const kInitialHeaders[] = { - "status", - "200 OK", - "version", - "HTTP/1.1" - }; - static const char* const kLateHeaders[] = { - "hello", - "bye", - }; - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyControlFrame(kInitialHeaders, - arraysize(kInitialHeaders) / 2, - false, - 1, - LOWEST, - SYN_REPLY, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - scoped_ptr<SpdyFrame> - stream1_headers(ConstructSpdyControlFrame(kLateHeaders, - arraysize(kLateHeaders) / 2, - false, - 1, - LOWEST, - HEADERS, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - scoped_ptr<SpdyFrame> stream1_body(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*stream1_reply), - CreateMockRead(*stream1_headers), - CreateMockRead(*stream1_body), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!", out.response_data); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, SynReplyWithLateHeaders) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - static const char* const kInitialHeaders[] = { - "status", - "200 OK", - "version", - "HTTP/1.1" - }; - static const char* const kLateHeaders[] = { - "hello", - "bye", - }; - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyControlFrame(kInitialHeaders, - arraysize(kInitialHeaders) / 2, - false, - 1, - LOWEST, - SYN_REPLY, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - scoped_ptr<SpdyFrame> - stream1_headers(ConstructSpdyControlFrame(kLateHeaders, - arraysize(kLateHeaders) / 2, - false, - 1, - LOWEST, - HEADERS, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - scoped_ptr<SpdyFrame> stream1_body(ConstructSpdyBodyFrame(1, false)); - scoped_ptr<SpdyFrame> stream1_body2(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*stream1_reply), - CreateMockRead(*stream1_body), - CreateMockRead(*stream1_headers), - CreateMockRead(*stream1_body2), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(OK, out.rv); - EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); - EXPECT_EQ("hello!hello!", out.response_data); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, SynReplyWithDuplicateLateHeaders) { - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - MockWrite writes[] = { CreateMockWrite(*req) }; - - static const char* const kInitialHeaders[] = { - "status", - "200 OK", - "version", - "HTTP/1.1" - }; - static const char* const kLateHeaders[] = { - "status", - "500 Server Error", - }; - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyControlFrame(kInitialHeaders, - arraysize(kInitialHeaders) / 2, - false, - 1, - LOWEST, - SYN_REPLY, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - scoped_ptr<SpdyFrame> - stream1_headers(ConstructSpdyControlFrame(kLateHeaders, - arraysize(kLateHeaders) / 2, - false, - 1, - LOWEST, - HEADERS, - CONTROL_FLAG_NONE, - NULL, - 0, - 0)); - scoped_ptr<SpdyFrame> stream1_body(ConstructSpdyBodyFrame(1, false)); - scoped_ptr<SpdyFrame> stream1_body2(ConstructSpdyBodyFrame(1, true)); - MockRead reads[] = { - CreateMockRead(*stream1_reply), - CreateMockRead(*stream1_body), - CreateMockRead(*stream1_headers), - CreateMockRead(*stream1_body2), - MockRead(ASYNC, 0, 0) // EOF - }; - - scoped_ptr<DelayedSocketData> data( - new DelayedSocketData(1, reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - helper.RunToCompletion(data.get()); - TransactionHelperResult out = helper.output(); - EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, ServerPushCrossOriginCorrectness) { - // In this test we want to verify that we can't accidentally push content - // which can't be pushed by this content server. - // This test assumes that: - // - if we're requesting http://www.foo.com/barbaz - // - the browser has made a connection to "www.foo.com". - - // A list of the URL to fetch, followed by the URL being pushed. - static const char* const kTestCases[] = { - "http://www.google.com/foo.html", - "http://www.google.com:81/foo.js", // Bad port - - "http://www.google.com/foo.html", - "https://www.google.com/foo.js", // Bad protocol - - "http://www.google.com/foo.html", - "ftp://www.google.com/foo.js", // Invalid Protocol - - "http://www.google.com/foo.html", - "http://blat.www.google.com/foo.js", // Cross subdomain - - "http://www.google.com/foo.html", - "http://www.foo.com/foo.js", // Cross domain - }; - - - static const unsigned char kPushBodyFrame[] = { - 0x00, 0x00, 0x00, 0x02, // header, ID - 0x01, 0x00, 0x00, 0x06, // FIN, length - 'p', 'u', 's', 'h', 'e', 'd' // "pushed" - }; - - for (size_t index = 0; index < arraysize(kTestCases); index += 2) { - const char* url_to_fetch = kTestCases[index]; - const char* url_to_push = kTestCases[index + 1]; - - scoped_ptr<SpdyFrame> - stream1_syn(ConstructSpdyGet(url_to_fetch, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> - stream1_body(ConstructSpdyBodyFrame(1, true)); - scoped_ptr<SpdyFrame> push_rst( - ConstructSpdyRstStream(2, REFUSED_STREAM)); - MockWrite writes[] = { - CreateMockWrite(*stream1_syn, 1), - CreateMockWrite(*push_rst, 4), - }; - - scoped_ptr<SpdyFrame> - stream1_reply(ConstructSpdyGetSynReply(NULL, 0, 1)); - scoped_ptr<SpdyFrame> - stream2_syn(ConstructSpdyPush(NULL, - 0, - 2, - 1, - url_to_push)); - scoped_ptr<SpdyFrame> rst( - ConstructSpdyRstStream(2, CANCEL)); - - MockRead reads[] = { - CreateMockRead(*stream1_reply, 2), - CreateMockRead(*stream2_syn, 3), - CreateMockRead(*stream1_body, 5, SYNCHRONOUS), - MockRead(ASYNC, reinterpret_cast<const char*>(kPushBodyFrame), - arraysize(kPushBodyFrame), 6), - MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause - }; - - HttpResponseInfo response; - scoped_ptr<OrderedSocketData> data(new OrderedSocketData( - reads, - arraysize(reads), - writes, - arraysize(writes))); - - HttpRequestInfo request; - request.method = "GET"; - request.url = GURL(url_to_fetch); - request.load_flags = 0; - NormalSpdyTransactionHelper helper(request, - BoundNetLog(), GetParam()); - helper.RunPreTestSetup(); - helper.AddData(data.get()); - - // Enable cross-origin push. Since we are not using a proxy, this should - // not actually enable cross-origin SPDY push. - net::SpdySession::set_allow_spdy_proxy_push_across_origins( - "123.45.67.89:8080"); - - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - - int rv = trans->Start(&request, callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - - // Read the response body. - std::string result; - ReadResult(trans, data.get(), &result); - - // Verify that we consumed all test data. - EXPECT_TRUE(data->at_read_eof()); - EXPECT_TRUE(data->at_write_eof()); - - // Verify the SYN_REPLY. - // Copy the response info, because trans goes away. - response = *trans->GetResponseInfo(); - - VerifyStreamsClosed(helper); - - // Verify the SYN_REPLY. - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); - } -} - -TEST_P(SpdyNetworkTransactionSpdy21Test, RetryAfterRefused) { - // Construct the request. - scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); - scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); - MockWrite writes[] = { - CreateMockWrite(*req, 1), - CreateMockWrite(*req2, 3), - }; - - scoped_ptr<SpdyFrame> refused( - ConstructSpdyRstStream(1, REFUSED_STREAM)); - scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 3)); - scoped_ptr<SpdyFrame> body(ConstructSpdyBodyFrame(3, true)); - MockRead reads[] = { - CreateMockRead(*refused, 2), - CreateMockRead(*resp, 4), - CreateMockRead(*body, 5), - MockRead(ASYNC, 0, 6) // EOF - }; - - scoped_ptr<OrderedSocketData> data( - new OrderedSocketData(reads, arraysize(reads), - writes, arraysize(writes))); - NormalSpdyTransactionHelper helper(CreateGetRequest(), - BoundNetLog(), GetParam()); - - helper.RunPreTestSetup(); - helper.AddData(data.get()); - - HttpNetworkTransaction* trans = helper.trans(); - - // Start the transaction with basic parameters. - TestCompletionCallback callback; - int rv = trans->Start( - &CreateGetRequest(), callback.callback(), BoundNetLog()); - EXPECT_EQ(ERR_IO_PENDING, rv); - rv = callback.WaitForResult(); - EXPECT_EQ(OK, rv); - - // Verify that we consumed all test data. - EXPECT_TRUE(data->at_read_eof()) << "Read count: " - << data->read_count() - << " Read index: " - << data->read_index(); - EXPECT_TRUE(data->at_write_eof()) << "Write count: " - << data->write_count() - << " Write index: " - << data->write_index(); - - // Verify the SYN_REPLY. - HttpResponseInfo response = *trans->GetResponseInfo(); - EXPECT_TRUE(response.headers != NULL); - EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); -} - -} // namespace net diff --git a/net/spdy/spdy_network_transaction_spdy2_unittest.cc b/net/spdy/spdy_network_transaction_spdy2_unittest.cc index 5e6cf17..85b875e 100644 --- a/net/spdy/spdy_network_transaction_spdy2_unittest.cc +++ b/net/spdy/spdy_network_transaction_spdy2_unittest.cc @@ -119,7 +119,6 @@ class SpdyNetworkTransactionSpdy2Test std::vector<std::string> next_protos; next_protos.push_back("http/1.1"); next_protos.push_back("spdy/2"); - next_protos.push_back("spdy/2.1"); switch (test_type_) { case SPDYNPN: diff --git a/net/spdy/spdy_network_transaction_spdy3_unittest.cc b/net/spdy/spdy_network_transaction_spdy3_unittest.cc index e92ba87..92fab4c 100644 --- a/net/spdy/spdy_network_transaction_spdy3_unittest.cc +++ b/net/spdy/spdy_network_transaction_spdy3_unittest.cc @@ -119,7 +119,6 @@ class SpdyNetworkTransactionSpdy3Test std::vector<std::string> next_protos; next_protos.push_back("http/1.1"); next_protos.push_back("spdy/2"); - next_protos.push_back("spdy/2.1"); next_protos.push_back("spdy/3"); switch (test_type_) { diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index 9da8136..f6b360dc 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc @@ -451,7 +451,7 @@ net::Error SpdySession::InitializeWithSocket( DCHECK(protocol >= kProtoSPDY2); DCHECK(protocol <= kProtoSPDY3); int version = (protocol == kProtoSPDY3) ? 3 : 2; - flow_control_ = (protocol >= kProtoSPDY21); + flow_control_ = (protocol >= kProtoSPDY3); buffered_spdy_framer_.reset(new BufferedSpdyFramer(version)); buffered_spdy_framer_->set_visitor(this); diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h index 39f9fe2..27d1785 100644 --- a/net/spdy/spdy_session_pool.h +++ b/net/spdy/spdy_session_pool.h @@ -146,12 +146,9 @@ class NET_EXPORT SpdySessionPool friend class test_spdy2::SpdySessionPoolPeer; // For testing. friend class test_spdy3::SpdySessionPoolPeer; // For testing. friend class SpdyNetworkTransactionSpdy2Test; // For testing. - friend class SpdyNetworkTransactionSpdy21Test; // For testing. friend class SpdyNetworkTransactionSpdy3Test; // For testing. FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy2Test, WindowUpdateOverflow); - FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy21Test, - WindowUpdateOverflow); FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionSpdy3Test, WindowUpdateOverflow); |