Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / net / http / http_network_transaction_unittest.cc
index ca06785..e3d3a59 100644 (file)
@@ -409,8 +409,7 @@ INSTANTIATE_TEST_CASE_P(
     NextProto,
     HttpNetworkTransactionTest,
     testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
-                    kProtoHTTP2Draft04));
+                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
 
 namespace {
 
@@ -3388,23 +3387,15 @@ 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",
-  };
+  SpdySynStreamIR connect2_ir(3);
+  spdy_util_.SetPriority(LOWEST, &connect2_ir);
+  connect2_ir.SetHeader(spdy_util_.GetMethodKey(), "CONNECT");
+  connect2_ir.SetHeader(spdy_util_.GetPathKey(), "news.google.com:443");
+  connect2_ir.SetHeader(spdy_util_.GetHostKey(), "news.google.com");
+  spdy_util_.MaybeAddVersionHeader(&connect2_ir);
   scoped_ptr<SpdyFrame> connect2(
-      spdy_util_.ConstructSpdyControlFrame(NULL,
-                                           0,
-                                           /*compressed*/ false,
-                                           3,
-                                           LOWEST,
-                                           SYN_STREAM,
-                                           CONTROL_FLAG_NONE,
-                                           kConnectHeaders2,
-                                           arraysize(kConnectHeaders2),
-                                           0));
+      spdy_util_.CreateFramer(false)->SerializeFrame(connect2_ir));
+
   scoped_ptr<SpdyFrame> conn_resp2(
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
 
@@ -3959,6 +3950,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"));
 }
@@ -9218,7 +9213,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());
 
@@ -10377,7 +10372,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());
 
@@ -11277,20 +11272,21 @@ 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).
+  SpdySynStreamIR req2_ir(3);
+  spdy_util_.SetPriority(MEDIUM, &req2_ir);
+  req2_ir.set_fin(true);
+  req2_ir.SetHeader(spdy_util_.GetMethodKey(), "GET");
+  req2_ir.SetHeader(spdy_util_.GetPathKey(),
+                    spdy_util_.is_spdy2() ? http_url.c_str() : "/");
+  req2_ir.SetHeader(spdy_util_.GetHostKey(), "www.google.com:443");
+  req2_ir.SetHeader(spdy_util_.GetSchemeKey(), "http");
+  spdy_util_.MaybeAddVersionHeader(&req2_ir);
+  scoped_ptr<SpdyFrame> req2(
+      spdy_util_.CreateFramer(false)->SerializeFrame(req2_ir));
 
   MockWrite writes1[] = {
     CreateMockWrite(*connect, 0),
@@ -11735,7 +11731,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));
 
@@ -11767,7 +11763,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;
@@ -11795,7 +11791,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;
@@ -12613,4 +12609,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