Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / net / http / http_network_transaction_unittest.cc
index 7846028..f56b6e2 100644 (file)
@@ -16,6 +16,7 @@
 #include "base/json/json_writer.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/test_file_util.h"
@@ -35,6 +36,7 @@
 #include "net/cert/mock_cert_verifier.h"
 #include "net/dns/host_cache.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/http/http_auth_challenge_tokenizer.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"
@@ -44,7 +46,7 @@
 #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/http/http_transaction_test_util.h"
 #include "net/proxy/proxy_config_service_fixed.h"
 #include "net/proxy/proxy_info.h"
 #include "net/proxy/proxy_resolver.h"
 #include "net/ssl/ssl_config_service_defaults.h"
 #include "net/ssl/ssl_info.h"
 #include "net/test/cert_test_util.h"
+#include "net/websockets/websocket_handshake_stream_base.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #include "url/gurl.h"
 
+using base::ASCIIToUTF16;
+
 //-----------------------------------------------------------------------------
 
 namespace {
@@ -111,7 +116,7 @@ bool GetHeaders(base::DictionaryValue* params, std::string* headers) {
     return false;
   std::string double_quote_headers;
   base::JSONWriter::Write(header_list, &double_quote_headers);
-  ReplaceChars(double_quote_headers, "\"", "'", headers);
+  base::ReplaceChars(double_quote_headers, "\"", "'", headers);
   return true;
 }
 
@@ -243,6 +248,7 @@ class HttpNetworkTransactionTest
     int rv;
     std::string status_line;
     std::string response_data;
+    int64 totalReceivedBytes;
     LoadTimingInfo load_timing_info;
   };
 
@@ -259,8 +265,6 @@ class HttpNetworkTransactionTest
     PlatformTest::TearDown();
     NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
     base::MessageLoop::current()->RunUntilIdle();
-    HttpStreamFactory::set_use_alternate_protocols(false);
-    HttpStreamFactory::SetNextProtos(std::vector<NextProto>());
   }
 
   // This is the expected return from a current server advertising SPDY.
@@ -278,6 +282,14 @@ class HttpNetworkTransactionTest
   void KeepAliveConnectionResendRequestTest(const MockWrite* write_failure,
                                             const MockRead* read_failure);
 
+  // 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 PreconnectErrorResendRequestTest(const MockWrite* write_failure,
+                                        const MockRead* read_failure,
+                                        bool use_spdy);
+
   SimpleGetHelperResult SimpleGetHelperForData(StaticSocketDataProvider* data[],
                                                size_t data_count) {
     SimpleGetHelperResult out;
@@ -299,7 +311,7 @@ class HttpNetworkTransactionTest
 
     TestCompletionCallback callback;
 
-    EXPECT_TRUE(log.bound().IsLoggingAllEvents());
+    EXPECT_TRUE(log.bound().IsLogging());
     int rv = trans->Start(&request, callback.callback(), log.bound());
     EXPECT_EQ(ERR_IO_PENDING, rv);
 
@@ -355,6 +367,7 @@ class HttpNetworkTransactionTest
     EXPECT_EQ("['Host: www.google.com','Connection: keep-alive']",
               response_headers);
 
+    out.totalReceivedBytes = trans->GetTotalReceivedBytes();
     return out;
   }
 
@@ -365,6 +378,13 @@ class HttpNetworkTransactionTest
     return SimpleGetHelperForData(data, 1);
   }
 
+  int64 ReadsSize(MockRead data_reads[], size_t reads_count) {
+    int64 size = 0;
+    for (size_t i = 0; i < reads_count; ++i)
+      size += data_reads[i].data_len;
+    return size;
+  }
+
   void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
                                              int expected_status);
 
@@ -387,11 +407,58 @@ INSTANTIATE_TEST_CASE_P(
     NextProto,
     HttpNetworkTransactionTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
-                    kProtoHTTP2Draft04));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
 
 namespace {
 
+class BeforeNetworkStartHandler {
+ public:
+  explicit BeforeNetworkStartHandler(bool defer)
+      : defer_on_before_network_start_(defer),
+        observed_before_network_start_(false) {}
+
+  void OnBeforeNetworkStart(bool* defer) {
+    *defer = defer_on_before_network_start_;
+    observed_before_network_start_ = true;
+  }
+
+  bool observed_before_network_start() const {
+    return observed_before_network_start_;
+  }
+
+ private:
+  const bool defer_on_before_network_start_;
+  bool observed_before_network_start_;
+
+  DISALLOW_COPY_AND_ASSIGN(BeforeNetworkStartHandler);
+};
+
+class BeforeProxyHeadersSentHandler {
+ public:
+  BeforeProxyHeadersSentHandler()
+      : observed_before_proxy_headers_sent_(false) {}
+
+  void OnBeforeProxyHeadersSent(const ProxyInfo& proxy_info,
+                                HttpRequestHeaders* request_headers) {
+    observed_before_proxy_headers_sent_ = true;
+    observed_proxy_server_uri_ = proxy_info.proxy_server().ToURI();
+  }
+
+  bool observed_before_proxy_headers_sent() const {
+    return observed_before_proxy_headers_sent_;
+  }
+
+  std::string observed_proxy_server_uri() const {
+    return observed_proxy_server_uri_;
+  }
+
+ private:
+  bool observed_before_proxy_headers_sent_;
+  std::string observed_proxy_server_uri_;
+
+  DISALLOW_COPY_AND_ASSIGN(BeforeProxyHeadersSentHandler);
+};
+
 // Fill |str| with a long header list that consumes >= |size| bytes.
 void FillLargeHeadersString(std::string* str, int size) {
   const char* row =
@@ -511,13 +578,16 @@ CaptureGroupNameSSLSocketPool::CaptureGroupNameSocketPool(
                           cert_verifier,
                           NULL,
                           NULL,
+                          NULL,
                           std::string(),
                           NULL,
                           NULL,
                           NULL,
                           NULL,
                           NULL,
-                          NULL) {}
+                          false,
+                          NULL) {
+}
 
 //-----------------------------------------------------------------------------
 
@@ -582,6 +652,8 @@ TEST_P(HttpNetworkTransactionTest, SimpleGET) {
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
   EXPECT_EQ("hello world", out.response_data);
+  int64 reads_size = ReadsSize(data_reads, arraysize(data_reads));
+  EXPECT_EQ(reads_size, out.totalReceivedBytes);
 }
 
 // Response with no status line.
@@ -595,6 +667,8 @@ TEST_P(HttpNetworkTransactionTest, SimpleGETNoHeaders) {
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
   EXPECT_EQ("hello world", out.response_data);
+  int64 reads_size = ReadsSize(data_reads, arraysize(data_reads));
+  EXPECT_EQ(reads_size, out.totalReceivedBytes);
 }
 
 // Allow up to 4 bytes of junk to precede status line.
@@ -608,6 +682,8 @@ TEST_P(HttpNetworkTransactionTest, StatusLineJunk3Bytes) {
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
   EXPECT_EQ("DATA", out.response_data);
+  int64 reads_size = ReadsSize(data_reads, arraysize(data_reads));
+  EXPECT_EQ(reads_size, out.totalReceivedBytes);
 }
 
 // Allow up to 4 bytes of junk to precede status line.
@@ -621,6 +697,8 @@ TEST_P(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
   EXPECT_EQ("DATA", out.response_data);
+  int64 reads_size = ReadsSize(data_reads, arraysize(data_reads));
+  EXPECT_EQ(reads_size, out.totalReceivedBytes);
 }
 
 // Beyond 4 bytes of slop and it should fail to find a status line.
@@ -634,6 +712,8 @@ TEST_P(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
   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);
+  int64 reads_size = ReadsSize(data_reads, arraysize(data_reads));
+  EXPECT_EQ(reads_size, out.totalReceivedBytes);
 }
 
 // Same as StatusLineJunk4Bytes, except the read chunks are smaller.
@@ -651,6 +731,8 @@ TEST_P(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
   EXPECT_EQ("DATA", out.response_data);
+  int64 reads_size = ReadsSize(data_reads, arraysize(data_reads));
+  EXPECT_EQ(reads_size, out.totalReceivedBytes);
 }
 
 // Close the connection before enough bytes to have a status line.
@@ -664,15 +746,18 @@ TEST_P(HttpNetworkTransactionTest, StatusLinePartial) {
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
   EXPECT_EQ("HTT", out.response_data);
+  int64 reads_size = ReadsSize(data_reads, arraysize(data_reads));
+  EXPECT_EQ(reads_size, out.totalReceivedBytes);
 }
 
 // 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_P(HttpNetworkTransactionTest, StopsReading204) {
+  char junk[] = "junk";
   MockRead data_reads[] = {
     MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
-    MockRead("junk"),  // Should not be read!!
+    MockRead(junk),  // Should not be read!!
     MockRead(SYNCHRONOUS, OK),
   };
   SimpleGetHelperResult out = SimpleGetHelper(data_reads,
@@ -680,18 +765,23 @@ TEST_P(HttpNetworkTransactionTest, StopsReading204) {
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line);
   EXPECT_EQ("", out.response_data);
+  int64 reads_size = ReadsSize(data_reads, arraysize(data_reads));
+  int64 response_size = reads_size - strlen(junk);
+  EXPECT_EQ(response_size, out.totalReceivedBytes);
 }
 
 // A simple request using chunked encoding with some extra data after.
-// (Like might be seen in a pipelined response.)
 TEST_P(HttpNetworkTransactionTest, ChunkedEncoding) {
+  std::string final_chunk = "0\r\n\r\n";
+  std::string extra_data = "HTTP/1.1 200 OK\r\n";
+  std::string last_read = final_chunk + extra_data;
   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(last_read.data()),
     MockRead(SYNCHRONOUS, OK),
   };
   SimpleGetHelperResult out = SimpleGetHelper(data_reads,
@@ -699,6 +789,9 @@ TEST_P(HttpNetworkTransactionTest, ChunkedEncoding) {
   EXPECT_EQ(OK, out.rv);
   EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
   EXPECT_EQ("Hello world", out.response_data);
+  int64 reads_size = ReadsSize(data_reads, arraysize(data_reads));
+  int64 response_size = reads_size - extra_data.size();
+  EXPECT_EQ(response_size, out.totalReceivedBytes);
 }
 
 // Next tests deal with http://crbug.com/56344.
@@ -881,6 +974,7 @@ TEST_P(HttpNetworkTransactionTest, TwoIdenticalLocationHeaders) {
   std::string url;
   EXPECT_TRUE(response->headers->IsRedirect(&url));
   EXPECT_EQ("http://good.com/", url);
+  EXPECT_TRUE(response->proxy_server.IsEmpty());
 }
 
 // Checks that two distinct Location headers result in an error.
@@ -908,6 +1002,10 @@ TEST_P(HttpNetworkTransactionTest, Head) {
   scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+  BeforeProxyHeadersSentHandler proxy_headers_handler;
+  trans->SetBeforeProxyHeadersSentCallback(
+      base::Bind(&BeforeProxyHeadersSentHandler::OnBeforeProxyHeadersSent,
+                 base::Unretained(&proxy_headers_handler)));
 
   MockWrite data_writes1[] = {
     MockWrite("HEAD / HTTP/1.1\r\n"
@@ -943,6 +1041,8 @@ TEST_P(HttpNetworkTransactionTest, Head) {
   EXPECT_TRUE(response->headers.get() != NULL);
   EXPECT_EQ(1234, response->headers->GetContentLength());
   EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine());
+  EXPECT_TRUE(response->proxy_server.IsEmpty());
+  EXPECT_FALSE(proxy_headers_handler.observed_before_proxy_headers_sent());
 
   std::string server_header;
   void* iter = NULL;
@@ -998,6 +1098,7 @@ TEST_P(HttpNetworkTransactionTest, ReuseConnection) {
 
     EXPECT_TRUE(response->headers.get() != NULL);
     EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+    EXPECT_TRUE(response->proxy_server.IsEmpty());
 
     std::string response_data;
     rv = ReadTransaction(trans.get(), &response_data);
@@ -1179,7 +1280,7 @@ void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
   };
 
   if (write_failure) {
-    ASSERT_TRUE(!read_failure);
+    ASSERT_FALSE(read_failure);
     data1_writes[1] = *write_failure;
   } else {
     ASSERT_TRUE(read_failure);
@@ -1238,6 +1339,126 @@ void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
   }
 }
 
+void HttpNetworkTransactionTest::PreconnectErrorResendRequestTest(
+    const MockWrite* write_failure,
+    const MockRead* read_failure,
+    bool use_spdy) {
+  HttpRequestInfo request;
+  request.method = "GET";
+  request.url = GURL("https://www.foo.com/");
+  request.load_flags = 0;
+
+  CapturingNetLog net_log;
+  session_deps_.net_log = &net_log;
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+  SSLSocketDataProvider ssl1(ASYNC, OK);
+  SSLSocketDataProvider ssl2(ASYNC, OK);
+  if (use_spdy) {
+    ssl1.SetNextProto(GetParam());
+    ssl2.SetNextProto(GetParam());
+  }
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
+
+  // SPDY versions of the request and response.
+  scoped_ptr<SpdyFrame> spdy_request(spdy_util_.ConstructSpdyGet(
+      request.url.spec().c_str(), false, 1, DEFAULT_PRIORITY));
+  scoped_ptr<SpdyFrame> spdy_response(
+      spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> spdy_data(
+      spdy_util_.ConstructSpdyBodyFrame(1, "hello", 5, true));
+
+  // HTTP/1.1 versions of the request and response.
+  const char kHttpRequest[] = "GET / HTTP/1.1\r\n"
+      "Host: www.foo.com\r\n"
+      "Connection: keep-alive\r\n\r\n";
+  const char kHttpResponse[] = "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n";
+  const char kHttpData[] = "hello";
+
+  std::vector<MockRead> data1_reads;
+  std::vector<MockWrite> data1_writes;
+  if (write_failure) {
+    ASSERT_FALSE(read_failure);
+    data1_writes.push_back(*write_failure);
+    data1_reads.push_back(MockRead(ASYNC, OK));
+  } else {
+    ASSERT_TRUE(read_failure);
+    if (use_spdy) {
+      data1_writes.push_back(CreateMockWrite(*spdy_request));
+    } else {
+      data1_writes.push_back(MockWrite(kHttpRequest));
+    }
+    data1_reads.push_back(*read_failure);
+  }
+
+  StaticSocketDataProvider data1(&data1_reads[0], data1_reads.size(),
+                                 &data1_writes[0], data1_writes.size());
+  session_deps_.socket_factory->AddSocketDataProvider(&data1);
+
+  std::vector<MockRead> data2_reads;
+  std::vector<MockWrite> data2_writes;
+
+  if (use_spdy) {
+    data2_writes.push_back(CreateMockWrite(*spdy_request, 0, ASYNC));
+
+    data2_reads.push_back(CreateMockRead(*spdy_response, 1, ASYNC));
+    data2_reads.push_back(CreateMockRead(*spdy_data, 2, ASYNC));
+    data2_reads.push_back(MockRead(ASYNC, OK, 3));
+  } else {
+    data2_writes.push_back(
+        MockWrite(ASYNC, kHttpRequest, strlen(kHttpRequest), 0));
+
+    data2_reads.push_back(
+        MockRead(ASYNC, kHttpResponse, strlen(kHttpResponse), 1));
+    data2_reads.push_back(MockRead(ASYNC, kHttpData, strlen(kHttpData), 2));
+    data2_reads.push_back(MockRead(ASYNC, OK, 3));
+  }
+  OrderedSocketData data2(&data2_reads[0], data2_reads.size(),
+                          &data2_writes[0], data2_writes.size());
+  session_deps_.socket_factory->AddSocketDataProvider(&data2);
+
+  // Preconnect a socket.
+  net::SSLConfig ssl_config;
+  session->ssl_config_service()->GetSSLConfig(&ssl_config);
+  session->GetNextProtos(&ssl_config.next_protos);
+  session->http_stream_factory()->PreconnectStreams(
+      1, request, DEFAULT_PRIORITY, ssl_config, ssl_config);
+  // Wait for the preconnect to complete.
+  // TODO(davidben): Some way to wait for an idle socket count might be handy.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, GetIdleSocketCountInSSLSocketPool(session.get()));
+
+  // Make the request.
+  TestCompletionCallback callback;
+
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+
+  int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+  EXPECT_EQ(ERR_IO_PENDING, rv);
+
+  rv = callback.WaitForResult();
+  EXPECT_EQ(OK, rv);
+
+  LoadTimingInfo load_timing_info;
+  EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
+  TestLoadTimingNotReused(
+      load_timing_info,
+      CONNECT_TIMING_HAS_DNS_TIMES|CONNECT_TIMING_HAS_SSL_TIMES);
+
+  const HttpResponseInfo* response = trans->GetResponseInfo();
+  ASSERT_TRUE(response != NULL);
+
+  EXPECT_TRUE(response->headers.get() != 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(kHttpData, response_data);
+}
+
 TEST_P(HttpNetworkTransactionTest,
        KeepAliveConnectionNotConnectedOnWrite) {
   MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED);
@@ -1254,6 +1475,71 @@ TEST_P(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
   KeepAliveConnectionResendRequestTest(NULL, &read_failure);
 }
 
+// Make sure that on a 408 response (Request Timeout), the request is retried,
+// if the socket was a reused keep alive socket.
+TEST_P(HttpNetworkTransactionTest, KeepAlive408) {
+  MockRead read_failure(SYNCHRONOUS,
+                        "HTTP/1.1 408 Request Timeout\r\n"
+                        "Connection: Keep-Alive\r\n"
+                        "Content-Length: 6\r\n\r\n"
+                        "Pickle");
+  KeepAliveConnectionResendRequestTest(NULL, &read_failure);
+}
+
+TEST_P(HttpNetworkTransactionTest,
+       PreconnectErrorNotConnectedOnWrite) {
+  MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED);
+  PreconnectErrorResendRequestTest(&write_failure, NULL, false);
+}
+
+TEST_P(HttpNetworkTransactionTest, PreconnectErrorReset) {
+  MockRead read_failure(ASYNC, ERR_CONNECTION_RESET);
+  PreconnectErrorResendRequestTest(NULL, &read_failure, false);
+}
+
+TEST_P(HttpNetworkTransactionTest, PreconnectErrorEOF) {
+  MockRead read_failure(SYNCHRONOUS, OK);  // EOF
+  PreconnectErrorResendRequestTest(NULL, &read_failure, false);
+}
+
+TEST_P(HttpNetworkTransactionTest, PreconnectErrorAsyncEOF) {
+  MockRead read_failure(ASYNC, OK);  // EOF
+  PreconnectErrorResendRequestTest(NULL, &read_failure, false);
+}
+
+// Make sure that on a 408 response (Request Timeout), the request is retried,
+// if the socket was a preconnected (UNUSED_IDLE) socket.
+TEST_P(HttpNetworkTransactionTest, RetryOnIdle408) {
+  MockRead read_failure(SYNCHRONOUS,
+                        "HTTP/1.1 408 Request Timeout\r\n"
+                        "Connection: Keep-Alive\r\n"
+                        "Content-Length: 6\r\n\r\n"
+                        "Pickle");
+  KeepAliveConnectionResendRequestTest(NULL, &read_failure);
+  PreconnectErrorResendRequestTest(NULL, &read_failure, false);
+}
+
+TEST_P(HttpNetworkTransactionTest,
+       SpdyPreconnectErrorNotConnectedOnWrite) {
+  MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED);
+  PreconnectErrorResendRequestTest(&write_failure, NULL, true);
+}
+
+TEST_P(HttpNetworkTransactionTest, SpdyPreconnectErrorReset) {
+  MockRead read_failure(ASYNC, ERR_CONNECTION_RESET);
+  PreconnectErrorResendRequestTest(NULL, &read_failure, true);
+}
+
+TEST_P(HttpNetworkTransactionTest, SpdyPreconnectErrorEOF) {
+  MockRead read_failure(SYNCHRONOUS, OK);  // EOF
+  PreconnectErrorResendRequestTest(NULL, &read_failure, true);
+}
+
+TEST_P(HttpNetworkTransactionTest, SpdyPreconnectErrorAsyncEOF) {
+  MockRead read_failure(ASYNC, OK);  // EOF
+  PreconnectErrorResendRequestTest(NULL, &read_failure, true);
+}
+
 TEST_P(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
   HttpRequestInfo request;
   request.method = "GET";
@@ -1306,6 +1592,85 @@ TEST_P(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
   EXPECT_EQ(ERR_EMPTY_RESPONSE, out.rv);
 }
 
+// Test that network access can be deferred and resumed.
+TEST_P(HttpNetworkTransactionTest, ThrottleBeforeNetworkStart) {
+  HttpRequestInfo request;
+  request.method = "GET";
+  request.url = GURL("http://www.google.com/");
+  request.load_flags = 0;
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+
+  // Defer on OnBeforeNetworkStart.
+  BeforeNetworkStartHandler net_start_handler(true);  // defer
+  trans->SetBeforeNetworkStartCallback(
+      base::Bind(&BeforeNetworkStartHandler::OnBeforeNetworkStart,
+                 base::Unretained(&net_start_handler)));
+
+  MockRead data_reads[] = {
+    MockRead("HTTP/1.0 200 OK\r\n"),
+    MockRead("Content-Length: 5\r\n\r\n"),
+    MockRead("hello"),
+    MockRead(SYNCHRONOUS, 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);
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Should have deferred for network start.
+  EXPECT_TRUE(net_start_handler.observed_before_network_start());
+  EXPECT_EQ(LOAD_STATE_WAITING_FOR_DELEGATE, trans->GetLoadState());
+  EXPECT_TRUE(trans->GetResponseInfo() == NULL);
+
+  trans->ResumeNetworkStart();
+  rv = callback.WaitForResult();
+  EXPECT_EQ(OK, rv);
+  EXPECT_TRUE(trans->GetResponseInfo() != NULL);
+
+  scoped_refptr<IOBufferWithSize> io_buf(new IOBufferWithSize(100));
+  rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback());
+  if (rv == ERR_IO_PENDING)
+    rv = callback.WaitForResult();
+  EXPECT_EQ(5, rv);
+  trans.reset();
+}
+
+// Test that network use can be deferred and canceled.
+TEST_P(HttpNetworkTransactionTest, ThrottleAndCancelBeforeNetworkStart) {
+  HttpRequestInfo request;
+  request.method = "GET";
+  request.url = GURL("http://www.google.com/");
+  request.load_flags = 0;
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+
+  // Defer on OnBeforeNetworkStart.
+  BeforeNetworkStartHandler net_start_handler(true);  // defer
+  trans->SetBeforeNetworkStartCallback(
+      base::Bind(&BeforeNetworkStartHandler::OnBeforeNetworkStart,
+                 base::Unretained(&net_start_handler)));
+
+  TestCompletionCallback callback;
+
+  int rv = trans->Start(&request, callback.callback(), BoundNetLog());
+  EXPECT_EQ(ERR_IO_PENDING, rv);
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Should have deferred for network start.
+  EXPECT_TRUE(net_start_handler.observed_before_network_start());
+  EXPECT_EQ(LOAD_STATE_WAITING_FOR_DELEGATE, trans->GetLoadState());
+  EXPECT_TRUE(trans->GetResponseInfo() == NULL);
+}
+
 // Next 2 cases (KeepAliveEarlyClose and KeepAliveEarlyClose2) are regression
 // tests. There was a bug causing HttpNetworkTransaction to hang in the
 // destructor in such situations.
@@ -1567,6 +1932,9 @@ TEST_P(HttpNetworkTransactionTest, BasicAuth) {
   EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info1));
   TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_DNS_TIMES);
 
+  int64 reads_size1 = ReadsSize(data_reads1, arraysize(data_reads1));
+  EXPECT_EQ(reads_size1, trans->GetTotalReceivedBytes());
+
   const HttpResponseInfo* response = trans->GetResponseInfo();
   ASSERT_TRUE(response != NULL);
   EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge.get()));
@@ -1589,6 +1957,9 @@ TEST_P(HttpNetworkTransactionTest, BasicAuth) {
             load_timing_info2.connect_timing.connect_start);
   EXPECT_NE(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
 
+  int64 reads_size2 = ReadsSize(data_reads2, arraysize(data_reads2));
+  EXPECT_EQ(reads_size1 + reads_size2, trans->GetTotalReceivedBytes());
+
   response = trans->GetResponseInfo();
   ASSERT_TRUE(response != NULL);
   EXPECT_TRUE(response->auth_challenge.get() == NULL);
@@ -1631,6 +2002,9 @@ TEST_P(HttpNetworkTransactionTest, DoNotSendAuth) {
   rv = callback.WaitForResult();
   EXPECT_EQ(0, rv);
 
+  int64 reads_size = ReadsSize(data_reads, arraysize(data_reads));
+  EXPECT_EQ(reads_size, trans->GetTotalReceivedBytes());
+
   const HttpResponseInfo* response = trans->GetResponseInfo();
   ASSERT_TRUE(response != NULL);
   EXPECT_TRUE(response->auth_challenge.get() == NULL);
@@ -1728,6 +2102,12 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
   ASSERT_TRUE(response != NULL);
   EXPECT_TRUE(response->auth_challenge.get() == NULL);
   EXPECT_EQ(5, response->headers->GetContentLength());
+
+  std::string response_data;
+  rv = ReadTransaction(trans.get(), &response_data);
+  EXPECT_EQ(OK, rv);
+  int64 reads_size1 = ReadsSize(data_reads1, arraysize(data_reads1));
+  EXPECT_EQ(reads_size1, trans->GetTotalReceivedBytes());
 }
 
 // Test the request-challenge-retry sequence for basic auth, over a keep-alive
@@ -2681,6 +3061,82 @@ TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGet) {
   EXPECT_EQ(kUploadData, response_data);
 }
 
+// Verifies that a session which races and wins against the owning transaction
+// (completing prior to host resolution), doesn't fail the transaction.
+// Regression test for crbug.com/334413.
+TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithSessionRace) {
+  HttpRequestInfo request;
+  request.method = "GET";
+  request.url = GURL("http://www.google.com/");
+  request.load_flags = 0;
+
+  // Configure SPDY proxy server "proxy:70".
+  session_deps_.proxy_service.reset(
+      ProxyService::CreateFixed("https://proxy:70"));
+  CapturingBoundNetLog log;
+  session_deps_.net_log = log.bound().net_log();
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+  // Fetch http://www.google.com/ through the SPDY proxy.
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false));
+  MockWrite spdy_writes[] = {CreateMockWrite(*req)};
+
+  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> data(spdy_util_.ConstructSpdyBodyFrame(1, true));
+  MockRead spdy_reads[] = {
+      CreateMockRead(*resp), CreateMockRead(*data), MockRead(ASYNC, 0, 0),
+  };
+
+  DelayedSocketData spdy_data(
+      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);
+
+  SSLSocketDataProvider ssl(ASYNC, OK);
+  ssl.SetNextProto(GetParam());
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
+
+  TestCompletionCallback callback1;
+
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+
+  // Stall the hostname resolution begun by the transaction.
+  session_deps_.host_resolver->set_synchronous_mode(false);
+  session_deps_.host_resolver->set_ondemand_mode(true);
+
+  int rv = trans->Start(&request, callback1.callback(), log.bound());
+  EXPECT_EQ(ERR_IO_PENDING, rv);
+
+  // Race a session to the proxy, which completes first.
+  session_deps_.host_resolver->set_ondemand_mode(false);
+  SpdySessionKey key(
+      HostPortPair("proxy", 70), ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
+  base::WeakPtr<SpdySession> spdy_session =
+      CreateSecureSpdySession(session, key, log.bound());
+
+  // Unstall the resolution begun by the transaction.
+  session_deps_.host_resolver->set_ondemand_mode(true);
+  session_deps_.host_resolver->ResolveAllPending();
+
+  EXPECT_FALSE(callback1.have_result());
+  rv = callback1.WaitForResult();
+  EXPECT_EQ(OK, rv);
+
+  const HttpResponseInfo* response = trans->GetResponseInfo();
+  ASSERT_TRUE(response != NULL);
+  ASSERT_TRUE(response->headers.get() != 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_P(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
   HttpRequestInfo request;
@@ -3062,23 +3518,14 @@ TEST_P(HttpNetworkTransactionTest,
       spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp1->size()));
 
   // CONNECT to news.google.com:443 via SPDY.
-  const char* const kConnectHeaders2[] = {
-    spdy_util_.GetMethodKey(), "CONNECT",
-    spdy_util_.GetPathKey(), "news.google.com:443",
-    spdy_util_.GetHostKey(), "news.google.com",
-    spdy_util_.GetVersionKey(), "HTTP/1.1",
-  };
+  SpdyHeaderBlock connect2_block;
+  connect2_block[spdy_util_.GetMethodKey()] = "CONNECT";
+  connect2_block[spdy_util_.GetPathKey()] = "news.google.com:443";
+  connect2_block[spdy_util_.GetHostKey()] = "news.google.com";
+  spdy_util_.MaybeAddVersionHeader(&connect2_block);
   scoped_ptr<SpdyFrame> connect2(
-      spdy_util_.ConstructSpdyControlFrame(NULL,
-                                           0,
-                                           /*compressed*/ false,
-                                           3,
-                                           LOWEST,
-                                           SYN_STREAM,
-                                           CONTROL_FLAG_NONE,
-                                           kConnectHeaders2,
-                                           arraysize(kConnectHeaders2),
-                                           0));
+      spdy_util_.ConstructSpdySyn(3, connect2_block, LOWEST, false, false));
+
   scoped_ptr<SpdyFrame> conn_resp2(
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
 
@@ -3333,8 +3780,8 @@ TEST_P(HttpNetworkTransactionTest,
   // http://www.google.com/
   scoped_ptr<SpdyHeaderBlock> headers(
       spdy_util_.ConstructGetHeaderBlockForProxy("http://www.google.com/"));
-  scoped_ptr<SpdyFrame> get1(spdy_util_.ConstructSpdyControlFrame(
-      headers.Pass(), false, 1, LOWEST, SYN_STREAM, CONTROL_FLAG_FIN, 0));
+  scoped_ptr<SpdyFrame> get1(
+      spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true));
   scoped_ptr<SpdyFrame> get_resp1(
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body1(
@@ -3343,8 +3790,8 @@ TEST_P(HttpNetworkTransactionTest,
   // http://news.google.com/
   scoped_ptr<SpdyHeaderBlock> headers2(
       spdy_util_.ConstructGetHeaderBlockForProxy("http://news.google.com/"));
-  scoped_ptr<SpdyFrame> get2(spdy_util_.ConstructSpdyControlFrame(
-      headers2.Pass(), false, 3, LOWEST, SYN_STREAM, CONTROL_FLAG_FIN, 0));
+  scoped_ptr<SpdyFrame> get2(
+      spdy_util_.ConstructSpdySyn(3, *headers2, LOWEST, false, true));
   scoped_ptr<SpdyFrame> get_resp2(
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
   scoped_ptr<SpdyFrame> body2(
@@ -3633,6 +4080,10 @@ TEST_P(HttpNetworkTransactionTest, ConnectStatus307) {
   ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n"));
 }
 
+TEST_P(HttpNetworkTransactionTest, ConnectStatus308) {
+  ConnectStatusHelper(MockRead("HTTP/1.1 308 Permanent Redirect\r\n"));
+}
+
 TEST_P(HttpNetworkTransactionTest, ConnectStatus400) {
   ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n"));
 }
@@ -5969,23 +6420,12 @@ TEST_P(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
 
   // The proxy responds to the connect with a 407, using a persistent
   // connection.
+  const char* const kAuthStatus = "407";
   const char* const kAuthChallenge[] = {
-    spdy_util_.GetStatusKey(), "407 Proxy Authentication Required",
-    spdy_util_.GetVersionKey(), "HTTP/1.1",
     "proxy-authenticate", "Basic realm=\"MyRealm1\"",
   };
-
-  scoped_ptr<SpdyFrame> conn_auth_resp(
-      spdy_util_.ConstructSpdyControlFrame(NULL,
-                                           0,
-                                           false,
-                                           1,
-                                           LOWEST,
-                                           SYN_REPLY,
-                                           CONTROL_FLAG_NONE,
-                                           kAuthChallenge,
-                                           arraysize(kAuthChallenge),
-                                           0));
+  scoped_ptr<SpdyFrame> conn_auth_resp(spdy_util_.ConstructSpdySynReplyError(
+      kAuthStatus, kAuthChallenge, arraysize(kAuthChallenge) / 2, 1));
 
   scoped_ptr<SpdyFrame> conn_resp(
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
@@ -7098,7 +7538,7 @@ scoped_refptr<HttpNetworkSession> SetupSessionForGroupNameTests(
       session->http_server_properties();
   http_server_properties->SetAlternateProtocol(
       HostPortPair("host.with.alternate", 80), 443,
-      AlternateProtocolFromNextProto(next_proto));
+      AlternateProtocolFromNextProto(next_proto), 1);
 
   return session;
 }
@@ -7158,7 +7598,7 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForDirectConnections) {
     },
   };
 
-  HttpStreamFactory::set_use_alternate_protocols(true);
+  session_deps_.use_alternate_protocols = true;
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
     session_deps_.proxy_service.reset(
@@ -7171,11 +7611,12 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForDirectConnections) {
         new CaptureGroupNameTransportSocketPool(NULL, NULL);
     CaptureGroupNameSSLSocketPool* ssl_conn_pool =
         new CaptureGroupNameSSLSocketPool(NULL, NULL);
-    MockClientSocketPoolManager* mock_pool_manager =
-        new MockClientSocketPoolManager;
+    scoped_ptr<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);
+    peer.SetClientSocketPoolManager(
+        mock_pool_manager.PassAs<ClientSocketPoolManager>());
 
     EXPECT_EQ(ERR_IO_PENDING,
               GroupNameTransactionHelper(tests[i].url, session));
@@ -7221,7 +7662,7 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
     },
   };
 
-  HttpStreamFactory::set_use_alternate_protocols(true);
+  session_deps_.use_alternate_protocols = true;
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
     session_deps_.proxy_service.reset(
@@ -7237,11 +7678,12 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForHTTPProxyConnections) {
     CaptureGroupNameSSLSocketPool* ssl_conn_pool =
         new CaptureGroupNameSSLSocketPool(NULL, NULL);
 
-    MockClientSocketPoolManager* mock_pool_manager =
-        new MockClientSocketPoolManager;
+    scoped_ptr<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);
+    peer.SetClientSocketPoolManager(
+        mock_pool_manager.PassAs<ClientSocketPoolManager>());
 
     EXPECT_EQ(ERR_IO_PENDING,
               GroupNameTransactionHelper(tests[i].url, session));
@@ -7291,7 +7733,7 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
     },
   };
 
-  HttpStreamFactory::set_use_alternate_protocols(true);
+  session_deps_.use_alternate_protocols = true;
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
     session_deps_.proxy_service.reset(
@@ -7307,11 +7749,12 @@ TEST_P(HttpNetworkTransactionTest, GroupNameForSOCKSConnections) {
     CaptureGroupNameSSLSocketPool* ssl_conn_pool =
         new CaptureGroupNameSSLSocketPool(NULL, NULL);
 
-    MockClientSocketPoolManager* mock_pool_manager =
-        new MockClientSocketPoolManager;
+    scoped_ptr<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);
+    peer.SetClientSocketPoolManager(
+        mock_pool_manager.PassAs<ClientSocketPoolManager>());
 
     scoped_ptr<HttpTransaction> trans(
         new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
@@ -7647,7 +8090,7 @@ TEST_P(HttpNetworkTransactionTest, LargeContentLengthThenClose) {
 
 TEST_P(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
   base::FilePath temp_file_path;
-  ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file_path));
+  ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path));
   const uint64 kFakeSize = 100000;  // file is actually blank
   UploadFileElementReader::ScopedOverridingContentLengthForTests
       overriding_content_length(kFakeSize);
@@ -7703,11 +8146,11 @@ TEST_P(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
 
 TEST_P(HttpNetworkTransactionTest, UploadUnreadableFile) {
   base::FilePath temp_file;
-  ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file));
+  ASSERT_TRUE(base::CreateTemporaryFile(&temp_file));
   std::string temp_file_content("Unreadable file.");
-  ASSERT_TRUE(file_util::WriteFile(temp_file, temp_file_content.c_str(),
+  ASSERT_TRUE(base::WriteFile(temp_file, temp_file_content.c_str(),
                                    temp_file_content.length()));
-  ASSERT_TRUE(file_util::MakeFileUnreadable(temp_file));
+  ASSERT_TRUE(base::MakeFileUnreadable(temp_file));
 
   ScopedVector<UploadElementReader> element_readers;
   element_readers.push_back(
@@ -7724,25 +8167,12 @@ TEST_P(HttpNetworkTransactionTest, UploadUnreadableFile) {
   request.upload_data_stream = &upload_data_stream;
   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.
+  // If we try to upload an unreadable file, the transaction should fail.
   scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
 
-  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));
+  StaticSocketDataProvider data(NULL, 0, NULL, 0);
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   TestCompletionCallback callback;
@@ -7751,103 +8181,10 @@ TEST_P(HttpNetworkTransactionTest, UploadUnreadableFile) {
   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.get() != NULL);
-  EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
-
-  base::DeleteFile(temp_file, false);
-}
-
-TEST_P(HttpNetworkTransactionTest, UnreadableUploadFileAfterAuthRestart) {
-  base::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()));
-
-  ScopedVector<UploadElementReader> element_readers;
-  element_readers.push_back(
-      new UploadFileElementReader(base::MessageLoopProxy::current().get(),
-                                  temp_file,
-                                  0,
-                                  kuint64max,
-                                  base::Time()));
-  UploadDataStream upload_data_stream(element_readers.Pass(), 0);
-
-  HttpRequestInfo request;
-  request.method = "POST";
-  request.url = GURL("http://www.google.com/upload");
-  request.upload_data_stream = &upload_data_stream;
-  request.load_flags = 0;
-
-  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
-  scoped_ptr<HttpTransaction> trans(
-      new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
-
-  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: 0\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);
+  EXPECT_EQ(ERR_ACCESS_DENIED, rv);
 
   const HttpResponseInfo* response = trans->GetResponseInfo();
-  ASSERT_TRUE(response != NULL);
-  ASSERT_TRUE(response->headers.get() != 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.get() != NULL);
-  EXPECT_TRUE(response->auth_challenge.get() == NULL);
-  EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+  EXPECT_FALSE(response);
 
   base::DeleteFile(temp_file, false);
 }
@@ -8062,8 +8399,8 @@ TEST_P(HttpNetworkTransactionTest, ChangeAuthRealms) {
 }
 
 TEST_P(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) {
-  HttpStreamFactory::SetNextProtos(SpdyNextProtos());
-  HttpStreamFactory::set_use_alternate_protocols(true);
+  session_deps_.next_protos = SpdyNextProtos();
+  session_deps_.use_alternate_protocols = true;
 
   std::string alternate_protocol_http_header =
       GetAlternateProtocolHttpHeader();
@@ -8094,7 +8431,7 @@ TEST_P(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) {
   EXPECT_EQ(ERR_IO_PENDING, rv);
 
   HostPortPair http_host_port_pair("www.google.com", 80);
-  const HttpServerProperties& http_server_properties =
+  HttpServerProperties& http_server_properties =
       *session->http_server_properties();
   EXPECT_FALSE(
       http_server_properties.HasAlternateProtocol(http_host_port_pair));
@@ -8113,17 +8450,16 @@ TEST_P(HttpNetworkTransactionTest, HonorAlternateProtocolHeader) {
   EXPECT_EQ("hello world", response_data);
 
   ASSERT_TRUE(http_server_properties.HasAlternateProtocol(http_host_port_pair));
-  const PortAlternateProtocolPair alternate =
+  const AlternateProtocolInfo alternate =
       http_server_properties.GetAlternateProtocol(http_host_port_pair);
-  PortAlternateProtocolPair expected_alternate;
-  expected_alternate.port = 443;
-  expected_alternate.protocol = AlternateProtocolFromNextProto(GetParam());
+  AlternateProtocolInfo expected_alternate(
+      443, AlternateProtocolFromNextProto(GetParam()), 1);
   EXPECT_TRUE(expected_alternate.Equals(alternate));
 }
 
 TEST_P(HttpNetworkTransactionTest,
        MarkBrokenAlternateProtocolAndFallback) {
-  HttpStreamFactory::set_use_alternate_protocols(true);
+  session_deps_.use_alternate_protocols = true;
 
   HttpRequestInfo request;
   request.method = "GET";
@@ -8153,7 +8489,7 @@ TEST_P(HttpNetworkTransactionTest,
   http_server_properties->SetAlternateProtocol(
       HostPortPair::FromURL(request.url),
       666 /* port is ignored by MockConnect anyway */,
-      AlternateProtocolFromNextProto(GetParam()));
+      AlternateProtocolFromNextProto(GetParam()), 1);
 
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
@@ -8174,7 +8510,7 @@ TEST_P(HttpNetworkTransactionTest,
 
   ASSERT_TRUE(http_server_properties->HasAlternateProtocol(
       HostPortPair::FromURL(request.url)));
-  const PortAlternateProtocolPair alternate =
+  const AlternateProtocolInfo alternate =
       http_server_properties->GetAlternateProtocol(
           HostPortPair::FromURL(request.url));
   EXPECT_EQ(ALTERNATE_PROTOCOL_BROKEN, alternate.protocol);
@@ -8186,7 +8522,7 @@ TEST_P(HttpNetworkTransactionTest,
   // 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);
+  session_deps_.use_alternate_protocols = true;
 
   HttpRequestInfo restricted_port_request;
   restricted_port_request.method = "GET";
@@ -8215,7 +8551,7 @@ TEST_P(HttpNetworkTransactionTest,
   http_server_properties->SetAlternateProtocol(
       HostPortPair::FromURL(restricted_port_request.url),
       kUnrestrictedAlternatePort,
-      AlternateProtocolFromNextProto(GetParam()));
+      AlternateProtocolFromNextProto(GetParam()), 1);
 
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
@@ -8236,7 +8572,7 @@ TEST_P(HttpNetworkTransactionTest,
   // on a restricted port (port < 1024) if we set
   // enable_user_alternate_protocol_ports.
 
-  HttpStreamFactory::set_use_alternate_protocols(true);
+  session_deps_.use_alternate_protocols = true;
   session_deps_.enable_user_alternate_protocol_ports = true;
 
   HttpRequestInfo restricted_port_request;
@@ -8266,7 +8602,7 @@ TEST_P(HttpNetworkTransactionTest,
   http_server_properties->SetAlternateProtocol(
       HostPortPair::FromURL(restricted_port_request.url),
       kUnrestrictedAlternatePort,
-      AlternateProtocolFromNextProto(GetParam()));
+      AlternateProtocolFromNextProto(GetParam()), 1);
 
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
@@ -8285,7 +8621,7 @@ TEST_P(HttpNetworkTransactionTest,
   // 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);
+  session_deps_.use_alternate_protocols = true;
 
   HttpRequestInfo restricted_port_request;
   restricted_port_request.method = "GET";
@@ -8314,7 +8650,7 @@ TEST_P(HttpNetworkTransactionTest,
   http_server_properties->SetAlternateProtocol(
       HostPortPair::FromURL(restricted_port_request.url),
       kRestrictedAlternatePort,
-      AlternateProtocolFromNextProto(GetParam()));
+      AlternateProtocolFromNextProto(GetParam()), 1);
 
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
@@ -8334,7 +8670,7 @@ TEST_P(HttpNetworkTransactionTest,
   // 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);
+  session_deps_.use_alternate_protocols = true;
 
   HttpRequestInfo unrestricted_port_request;
   unrestricted_port_request.method = "GET";
@@ -8363,7 +8699,7 @@ TEST_P(HttpNetworkTransactionTest,
   http_server_properties->SetAlternateProtocol(
       HostPortPair::FromURL(unrestricted_port_request.url),
       kRestrictedAlternatePort,
-      AlternateProtocolFromNextProto(GetParam()));
+      AlternateProtocolFromNextProto(GetParam()), 1);
 
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
@@ -8382,7 +8718,7 @@ TEST_P(HttpNetworkTransactionTest,
   // 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);
+  session_deps_.use_alternate_protocols = true;
 
   HttpRequestInfo unrestricted_port_request;
   unrestricted_port_request.method = "GET";
@@ -8411,7 +8747,7 @@ TEST_P(HttpNetworkTransactionTest,
   http_server_properties->SetAlternateProtocol(
       HostPortPair::FromURL(unrestricted_port_request.url),
       kUnrestrictedAlternatePort,
-      AlternateProtocolFromNextProto(GetParam()));
+      AlternateProtocolFromNextProto(GetParam()), 1);
 
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
@@ -8424,12 +8760,11 @@ TEST_P(HttpNetworkTransactionTest,
   EXPECT_EQ(OK, callback.WaitForResult());
 }
 
-TEST_P(HttpNetworkTransactionTest,
-       AlternateProtocolUnsafeBlocked) {
+TEST_P(HttpNetworkTransactionTest, 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);
+  session_deps_.use_alternate_protocols = true;
 
   HttpRequestInfo request;
   request.method = "GET";
@@ -8455,7 +8790,7 @@ TEST_P(HttpNetworkTransactionTest,
   http_server_properties->SetAlternateProtocol(
       HostPortPair::FromURL(request.url),
       kUnsafePort,
-      AlternateProtocolFromNextProto(GetParam()));
+      AlternateProtocolFromNextProto(GetParam()), 1);
 
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
@@ -8467,7 +8802,7 @@ TEST_P(HttpNetworkTransactionTest,
   EXPECT_EQ(OK, callback.WaitForResult());
 
   // Disable alternate protocol before the asserts.
-  HttpStreamFactory::set_use_alternate_protocols(false);
// HttpStreamFactory::set_use_alternate_protocols(false);
 
   const HttpResponseInfo* response = trans->GetResponseInfo();
   ASSERT_TRUE(response != NULL);
@@ -8480,8 +8815,8 @@ TEST_P(HttpNetworkTransactionTest,
 }
 
 TEST_P(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
-  HttpStreamFactory::set_use_alternate_protocols(true);
-  HttpStreamFactory::SetNextProtos(SpdyNextProtos());
+  session_deps_.use_alternate_protocols = true;
+  session_deps_.next_protos = SpdyNextProtos();
 
   HttpRequestInfo request;
   request.method = "GET";
@@ -8570,8 +8905,8 @@ TEST_P(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
 }
 
 TEST_P(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
-  HttpStreamFactory::set_use_alternate_protocols(true);
-  HttpStreamFactory::SetNextProtos(SpdyNextProtos());
+  session_deps_.use_alternate_protocols = true;
+  session_deps_.next_protos = SpdyNextProtos();
 
   HttpRequestInfo request;
   request.method = "GET";
@@ -8687,8 +9022,8 @@ TEST_P(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
 }
 
 TEST_P(HttpNetworkTransactionTest, StallAlternateProtocolForNpnSpdy) {
-  HttpStreamFactory::set_use_alternate_protocols(true);
-  HttpStreamFactory::SetNextProtos(SpdyNextProtos());
+  session_deps_.use_alternate_protocols = true;
+  session_deps_.next_protos = SpdyNextProtos();
 
   HttpRequestInfo request;
   request.method = "GET";
@@ -8806,8 +9141,8 @@ class CapturingProxyResolver : public ProxyResolver {
 
 TEST_P(HttpNetworkTransactionTest,
        UseAlternateProtocolForTunneledNpnSpdy) {
-  HttpStreamFactory::set_use_alternate_protocols(true);
-  HttpStreamFactory::SetNextProtos(SpdyNextProtos());
+  session_deps_.use_alternate_protocols = true;
+  session_deps_.next_protos = SpdyNextProtos();
 
   ProxyConfig proxy_config;
   proxy_config.set_auto_detect(true);
@@ -8928,8 +9263,8 @@ TEST_P(HttpNetworkTransactionTest,
 
 TEST_P(HttpNetworkTransactionTest,
        UseAlternateProtocolForNpnSpdyWithExistingSpdySession) {
-  HttpStreamFactory::set_use_alternate_protocols(true);
-  HttpStreamFactory::SetNextProtos(SpdyNextProtos());
+  session_deps_.use_alternate_protocols = true;
+  session_deps_.next_protos = SpdyNextProtos();
 
   HttpRequestInfo request;
   request.method = "GET";
@@ -8995,7 +9330,7 @@ TEST_P(HttpNetworkTransactionTest,
   // Set up an initial SpdySession in the pool to reuse.
   HostPortPair host_port_pair("www.google.com", 443);
   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
-                     kPrivacyModeDisabled);
+                     PRIVACY_MODE_DISABLED);
   base::WeakPtr<SpdySession> spdy_session =
       CreateSecureSpdySession(session, key, BoundNetLog());
 
@@ -9331,8 +9666,8 @@ TEST_P(HttpNetworkTransactionTest, GenerateAuthToken) {
         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());
+        HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(),
+                                             auth_challenge.end());
         auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_PROXY,
                                         origin, BoundNetLog());
         auth_handler->SetGenerateExpectation(
@@ -9345,8 +9680,8 @@ TEST_P(HttpNetworkTransactionTest, GenerateAuthToken) {
       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());
+      HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(),
+                                           auth_challenge.end());
       auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER,
                                       origin, BoundNetLog());
       auth_handler->SetGenerateExpectation(
@@ -9442,8 +9777,8 @@ TEST_P(HttpNetworkTransactionTest, MultiRoundAuth) {
   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());
+  HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(),
+                                       auth_challenge.end());
   auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER,
                                   origin, BoundNetLog());
   auth_factory->AddMockHandler(auth_handler, HttpAuth::AUTH_SERVER);
@@ -9469,10 +9804,11 @@ TEST_P(HttpNetworkTransactionTest, MultiRoundAuth) {
       session_deps_.host_resolver.get(),
       session_deps_.socket_factory.get(),
       session_deps_.net_log);
-  MockClientSocketPoolManager* mock_pool_manager =
-      new MockClientSocketPoolManager;
+  scoped_ptr<MockClientSocketPoolManager> mock_pool_manager(
+      new MockClientSocketPoolManager);
   mock_pool_manager->SetTransportSocketPool(transport_pool);
-  session_peer.SetClientSocketPoolManager(mock_pool_manager);
+  session_peer.SetClientSocketPoolManager(
+      mock_pool_manager.PassAs<ClientSocketPoolManager>());
 
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
@@ -9618,10 +9954,11 @@ TEST_P(HttpNetworkTransactionTest, MultiRoundAuth) {
 // This tests the case that a request is issued via http instead of spdy after
 // npn is negotiated.
 TEST_P(HttpNetworkTransactionTest, NpnWithHttpOverSSL) {
-  HttpStreamFactory::set_use_alternate_protocols(true);
-  std::vector<NextProto> next_protos;
+  session_deps_.use_alternate_protocols = true;
+  NextProtoVector next_protos;
   next_protos.push_back(kProtoHTTP11);
-  HttpStreamFactory::SetNextProtos(next_protos);
+  session_deps_.next_protos = next_protos;
+
   HttpRequestInfo request;
   request.method = "GET";
   request.url = GURL("https://www.google.com/");
@@ -9682,8 +10019,8 @@ TEST_P(HttpNetworkTransactionTest, 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());
+  session_deps_.use_alternate_protocols = true;
+  session_deps_.next_protos = SpdyNextProtos();
 
   HttpRequestInfo request;
   request.method = "GET";
@@ -9745,8 +10082,8 @@ class UrlRecordingHttpAuthHandlerMock : public HttpAuthHandlerMock {
 TEST_P(HttpNetworkTransactionTest, 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(SpdyNextProtos());
+  session_deps_.use_alternate_protocols = true;
+  session_deps_.next_protos = SpdyNextProtos();
 
   session_deps_.proxy_service.reset(
       ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"));
@@ -9940,6 +10277,56 @@ TEST_P(HttpNetworkTransactionTest, SimpleCancel) {
   base::MessageLoop::current()->RunUntilIdle();
 }
 
+// Test that if a transaction is cancelled after receiving the headers, the
+// stream is drained properly and added back to the socket pool.  The main
+// purpose of this test is to make sure that an HttpStreamParser can be read
+// from after the HttpNetworkTransaction and the objects it owns have been
+// deleted.
+// See http://crbug.com/368418
+TEST_P(HttpNetworkTransactionTest, CancelAfterHeaders) {
+  MockRead data_reads[] = {
+    MockRead(ASYNC, "HTTP/1.1 200 OK\r\n"),
+    MockRead(ASYNC, "Content-Length: 2\r\n"),
+    MockRead(ASYNC, "Connection: Keep-Alive\r\n\r\n"),
+    MockRead(ASYNC, "1"),
+    // 2 async reads are necessary to trigger a ReadResponseBody call after the
+    // HttpNetworkTransaction has been deleted.
+    MockRead(ASYNC, "2"),
+    MockRead(SYNCHRONOUS, ERR_IO_PENDING),  // Should never read this.
+  };
+  StaticSocketDataProvider data(data_reads, arraysize(data_reads), NULL, 0);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+  {
+    HttpRequestInfo request;
+    request.method = "GET";
+    request.url = GURL("http://www.google.com/");
+    request.load_flags = 0;
+
+    HttpNetworkTransaction trans(DEFAULT_PRIORITY, session);
+    TestCompletionCallback callback;
+
+    int rv = trans.Start(&request, callback.callback(), BoundNetLog());
+    EXPECT_EQ(ERR_IO_PENDING, rv);
+    callback.WaitForResult();
+
+    const HttpResponseInfo* response = trans.GetResponseInfo();
+    ASSERT_TRUE(response != NULL);
+    EXPECT_TRUE(response->headers.get() != NULL);
+    EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+
+    // The transaction and HttpRequestInfo are deleted.
+  }
+
+  // Let the HttpResponseBodyDrainer drain the socket.
+  base::MessageLoop::current()->RunUntilIdle();
+
+  // Socket should now be idle, waiting to be reused.
+  EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session));
+}
+
 // Test a basic GET request through a proxy.
 TEST_P(HttpNetworkTransactionTest, ProxyGet) {
   session_deps_.proxy_service.reset(
@@ -9973,6 +10360,10 @@ TEST_P(HttpNetworkTransactionTest, ProxyGet) {
 
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
+  BeforeProxyHeadersSentHandler proxy_headers_handler;
+  trans->SetBeforeProxyHeadersSentCallback(
+      base::Bind(&BeforeProxyHeadersSentHandler::OnBeforeProxyHeadersSent,
+                 base::Unretained(&proxy_headers_handler)));
 
   int rv = trans->Start(&request, callback1.callback(), log.bound());
   EXPECT_EQ(ERR_IO_PENDING, rv);
@@ -9987,6 +10378,10 @@ TEST_P(HttpNetworkTransactionTest, ProxyGet) {
   EXPECT_EQ(200, response->headers->response_code());
   EXPECT_EQ(100, response->headers->GetContentLength());
   EXPECT_TRUE(response->was_fetched_via_proxy);
+  EXPECT_TRUE(
+      response->proxy_server.Equals(HostPortPair::FromString("myproxy:70")));
+  EXPECT_TRUE(proxy_headers_handler.observed_before_proxy_headers_sent());
+  EXPECT_EQ("myproxy:70", proxy_headers_handler.observed_proxy_server_uri());
   EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
 
   LoadTimingInfo load_timing_info;
@@ -10061,6 +10456,8 @@ TEST_P(HttpNetworkTransactionTest, ProxyTunnelGet) {
   EXPECT_EQ(100, response->headers->GetContentLength());
   EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
   EXPECT_TRUE(response->was_fetched_via_proxy);
+  EXPECT_TRUE(
+      response->proxy_server.Equals(HostPortPair::FromString("myproxy:70")));
 
   LoadTimingInfo load_timing_info;
   EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
@@ -10153,7 +10550,7 @@ TEST_P(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) {
   // Set up an initial SpdySession in the pool to reuse.
   HostPortPair host_port_pair("www.google.com", 443);
   SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
-                     kPrivacyModeDisabled);
+                     PRIVACY_MODE_DISABLED);
   base::WeakPtr<SpdySession> spdy_session =
       CreateInsecureSpdySession(session, key, BoundNetLog());
 
@@ -10230,7 +10627,7 @@ TEST_P(HttpNetworkTransactionTest,
   request_info.load_flags = net::LOAD_NORMAL;
 
   scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
-  cert_request->host_and_port = "www.example.com:443";
+  cert_request->host_and_port = HostPortPair("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
@@ -10310,8 +10707,8 @@ TEST_P(HttpNetworkTransactionTest,
   // 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_TRUE(session->ssl_client_auth_cache()->Lookup(
+      HostPortPair("www.example.com", 443), &client_cert));
   ASSERT_EQ(NULL, client_cert.get());
 
   // Restart the handshake. This will consume ssl_data2, which fails, and
@@ -10322,8 +10719,8 @@ TEST_P(HttpNetworkTransactionTest,
 
   // 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));
+  ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup(
+      HostPortPair("www.example.com", 443), &client_cert));
 }
 
 // Ensure that a client certificate is removed from the SSL client auth
@@ -10340,7 +10737,7 @@ TEST_P(HttpNetworkTransactionTest,
   request_info.load_flags = net::LOAD_NORMAL;
 
   scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
-  cert_request->host_and_port = "www.example.com:443";
+  cert_request->host_and_port = HostPortPair("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.
@@ -10431,8 +10828,8 @@ TEST_P(HttpNetworkTransactionTest,
   // 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_TRUE(session->ssl_client_auth_cache()->Lookup(
+      HostPortPair("www.example.com", 443), &client_cert));
   ASSERT_EQ(NULL, client_cert.get());
 
   // Restart the handshake. This will consume ssl_data2, which fails, and
@@ -10443,8 +10840,8 @@ TEST_P(HttpNetworkTransactionTest,
 
   // 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));
+  ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup(
+      HostPortPair("www.example.com", 443), &client_cert));
 }
 
 // Ensure that a client certificate is removed from the SSL client auth
@@ -10462,7 +10859,7 @@ TEST_P(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
   session_deps_.net_log = log.bound().net_log();
 
   scoped_refptr<SSLCertRequestInfo> cert_request(new SSLCertRequestInfo());
-  cert_request->host_and_port = "proxy:70";
+  cert_request->host_and_port = HostPortPair("proxy", 70);
 
   // See ClientAuthCertCache_Direct_NoFalseStart for the explanation of
   // [ssl_]data[1-3]. Rather than represending the endpoint
@@ -10525,13 +10922,13 @@ TEST_P(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
     // 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_TRUE(session->ssl_client_auth_cache()->Lookup(
+        HostPortPair("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));
+    ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup(
+        HostPortPair("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
@@ -10541,10 +10938,10 @@ TEST_P(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
 
     // 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));
+    ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup(
+        HostPortPair("proxy", 70), &client_cert));
+    ASSERT_FALSE(session->ssl_client_auth_cache()->Lookup(
+        HostPortPair("www.example.com", 443), &client_cert));
   }
 }
 
@@ -10565,8 +10962,8 @@ TEST_P(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
 #define MAYBE_UseIPConnectionPooling UseIPConnectionPooling
 #endif
 WRAPPED_TEST_P(HttpNetworkTransactionTest, MAYBE_UseIPConnectionPooling) {
-  HttpStreamFactory::set_use_alternate_protocols(true);
-  HttpStreamFactory::SetNextProtos(SpdyNextProtos());
+  session_deps_.use_alternate_protocols = true;
+  session_deps_.next_protos = SpdyNextProtos();
 
   // Set up a special HttpNetworkSession with a MockCachingHostResolver.
   session_deps_.host_resolver.reset(new MockCachingHostResolver());
@@ -10668,8 +11065,8 @@ WRAPPED_TEST_P(HttpNetworkTransactionTest, MAYBE_UseIPConnectionPooling) {
 #undef MAYBE_UseIPConnectionPooling
 
 TEST_P(HttpNetworkTransactionTest, UseIPConnectionPoolingAfterResolution) {
-  HttpStreamFactory::set_use_alternate_protocols(true);
-  HttpStreamFactory::SetNextProtos(SpdyNextProtos());
+  session_deps_.use_alternate_protocols = true;
+  session_deps_.next_protos = SpdyNextProtos();
 
   // Set up a special HttpNetworkSession with a MockCachingHostResolver.
   session_deps_.host_resolver.reset(new MockCachingHostResolver());
@@ -10810,10 +11207,9 @@ WRAPPED_TEST_P(HttpNetworkTransactionTest,
 // prefix doesn't work with parametrized tests).
 #if defined(OS_WIN)
   return;
-#endif
-
-  HttpStreamFactory::set_use_alternate_protocols(true);
-  HttpStreamFactory::SetNextProtos(SpdyNextProtos());
+#else
+  session_deps_.use_alternate_protocols = true;
+  session_deps_.next_protos = SpdyNextProtos();
 
   // Set up a special HttpNetworkSession with a OneTimeCachingHostResolver.
   OneTimeCachingHostResolver host_resolver(HostPortPair("www.gmail.com", 443));
@@ -10913,56 +11309,10 @@ WRAPPED_TEST_P(HttpNetworkTransactionTest,
   EXPECT_TRUE(response->was_npn_negotiated);
   ASSERT_EQ(OK, ReadTransaction(&trans2, &response_data));
   EXPECT_EQ("hello!", response_data);
+#endif
 }
 #undef MAYBE_UseIPConnectionPoolingWithHostCacheExpiration
 
-TEST_P(HttpNetworkTransactionTest, 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_P(HttpNetworkTransactionTest, 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);
-}
-
 TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttp) {
   const std::string https_url = "https://www.google.com/";
   const std::string http_url = "http://www.google.com:443/";
@@ -11053,20 +11403,19 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) {
                                                                 LOWEST));
   scoped_ptr<SpdyFrame> req1(
       spdy_util_.ConstructSpdyGet(https_url.c_str(), false, 1, LOWEST));
-
-  // SPDY GET for HTTP URL (through the proxy, but not the tunnel)
   scoped_ptr<SpdyFrame> wrapped_req1(
       spdy_util_.ConstructWrappedSpdyFrame(req1, 1));
-  const char* const headers[] = {
-    spdy_util_.GetMethodKey(), "GET",
-    spdy_util_.GetPathKey(), spdy_util_.is_spdy2() ? http_url.c_str() : "/",
-    spdy_util_.GetHostKey(),  "www.google.com:443",
-    spdy_util_.GetSchemeKey(), "http",
-    spdy_util_.GetVersionKey(), "HTTP/1.1"
-  };
-  scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyControlFrame(
-      NULL, 0, false, 3, MEDIUM, SYN_STREAM, CONTROL_FLAG_FIN,
-      headers, arraysize(headers), 0));
+
+  // SPDY GET for HTTP URL (through the proxy, but not the tunnel).
+  SpdyHeaderBlock req2_block;
+  req2_block[spdy_util_.GetMethodKey()] = "GET";
+  req2_block[spdy_util_.GetPathKey()] =
+      spdy_util_.is_spdy2() ? http_url.c_str() : "/";
+  req2_block[spdy_util_.GetHostKey()] = "www.google.com:443";
+  req2_block[spdy_util_.GetSchemeKey()] = "http";
+  spdy_util_.MaybeAddVersionHeader(&req2_block);
+  scoped_ptr<SpdyFrame> req2(
+      spdy_util_.ConstructSpdySyn(3, req2_block, MEDIUM, false, true));
 
   MockWrite writes1[] = {
     CreateMockWrite(*connect, 0),
@@ -11158,7 +11507,7 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) {
 }
 
 TEST_P(HttpNetworkTransactionTest, UseSpdySessionForHttpWhenForced) {
-  HttpStreamFactory::set_force_spdy_always(true);
+  session_deps_.force_spdy_always = true;
   const std::string https_url = "https://www.google.com/";
   const std::string http_url = "http://www.google.com:443/";
 
@@ -11237,8 +11586,8 @@ TEST_P(HttpNetworkTransactionTest, DoNotUseSpdySessionIfCertDoesNotMatch) {
   // SPDY GET for HTTP URL (through SPDY proxy)
   scoped_ptr<SpdyHeaderBlock> headers(
       spdy_util_.ConstructGetHeaderBlockForProxy("http://www.google.com/"));
-  scoped_ptr<SpdyFrame> req1(spdy_util_.ConstructSpdyControlFrame(
-      headers.Pass(), false, 1, LOWEST, SYN_STREAM, CONTROL_FLAG_FIN, 0));
+  scoped_ptr<SpdyFrame> req1(
+      spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true));
 
   MockWrite writes1[] = {
     CreateMockWrite(*req1, 0),
@@ -11433,7 +11782,7 @@ TEST_P(HttpNetworkTransactionTest, ErrorSocketNotConnected) {
 }
 
 TEST_P(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
-  HttpStreamFactory::SetNextProtos(SpdyNextProtos());
+  session_deps_.next_protos = SpdyNextProtos();
   ClientSocketPoolManager::set_max_sockets_per_group(
       HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
   ClientSocketPoolManager::set_max_sockets_per_pool(
@@ -11511,7 +11860,7 @@ TEST_P(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
 
   HostPortPair host_port_pair_a("www.a.com", 443);
   SpdySessionKey spdy_session_key_a(
-      host_port_pair_a, ProxyServer::Direct(), kPrivacyModeDisabled);
+      host_port_pair_a, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
   EXPECT_FALSE(
       HasSpdySession(session->spdy_session_pool(), spdy_session_key_a));
 
@@ -11543,7 +11892,7 @@ TEST_P(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
 
   HostPortPair host_port_pair_b("www.b.com", 443);
   SpdySessionKey spdy_session_key_b(
-      host_port_pair_b, ProxyServer::Direct(), kPrivacyModeDisabled);
+      host_port_pair_b, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
   EXPECT_FALSE(
       HasSpdySession(session->spdy_session_pool(), spdy_session_key_b));
   HttpRequestInfo request2;
@@ -11571,7 +11920,7 @@ TEST_P(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
 
   HostPortPair host_port_pair_a1("www.a.com", 80);
   SpdySessionKey spdy_session_key_a1(
-      host_port_pair_a1, ProxyServer::Direct(), kPrivacyModeDisabled);
+      host_port_pair_a1, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
   EXPECT_FALSE(
       HasSpdySession(session->spdy_session_pool(), spdy_session_key_a1));
   HttpRequestInfo request3;
@@ -11879,11 +12228,6 @@ class FakeStream : public HttpStreamBase,
     return ERR_UNEXPECTED;
   }
 
-  virtual const HttpResponseInfo* GetResponseInfo() const OVERRIDE {
-    ADD_FAILURE();
-    return NULL;
-  }
-
   virtual int ReadResponseBody(IOBuffer* buf, int buf_len,
                                const CompletionCallback& callback) OVERRIDE {
     ADD_FAILURE();
@@ -11915,6 +12259,11 @@ class FakeStream : public HttpStreamBase,
     return false;
   }
 
+  virtual int64 GetTotalReceivedBytes() const OVERRIDE {
+    ADD_FAILURE();
+    return 0;
+  }
+
   virtual bool GetLoadTimingInfo(
       LoadTimingInfo* load_timing_info) const OVERRIDE {
     ADD_FAILURE();
@@ -11957,12 +12306,25 @@ class FakeStreamRequest : public HttpStreamRequest,
   FakeStreamRequest(RequestPriority priority,
                     HttpStreamRequest::Delegate* delegate)
       : priority_(priority),
-        delegate_(delegate) {}
+        delegate_(delegate),
+        websocket_stream_create_helper_(NULL) {}
+
+  FakeStreamRequest(RequestPriority priority,
+                    HttpStreamRequest::Delegate* delegate,
+                    WebSocketHandshakeStreamBase::CreateHelper* create_helper)
+      : priority_(priority),
+        delegate_(delegate),
+        websocket_stream_create_helper_(create_helper) {}
 
   virtual ~FakeStreamRequest() {}
 
   RequestPriority priority() const { return priority_; }
 
+  const WebSocketHandshakeStreamBase::CreateHelper*
+  websocket_stream_create_helper() const {
+    return websocket_stream_create_helper_;
+  }
+
   // Create a new FakeStream and pass it to the request's
   // delegate. Returns a weak pointer to the FakeStream.
   base::WeakPtr<FakeStream> FinishStreamRequest() {
@@ -12004,6 +12366,7 @@ class FakeStreamRequest : public HttpStreamRequest,
  private:
   RequestPriority priority_;
   HttpStreamRequest::Delegate* const delegate_;
+  WebSocketHandshakeStreamBase::CreateHelper* websocket_stream_create_helper_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeStreamRequest);
 };
@@ -12038,10 +12401,12 @@ class FakeStreamFactory : public HttpStreamFactory {
       const SSLConfig& server_ssl_config,
       const SSLConfig& proxy_ssl_config,
       HttpStreamRequest::Delegate* delegate,
-      WebSocketHandshakeStreamBase::Factory* factory,
+      WebSocketHandshakeStreamBase::CreateHelper* create_helper,
       const BoundNetLog& net_log) OVERRIDE {
-    ADD_FAILURE();
-    return NULL;
+    FakeStreamRequest* fake_request =
+        new FakeStreamRequest(priority, delegate, create_helper);
+    last_stream_request_ = fake_request->AsWeakPtr();
+    return fake_request;
   }
 
   virtual void PreconnectStreams(int num_streams,
@@ -12052,11 +12417,6 @@ class FakeStreamFactory : public HttpStreamFactory {
     ADD_FAILURE();
   }
 
-  virtual base::Value* PipelineInfoToValue() const OVERRIDE {
-    ADD_FAILURE();
-    return NULL;
-  }
-
   virtual const HostMappingRules* GetHostMappingRules() const OVERRIDE {
     ADD_FAILURE();
     return NULL;
@@ -12068,6 +12428,33 @@ class FakeStreamFactory : public HttpStreamFactory {
   DISALLOW_COPY_AND_ASSIGN(FakeStreamFactory);
 };
 
+// TODO(yhirano): Split this class out into a net/websockets file, if it is
+// worth doing.
+class FakeWebSocketStreamCreateHelper :
+      public WebSocketHandshakeStreamBase::CreateHelper {
+ public:
+  virtual WebSocketHandshakeStreamBase* CreateBasicStream(
+      scoped_ptr<ClientSocketHandle> connection,
+      bool using_proxy) OVERRIDE {
+    NOTREACHED();
+    return NULL;
+  }
+
+  virtual WebSocketHandshakeStreamBase* CreateSpdyStream(
+      const base::WeakPtr<SpdySession>& session,
+      bool use_relative_url) OVERRIDE {
+    NOTREACHED();
+    return NULL;
+  };
+
+  virtual ~FakeWebSocketStreamCreateHelper() {}
+
+  virtual scoped_ptr<WebSocketStream> Upgrade() {
+    NOTREACHED();
+    return scoped_ptr<WebSocketStream>();
+  }
+};
+
 }  // namespace
 
 // Make sure that HttpNetworkTransaction passes on its priority to its
@@ -12076,7 +12463,7 @@ TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriorityOnStart) {
   scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
   HttpNetworkSessionPeer peer(session);
   FakeStreamFactory* fake_factory = new FakeStreamFactory();
-  peer.SetHttpStreamFactory(fake_factory);
+  peer.SetHttpStreamFactory(scoped_ptr<HttpStreamFactory>(fake_factory));
 
   HttpNetworkTransaction trans(LOW, session);
 
@@ -12099,7 +12486,7 @@ TEST_P(HttpNetworkTransactionTest, SetStreamRequestPriority) {
   scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
   HttpNetworkSessionPeer peer(session);
   FakeStreamFactory* fake_factory = new FakeStreamFactory();
-  peer.SetHttpStreamFactory(fake_factory);
+  peer.SetHttpStreamFactory(scoped_ptr<HttpStreamFactory>(fake_factory));
 
   HttpNetworkTransaction trans(LOW, session);
 
@@ -12124,7 +12511,7 @@ TEST_P(HttpNetworkTransactionTest, SetStreamPriority) {
   scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
   HttpNetworkSessionPeer peer(session);
   FakeStreamFactory* fake_factory = new FakeStreamFactory();
-  peer.SetHttpStreamFactory(fake_factory);
+  peer.SetHttpStreamFactory(scoped_ptr<HttpStreamFactory>(fake_factory));
 
   HttpNetworkTransaction trans(LOW, session);
 
@@ -12144,6 +12531,39 @@ TEST_P(HttpNetworkTransactionTest, SetStreamPriority) {
   EXPECT_EQ(LOWEST, fake_stream->priority());
 }
 
+TEST_P(HttpNetworkTransactionTest, CreateWebSocketHandshakeStream) {
+  // The same logic needs to be tested for both ws: and wss: schemes, but this
+  // test is already parameterised on NextProto, so it uses a loop to verify
+  // that the different schemes work.
+  std::string test_cases[] = {"ws://www.google.com/", "wss://www.google.com/"};
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+    HttpNetworkSessionPeer peer(session);
+    FakeStreamFactory* fake_factory = new FakeStreamFactory();
+    FakeWebSocketStreamCreateHelper websocket_stream_create_helper;
+    peer.SetHttpStreamFactoryForWebSocket(
+        scoped_ptr<HttpStreamFactory>(fake_factory));
+
+    HttpNetworkTransaction trans(LOW, session);
+    trans.SetWebSocketHandshakeStreamCreateHelper(
+        &websocket_stream_create_helper);
+
+    HttpRequestInfo request;
+    TestCompletionCallback callback;
+    request.method = "GET";
+    request.url = GURL(test_cases[i]);
+
+    EXPECT_EQ(ERR_IO_PENDING,
+              trans.Start(&request, callback.callback(), BoundNetLog()));
+
+    base::WeakPtr<FakeStreamRequest> fake_request =
+        fake_factory->last_stream_request();
+    ASSERT_TRUE(fake_request != NULL);
+    EXPECT_EQ(&websocket_stream_create_helper,
+              fake_request->websocket_stream_create_helper());
+  }
+}
+
 // Tests that when a used socket is returned to the SSL socket pool, it's closed
 // if the transport socket pool is stalled on the global socket limit.
 TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest) {
@@ -12308,4 +12728,487 @@ TEST_P(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest2) {
   EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session));
 }
 
+TEST_P(HttpNetworkTransactionTest, PostReadsErrorResponseAfterReset) {
+  ScopedVector<UploadElementReader> element_readers;
+  element_readers.push_back(new UploadBytesElementReader("foo", 3));
+  UploadDataStream upload_data_stream(element_readers.Pass(), 0);
+
+  HttpRequestInfo request;
+  request.method = "POST";
+  request.url = GURL("http://www.foo.com/");
+  request.upload_data_stream = &upload_data_stream;
+  request.load_flags = 0;
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+  // Send headers successfully, but get an error while sending the body.
+  MockWrite data_writes[] = {
+    MockWrite("POST / HTTP/1.1\r\n"
+              "Host: www.foo.com\r\n"
+              "Connection: keep-alive\r\n"
+              "Content-Length: 3\r\n\r\n"),
+    MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
+  };
+
+  MockRead data_reads[] = {
+    MockRead("HTTP/1.0 400 Not OK\r\n\r\n"),
+    MockRead("hello world"),
+    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);
+
+  EXPECT_TRUE(response->headers.get() != NULL);
+  EXPECT_EQ("HTTP/1.0 400 Not 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 makes sure the retry logic doesn't trigger when reading an error
+// response from a server that rejected a POST with a CONNECTION_RESET.
+TEST_P(HttpNetworkTransactionTest,
+       PostReadsErrorResponseAfterResetOnReusedSocket) {
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  MockWrite data_writes[] = {
+    MockWrite("GET / HTTP/1.1\r\n"
+              "Host: www.foo.com\r\n"
+              "Connection: keep-alive\r\n\r\n"),
+    MockWrite("POST / HTTP/1.1\r\n"
+              "Host: www.foo.com\r\n"
+              "Connection: keep-alive\r\n"
+              "Content-Length: 3\r\n\r\n"),
+    MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
+  };
+
+  MockRead data_reads[] = {
+    MockRead("HTTP/1.1 200 Peachy\r\n"
+             "Content-Length: 14\r\n\r\n"),
+    MockRead("first response"),
+    MockRead("HTTP/1.1 400 Not OK\r\n"
+             "Content-Length: 15\r\n\r\n"),
+    MockRead("second response"),
+    MockRead(SYNCHRONOUS, OK),
+  };
+  StaticSocketDataProvider data(data_reads, arraysize(data_reads), data_writes,
+                                arraysize(data_writes));
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+  TestCompletionCallback callback;
+  HttpRequestInfo request1;
+  request1.method = "GET";
+  request1.url = GURL("http://www.foo.com/");
+  request1.load_flags = 0;
+
+  scoped_ptr<HttpTransaction> trans1(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+  int rv = trans1->Start(&request1, callback.callback(), BoundNetLog());
+  EXPECT_EQ(ERR_IO_PENDING, rv);
+
+  rv = callback.WaitForResult();
+  EXPECT_EQ(OK, rv);
+
+  const HttpResponseInfo* response1 = trans1->GetResponseInfo();
+  ASSERT_TRUE(response1 != NULL);
+
+  EXPECT_TRUE(response1->headers.get() != NULL);
+  EXPECT_EQ("HTTP/1.1 200 Peachy", response1->headers->GetStatusLine());
+
+  std::string response_data1;
+  rv = ReadTransaction(trans1.get(), &response_data1);
+  EXPECT_EQ(OK, rv);
+  EXPECT_EQ("first response", response_data1);
+  // Delete the transaction to release the socket back into the socket pool.
+  trans1.reset();
+
+  ScopedVector<UploadElementReader> element_readers;
+  element_readers.push_back(new UploadBytesElementReader("foo", 3));
+  UploadDataStream upload_data_stream(element_readers.Pass(), 0);
+
+  HttpRequestInfo request2;
+  request2.method = "POST";
+  request2.url = GURL("http://www.foo.com/");
+  request2.upload_data_stream = &upload_data_stream;
+  request2.load_flags = 0;
+
+  scoped_ptr<HttpTransaction> trans2(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+  rv = trans2->Start(&request2, callback.callback(), BoundNetLog());
+  EXPECT_EQ(ERR_IO_PENDING, rv);
+
+  rv = callback.WaitForResult();
+  EXPECT_EQ(OK, rv);
+
+  const HttpResponseInfo* response2 = trans2->GetResponseInfo();
+  ASSERT_TRUE(response2 != NULL);
+
+  EXPECT_TRUE(response2->headers.get() != NULL);
+  EXPECT_EQ("HTTP/1.1 400 Not OK", response2->headers->GetStatusLine());
+
+  std::string response_data2;
+  rv = ReadTransaction(trans2.get(), &response_data2);
+  EXPECT_EQ(OK, rv);
+  EXPECT_EQ("second response", response_data2);
+}
+
+TEST_P(HttpNetworkTransactionTest,
+       PostReadsErrorResponseAfterResetPartialBodySent) {
+  ScopedVector<UploadElementReader> element_readers;
+  element_readers.push_back(new UploadBytesElementReader("foo", 3));
+  UploadDataStream upload_data_stream(element_readers.Pass(), 0);
+
+  HttpRequestInfo request;
+  request.method = "POST";
+  request.url = GURL("http://www.foo.com/");
+  request.upload_data_stream = &upload_data_stream;
+  request.load_flags = 0;
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+  // Send headers successfully, but get an error while sending the body.
+  MockWrite data_writes[] = {
+    MockWrite("POST / HTTP/1.1\r\n"
+              "Host: www.foo.com\r\n"
+              "Connection: keep-alive\r\n"
+              "Content-Length: 3\r\n\r\n"
+              "fo"),
+    MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
+  };
+
+  MockRead data_reads[] = {
+    MockRead("HTTP/1.0 400 Not OK\r\n\r\n"),
+    MockRead("hello world"),
+    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);
+
+  EXPECT_TRUE(response->headers.get() != NULL);
+  EXPECT_EQ("HTTP/1.0 400 Not 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 tests the more common case than the previous test, where headers and
+// body are not merged into a single request.
+TEST_P(HttpNetworkTransactionTest, ChunkedPostReadsErrorResponseAfterReset) {
+  ScopedVector<UploadElementReader> element_readers;
+  element_readers.push_back(new UploadBytesElementReader("foo", 3));
+  UploadDataStream upload_data_stream(UploadDataStream::CHUNKED, 0);
+
+  HttpRequestInfo request;
+  request.method = "POST";
+  request.url = GURL("http://www.foo.com/");
+  request.upload_data_stream = &upload_data_stream;
+  request.load_flags = 0;
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+  // Send headers successfully, but get an error while sending the body.
+  MockWrite data_writes[] = {
+    MockWrite("POST / HTTP/1.1\r\n"
+              "Host: www.foo.com\r\n"
+              "Connection: keep-alive\r\n"
+              "Transfer-Encoding: chunked\r\n\r\n"),
+    MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
+  };
+
+  MockRead data_reads[] = {
+    MockRead("HTTP/1.0 400 Not OK\r\n\r\n"),
+    MockRead("hello world"),
+    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);
+  // Make sure the headers are sent before adding a chunk.  This ensures that
+  // they can't be merged with the body in a single send.  Not currently
+  // necessary since a chunked body is never merged with headers, but this makes
+  // the test more future proof.
+  base::RunLoop().RunUntilIdle();
+
+  upload_data_stream.AppendChunk("last chunk", 10, true);
+
+  rv = callback.WaitForResult();
+  EXPECT_EQ(OK, rv);
+
+  const HttpResponseInfo* response = trans->GetResponseInfo();
+  ASSERT_TRUE(response != NULL);
+
+  EXPECT_TRUE(response->headers.get() != NULL);
+  EXPECT_EQ("HTTP/1.0 400 Not 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_P(HttpNetworkTransactionTest, PostReadsErrorResponseAfterResetAnd100) {
+  ScopedVector<UploadElementReader> element_readers;
+  element_readers.push_back(new UploadBytesElementReader("foo", 3));
+  UploadDataStream upload_data_stream(element_readers.Pass(), 0);
+
+  HttpRequestInfo request;
+  request.method = "POST";
+  request.url = GURL("http://www.foo.com/");
+  request.upload_data_stream = &upload_data_stream;
+  request.load_flags = 0;
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+
+  MockWrite data_writes[] = {
+    MockWrite("POST / HTTP/1.1\r\n"
+              "Host: www.foo.com\r\n"
+              "Connection: keep-alive\r\n"
+              "Content-Length: 3\r\n\r\n"),
+    MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
+  };
+
+  MockRead data_reads[] = {
+    MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
+    MockRead("HTTP/1.0 400 Not OK\r\n\r\n"),
+    MockRead("hello world"),
+    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);
+
+  EXPECT_TRUE(response->headers.get() != NULL);
+  EXPECT_EQ("HTTP/1.0 400 Not 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_P(HttpNetworkTransactionTest, PostIgnoresNonErrorResponseAfterReset) {
+  ScopedVector<UploadElementReader> element_readers;
+  element_readers.push_back(new UploadBytesElementReader("foo", 3));
+  UploadDataStream upload_data_stream(element_readers.Pass(), 0);
+
+  HttpRequestInfo request;
+  request.method = "POST";
+  request.url = GURL("http://www.foo.com/");
+  request.upload_data_stream = &upload_data_stream;
+  request.load_flags = 0;
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+  // Send headers successfully, but get an error while sending the body.
+  MockWrite data_writes[] = {
+    MockWrite("POST / HTTP/1.1\r\n"
+              "Host: www.foo.com\r\n"
+              "Connection: keep-alive\r\n"
+              "Content-Length: 3\r\n\r\n"),
+    MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
+  };
+
+  MockRead data_reads[] = {
+    MockRead("HTTP/1.0 200 Just Dandy\r\n\r\n"),
+    MockRead("hello world"),
+    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(ERR_CONNECTION_RESET, rv);
+
+  const HttpResponseInfo* response = trans->GetResponseInfo();
+  EXPECT_TRUE(response == NULL);
+}
+
+TEST_P(HttpNetworkTransactionTest,
+       PostIgnoresNonErrorResponseAfterResetAnd100) {
+  ScopedVector<UploadElementReader> element_readers;
+  element_readers.push_back(new UploadBytesElementReader("foo", 3));
+  UploadDataStream upload_data_stream(element_readers.Pass(), 0);
+
+  HttpRequestInfo request;
+  request.method = "POST";
+  request.url = GURL("http://www.foo.com/");
+  request.upload_data_stream = &upload_data_stream;
+  request.load_flags = 0;
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+  // Send headers successfully, but get an error while sending the body.
+  MockWrite data_writes[] = {
+    MockWrite("POST / HTTP/1.1\r\n"
+              "Host: www.foo.com\r\n"
+              "Connection: keep-alive\r\n"
+              "Content-Length: 3\r\n\r\n"),
+    MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
+  };
+
+  MockRead data_reads[] = {
+    MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
+    MockRead("HTTP/1.0 302 Redirect\r\n"),
+    MockRead("Location: http://somewhere-else.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));
+  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);
+}
+
+TEST_P(HttpNetworkTransactionTest, PostIgnoresHttp09ResponseAfterReset) {
+  ScopedVector<UploadElementReader> element_readers;
+  element_readers.push_back(new UploadBytesElementReader("foo", 3));
+  UploadDataStream upload_data_stream(element_readers.Pass(), 0);
+
+  HttpRequestInfo request;
+  request.method = "POST";
+  request.url = GURL("http://www.foo.com/");
+  request.upload_data_stream = &upload_data_stream;
+  request.load_flags = 0;
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+  // Send headers successfully, but get an error while sending the body.
+  MockWrite data_writes[] = {
+    MockWrite("POST / HTTP/1.1\r\n"
+              "Host: www.foo.com\r\n"
+              "Connection: keep-alive\r\n"
+              "Content-Length: 3\r\n\r\n"),
+    MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
+  };
+
+  MockRead data_reads[] = {
+    MockRead("HTTP 0.9 rocks!"),
+    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(ERR_CONNECTION_RESET, rv);
+
+  const HttpResponseInfo* response = trans->GetResponseInfo();
+  EXPECT_TRUE(response == NULL);
+}
+
+TEST_P(HttpNetworkTransactionTest, PostIgnoresPartial400HeadersAfterReset) {
+  ScopedVector<UploadElementReader> element_readers;
+  element_readers.push_back(new UploadBytesElementReader("foo", 3));
+  UploadDataStream upload_data_stream(element_readers.Pass(), 0);
+
+  HttpRequestInfo request;
+  request.method = "POST";
+  request.url = GURL("http://www.foo.com/");
+  request.upload_data_stream = &upload_data_stream;
+  request.load_flags = 0;
+
+  scoped_refptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+  scoped_ptr<HttpTransaction> trans(
+      new HttpNetworkTransaction(DEFAULT_PRIORITY, session));
+  // Send headers successfully, but get an error while sending the body.
+  MockWrite data_writes[] = {
+    MockWrite("POST / HTTP/1.1\r\n"
+              "Host: www.foo.com\r\n"
+              "Connection: keep-alive\r\n"
+              "Content-Length: 3\r\n\r\n"),
+    MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
+  };
+
+  MockRead data_reads[] = {
+    MockRead("HTTP/1.0 400 Not a Full Response\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(ERR_CONNECTION_RESET, rv);
+
+  const HttpResponseInfo* response = trans->GetResponseInfo();
+  EXPECT_TRUE(response == NULL);
+}
+
 }  // namespace net