Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / net / spdy / spdy_network_transaction_unittest.cc
index f488ff7..59a2f1b 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/file_util.h"
+#include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/scoped_vector.h"
 #include "base/run_loop.h"
@@ -23,7 +23,7 @@
 #include "net/http/http_network_session_peer.h"
 #include "net/http/http_network_transaction.h"
 #include "net/http/http_server_properties.h"
-#include "net/http/http_transaction_unittest.h"
+#include "net/http/http_transaction_test_util.h"
 #include "net/socket/client_socket_pool_base.h"
 #include "net/socket/next_proto.h"
 #include "net/spdy/buffered_spdy_framer.h"
@@ -33,6 +33,7 @@
 #include "net/spdy/spdy_session_pool.h"
 #include "net/spdy/spdy_test_util_common.h"
 #include "net/spdy/spdy_test_utils.h"
+#include "net/ssl/ssl_connection_status_flags.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/platform_test.h"
@@ -69,15 +70,45 @@ struct SpdyNetworkTransactionTestParams {
   SpdyNetworkTransactionTestSSLType ssl_type;
 };
 
+void UpdateSpdySessionDependencies(
+    SpdyNetworkTransactionTestParams test_params,
+    SpdySessionDependencies* session_deps) {
+  switch (test_params.ssl_type) {
+    case SPDYNPN:
+      session_deps->http_server_properties.SetAlternateProtocol(
+          HostPortPair("www.google.com", 80), 443,
+          AlternateProtocolFromNextProto(test_params.protocol), 1);
+      session_deps->use_alternate_protocols = true;
+      session_deps->next_protos = SpdyNextProtos();
+      break;
+    case SPDYNOSSL:
+      session_deps->force_spdy_over_ssl = false;
+      session_deps->force_spdy_always = true;
+      break;
+    case SPDYSSL:
+      session_deps->force_spdy_over_ssl = true;
+      session_deps->force_spdy_always = true;
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
 SpdySessionDependencies* CreateSpdySessionDependencies(
     SpdyNetworkTransactionTestParams test_params) {
-  return new SpdySessionDependencies(test_params.protocol);
+  SpdySessionDependencies* session_deps =
+      new SpdySessionDependencies(test_params.protocol);
+  UpdateSpdySessionDependencies(test_params, session_deps);
+  return session_deps;
 }
 
 SpdySessionDependencies* CreateSpdySessionDependencies(
     SpdyNetworkTransactionTestParams test_params,
     ProxyService* proxy_service) {
-  return new SpdySessionDependencies(test_params.protocol, proxy_service);
+  SpdySessionDependencies* session_deps =
+      new SpdySessionDependencies(test_params.protocol, proxy_service);
+  UpdateSpdySessionDependencies(test_params, session_deps);
+  return session_deps;
 }
 
 }  // namespace
@@ -86,25 +117,20 @@ class SpdyNetworkTransactionTest
     : public ::testing::TestWithParam<SpdyNetworkTransactionTestParams> {
  protected:
   SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol) {
-    LOG(INFO) << __FUNCTION__;
   }
 
   virtual ~SpdyNetworkTransactionTest() {
-    LOG(INFO) << __FUNCTION__;
     // UploadDataStream posts deletion tasks back to the message loop on
     // destruction.
     upload_data_stream_.reset();
     base::RunLoop().RunUntilIdle();
-    LOG(INFO) << __FUNCTION__;
   }
 
   virtual void SetUp() {
-    LOG(INFO) << __FUNCTION__;
     google_get_request_initialized_ = false;
     google_post_request_initialized_ = false;
     google_chunked_post_request_initialized_ = false;
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    LOG(INFO) << __FUNCTION__;
   }
 
   struct TransactionHelperResult {
@@ -170,54 +196,26 @@ class SpdyNetworkTransactionTest
     }
 
     void RunPreTestSetup() {
-      LOG(INFO) << __FUNCTION__;
       if (!session_deps_.get())
         session_deps_.reset(CreateSpdySessionDependencies(test_params_));
-      if (!session_.get())
+      if (!session_.get()) {
         session_ = SpdySessionDependencies::SpdyCreateSession(
             session_deps_.get());
-      HttpStreamFactory::set_use_alternate_protocols(false);
-      HttpStreamFactory::set_force_spdy_over_ssl(false);
-      HttpStreamFactory::set_force_spdy_always(false);
-
-      std::vector<NextProto> next_protos = SpdyNextProtos();
-
-      switch (test_params_.ssl_type) {
-        case SPDYNPN:
-          session_->http_server_properties()->SetAlternateProtocol(
-              HostPortPair("www.google.com", 80), 443,
-              AlternateProtocolFromNextProto(test_params_.protocol));
-          HttpStreamFactory::set_use_alternate_protocols(true);
-          HttpStreamFactory::SetNextProtos(next_protos);
-          break;
-        case SPDYNOSSL:
-          HttpStreamFactory::set_force_spdy_over_ssl(false);
-          HttpStreamFactory::set_force_spdy_always(true);
-          break;
-        case SPDYSSL:
-          HttpStreamFactory::set_force_spdy_over_ssl(true);
-          HttpStreamFactory::set_force_spdy_always(true);
-          break;
-        default:
-          NOTREACHED();
       }
 
       // We're now ready to use SSL-npn SPDY.
       trans_.reset(new HttpNetworkTransaction(priority_, session_.get()));
-      LOG(INFO) << __FUNCTION__;
     }
 
     // Start the transaction, read some data, finish.
     void RunDefaultTest() {
-      LOG(INFO) << __FUNCTION__;
       if (!StartDefaultTest())
         return;
       FinishDefaultTest();
-      LOG(INFO) << __FUNCTION__;
     }
 
     bool StartDefaultTest() {
-      output_.rv = trans_->Start(&request_, callback.callback(), log_);
+      output_.rv = trans_->Start(&request_, callback_.callback(), log_);
 
       // We expect an IO Pending or some sort of error.
       EXPECT_LT(output_.rv, 0);
@@ -225,7 +223,7 @@ class SpdyNetworkTransactionTest
     }
 
     void FinishDefaultTest() {
-      output_.rv = callback.WaitForResult();
+      output_.rv = callback_.WaitForResult();
       if (output_.rv != OK) {
         session_->spdy_session_pool()->CloseCurrentSessions(net::ERR_ABORTED);
         return;
@@ -305,17 +303,35 @@ class SpdyNetworkTransactionTest
       VerifyDataConsumed();
     }
 
+    void RunToCompletionWithSSLData(
+        StaticSocketDataProvider* data,
+        scoped_ptr<SSLSocketDataProvider> ssl_provider) {
+      RunPreTestSetup();
+      AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass());
+      RunDefaultTest();
+      VerifyDataConsumed();
+    }
+
     void AddData(StaticSocketDataProvider* data) {
+      scoped_ptr<SSLSocketDataProvider> ssl_provider(
+          new SSLSocketDataProvider(ASYNC, OK));
+      AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass());
+    }
+
+    void AddDataWithSSLSocketDataProvider(
+        StaticSocketDataProvider* data,
+        scoped_ptr<SSLSocketDataProvider> ssl_provider) {
       DCHECK(!deterministic_);
       data_vector_.push_back(data);
-      SSLSocketDataProvider* ssl_provider =
-          new SSLSocketDataProvider(ASYNC, OK);
       if (test_params_.ssl_type == SPDYNPN)
         ssl_provider->SetNextProto(test_params_.protocol);
 
-      ssl_vector_.push_back(ssl_provider);
-      if (test_params_.ssl_type == SPDYNPN || test_params_.ssl_type == SPDYSSL)
-        session_deps_->socket_factory->AddSSLSocketDataProvider(ssl_provider);
+      if (test_params_.ssl_type == SPDYNPN ||
+          test_params_.ssl_type == SPDYSSL) {
+        session_deps_->socket_factory->AddSSLSocketDataProvider(
+            ssl_provider.get());
+      }
+      ssl_vector_.push_back(ssl_provider.release());
 
       session_deps_->socket_factory->AddSocketDataProvider(data);
       if (test_params_.ssl_type == SPDYNPN) {
@@ -388,7 +404,7 @@ class SpdyNetworkTransactionTest
     TransactionHelperResult output_;
     scoped_ptr<StaticSocketDataProvider> first_transaction_;
     SSLVector ssl_vector_;
-    TestCompletionCallback callback;
+    TestCompletionCallback callback_;
     scoped_ptr<HttpNetworkTransaction> trans_;
     scoped_ptr<HttpNetworkTransaction> trans_http_;
     DataVector data_vector_;
@@ -483,7 +499,7 @@ class SpdyNetworkTransactionTest
     CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
     CHECK_EQ(static_cast<int>(kUploadDataSize),
              base::WriteFile(file_path, kUploadData, kUploadDataSize));
-    CHECK(file_util::MakeFileUnreadable(file_path));
+    CHECK(base::MakeFileUnreadable(file_path));
 
     ScopedVector<UploadElementReader> element_readers;
     element_readers.push_back(
@@ -588,7 +604,7 @@ class SpdyNetworkTransactionTest
     int port = helper.test_params().ssl_type == SPDYNPN ? 443 : 80;
     HostPortPair host_port_pair(url.host(), port);
     SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
-                       kPrivacyModeDisabled);
+                       PRIVACY_MODE_DISABLED);
     BoundNetLog log;
     const scoped_refptr<HttpNetworkSession>& session = helper.session();
     base::WeakPtr<SpdySession> spdy_session =
@@ -705,29 +721,21 @@ INSTANTIATE_TEST_CASE_P(
         SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNOSSL),
         SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYSSL),
         SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN),
-        SpdyNetworkTransactionTestParams(kProtoSPDY4a2, SPDYNOSSL),
-        SpdyNetworkTransactionTestParams(kProtoSPDY4a2, SPDYSSL),
-        SpdyNetworkTransactionTestParams(kProtoSPDY4a2, SPDYNPN),
-        SpdyNetworkTransactionTestParams(kProtoHTTP2Draft04, SPDYNOSSL),
-        SpdyNetworkTransactionTestParams(kProtoHTTP2Draft04, SPDYSSL),
-        SpdyNetworkTransactionTestParams(kProtoHTTP2Draft04, SPDYNPN)));
+        SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNOSSL),
+        SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYSSL),
+        SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNPN)));
 
 // Verify HttpNetworkTransaction constructor.
 TEST_P(SpdyNetworkTransactionTest, Constructor) {
-  LOG(INFO) << __FUNCTION__;
   scoped_ptr<SpdySessionDependencies> session_deps(
       CreateSpdySessionDependencies(GetParam()));
-  LOG(INFO) << __FUNCTION__;
   scoped_refptr<HttpNetworkSession> session(
       SpdySessionDependencies::SpdyCreateSession(session_deps.get()));
-  LOG(INFO) << __FUNCTION__;
   scoped_ptr<HttpTransaction> trans(
       new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get()));
-  LOG(INFO) << __FUNCTION__;
 }
 
 TEST_P(SpdyNetworkTransactionTest, Get) {
-  LOG(INFO) << __FUNCTION__;
   // Construct the request.
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
@@ -1080,9 +1088,7 @@ TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
   helper.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config);
   HttpStreamFactory* http_stream_factory =
       helper.session()->http_stream_factory();
-  if (http_stream_factory->has_next_protos()) {
-    preconnect_ssl_config.next_protos = http_stream_factory->next_protos();
-  }
+  helper.session()->GetNextProtos(&preconnect_ssl_config.next_protos);
 
   http_stream_factory->PreconnectStreams(
       1, httpreq, DEFAULT_PRIORITY,
@@ -1152,9 +1158,11 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
       SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
   scoped_ptr<SpdyFrame> settings_frame(
       spdy_util_.ConstructSpdySettings(settings));
+  scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
 
   MockWrite writes[] = {
     CreateMockWrite(*req),
+    CreateMockWrite(*settings_ack, 2),
     CreateMockWrite(*req2),
     CreateMockWrite(*req3),
   };
@@ -1164,10 +1172,10 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
     CreateMockRead(*resp),
     CreateMockRead(*body),
     CreateMockRead(*fbody),
-    CreateMockRead(*resp2, 7),
+    CreateMockRead(*resp2, 8),
     CreateMockRead(*body2),
     CreateMockRead(*fbody2),
-    CreateMockRead(*resp3, 12),
+    CreateMockRead(*resp3, 13),
     CreateMockRead(*body3),
     CreateMockRead(*fbody3),
 
@@ -1290,8 +1298,10 @@ TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
       SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
   scoped_ptr<SpdyFrame> settings_frame(
       spdy_util_.ConstructSpdySettings(settings));
+  scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
 
   MockWrite writes[] = { CreateMockWrite(*req),
+    CreateMockWrite(*settings_ack, 2),
     CreateMockWrite(*req2),
     CreateMockWrite(*req4),
     CreateMockWrite(*req3),
@@ -1301,12 +1311,12 @@ TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
     CreateMockRead(*resp),
     CreateMockRead(*body),
     CreateMockRead(*fbody),
-    CreateMockRead(*resp2, 7),
+    CreateMockRead(*resp2, 8),
     CreateMockRead(*body2),
     CreateMockRead(*fbody2),
-    CreateMockRead(*resp4, 13),
+    CreateMockRead(*resp4, 14),
     CreateMockRead(*fbody4),
-    CreateMockRead(*resp3, 16),
+    CreateMockRead(*resp3, 17),
     CreateMockRead(*body3),
     CreateMockRead(*fbody3),
 
@@ -1432,8 +1442,11 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
       SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
   scoped_ptr<SpdyFrame> settings_frame(
       spdy_util_.ConstructSpdySettings(settings));
+  scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
 
-  MockWrite writes[] = { CreateMockWrite(*req),
+  MockWrite writes[] = {
+    CreateMockWrite(*req),
+    CreateMockWrite(*settings_ack, 2),
     CreateMockWrite(*req2),
   };
   MockRead reads[] = {
@@ -1441,7 +1454,7 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
     CreateMockRead(*resp),
     CreateMockRead(*body),
     CreateMockRead(*fbody),
-    CreateMockRead(*resp2, 7),
+    CreateMockRead(*resp2, 8),
     CreateMockRead(*body2),
     CreateMockRead(*fbody2),
     MockRead(ASYNC, 0, 0),  // EOF
@@ -1566,8 +1579,11 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
       SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams);
   scoped_ptr<SpdyFrame> settings_frame(
       spdy_util_.ConstructSpdySettings(settings));
+  scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
 
-  MockWrite writes[] = { CreateMockWrite(*req),
+  MockWrite writes[] = {
+    CreateMockWrite(*req),
+    CreateMockWrite(*settings_ack, 2),
     CreateMockWrite(*req2),
   };
   MockRead reads[] = {
@@ -1575,7 +1591,7 @@ TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
     CreateMockRead(*resp),
     CreateMockRead(*body),
     CreateMockRead(*fin_body),
-    CreateMockRead(*resp2, 7),
+    CreateMockRead(*resp2, 8),
     MockRead(ASYNC, ERR_CONNECTION_RESET, 0),  // Abort!
   };
 
@@ -1647,49 +1663,16 @@ TEST_P(SpdyNetworkTransactionTest, Put) {
   request.method = "PUT";
   request.url = GURL("http://www.google.com/");
 
-  const SpdyHeaderInfo kSynStartHeader = {
-    SYN_STREAM,             // Kind = Syn
-    1,                      // Stream ID
-    0,                      // Associated stream ID
-    ConvertRequestPriorityToSpdyPriority(
-        LOWEST, spdy_util_.spdy_version()),
-    kSpdyCredentialSlotUnused,
-    CONTROL_FLAG_FIN,       // Control Flags
-    false,                  // Compressed
-    RST_STREAM_INVALID,     // Status
-    NULL,                   // Data
-    0,                      // Length
-    DATA_FLAG_NONE          // Data Flags
-  };
   scoped_ptr<SpdyHeaderBlock> put_headers(
       spdy_util_.ConstructPutHeaderBlock("http://www.google.com", 0));
-  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyFrame(
-      kSynStartHeader, put_headers.Pass()));
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdySyn(1, *put_headers, LOWEST, false, true));
   MockWrite writes[] = {
     CreateMockWrite(*req),
   };
 
+  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
-  const SpdyHeaderInfo kSynReplyHeader = {
-    SYN_REPLY,              // Kind = SynReply
-    1,                      // Stream ID
-    0,                      // Associated stream ID
-    ConvertRequestPriorityToSpdyPriority(
-        LOWEST, spdy_util_.spdy_version()),
-    kSpdyCredentialSlotUnused,
-    CONTROL_FLAG_NONE,      // Control Flags
-    false,                  // Compressed
-    RST_STREAM_INVALID,     // Status
-    NULL,                   // Data
-    0,                      // Length
-    DATA_FLAG_NONE          // Data Flags
-  };
-  scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
-  (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
-  (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
-  (*reply_headers)["content-length"] = "1234";
-  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyFrame(
-      kSynReplyHeader, reply_headers.Pass()));
   MockRead reads[] = {
     CreateMockRead(*resp),
     CreateMockRead(*body),
@@ -1714,50 +1697,16 @@ TEST_P(SpdyNetworkTransactionTest, Head) {
   request.method = "HEAD";
   request.url = GURL("http://www.google.com/");
 
-  const SpdyHeaderInfo kSynStartHeader = {
-    SYN_STREAM,             // Kind = Syn
-    1,                      // Stream ID
-    0,                      // Associated stream ID
-    ConvertRequestPriorityToSpdyPriority(
-        LOWEST, spdy_util_.spdy_version()),
-    kSpdyCredentialSlotUnused,
-    CONTROL_FLAG_FIN,       // Control Flags
-    false,                  // Compressed
-    RST_STREAM_INVALID,     // Status
-    NULL,                   // Data
-    0,                      // Length
-    DATA_FLAG_NONE          // Data Flags
-  };
   scoped_ptr<SpdyHeaderBlock> head_headers(
       spdy_util_.ConstructHeadHeaderBlock("http://www.google.com", 0));
-  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyFrame(
-      kSynStartHeader, head_headers.Pass()));
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdySyn(1, *head_headers, LOWEST, false, true));
   MockWrite writes[] = {
     CreateMockWrite(*req),
   };
 
+  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
-  const SpdyHeaderInfo kSynReplyHeader = {
-    SYN_REPLY,              // Kind = SynReply
-    1,                      // Stream ID
-    0,                      // Associated stream ID
-    ConvertRequestPriorityToSpdyPriority(
-        LOWEST, spdy_util_.spdy_version()),
-    kSpdyCredentialSlotUnused,
-    CONTROL_FLAG_NONE,      // Control Flags
-    false,                  // Compressed
-    RST_STREAM_INVALID,     // Status
-    NULL,                   // Data
-    0,                      // Length
-    DATA_FLAG_NONE          // Data Flags
-  };
-  scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock());
-  (*reply_headers)[spdy_util_.GetStatusKey()] = "200";
-  (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
-  (*reply_headers)["content-length"] = "1234";
-  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyFrame(
-      kSynReplyHeader,
-      reply_headers.Pass()));
   MockRead reads[] = {
     CreateMockRead(*resp),
     CreateMockRead(*body),
@@ -1989,13 +1938,10 @@ TEST_P(SpdyNetworkTransactionTest, NullPost) {
 
   // When request.upload_data_stream is NULL for post, content-length is
   // expected to be 0.
-  SpdySynStreamIR syn_ir(1);
-  syn_ir.set_name_value_block(
-      *spdy_util_.ConstructPostHeaderBlock(kRequestUrl, 0));
-  syn_ir.set_fin(true);  // No body.
-  syn_ir.set_priority(ConvertRequestPriorityToSpdyPriority(
-      LOWEST, spdy_util_.spdy_version()));
-  scoped_ptr<SpdyFrame> req(framer.SerializeFrame(syn_ir));
+  scoped_ptr<SpdyHeaderBlock> req_block(
+      spdy_util_.ConstructPostHeaderBlock(kRequestUrl, 0));
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true));
 
   MockWrite writes[] = {
     CreateMockWrite(*req),
@@ -2036,13 +1982,10 @@ TEST_P(SpdyNetworkTransactionTest, EmptyPost) {
 
   const uint64 kContentLength = 0;
 
-  SpdySynStreamIR syn_ir(1);
-  syn_ir.set_name_value_block(
-      *spdy_util_.ConstructPostHeaderBlock(kRequestUrl, kContentLength));
-  syn_ir.set_fin(true);  // No body.
-  syn_ir.set_priority(ConvertRequestPriorityToSpdyPriority(
-      LOWEST, spdy_util_.spdy_version()));
-  scoped_ptr<SpdyFrame> req(framer.SerializeFrame(syn_ir));
+  scoped_ptr<SpdyHeaderBlock> req_block(
+      spdy_util_.ConstructPostHeaderBlock(kRequestUrl, kContentLength));
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true));
 
   MockWrite writes[] = {
     CreateMockWrite(*req),
@@ -2493,21 +2436,20 @@ TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
 
 // Send a spdy request to www.google.com that gets redirected to www.foo.com.
 TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) {
-  const SpdyHeaderInfo kSynStartHeader = spdy_util_.MakeSpdyHeader(SYN_STREAM);
   scoped_ptr<SpdyHeaderBlock> headers(
       spdy_util_.ConstructGetHeaderBlock("http://www.google.com/"));
   (*headers)["user-agent"] = "";
-  (*headers)["accept-encoding"] = "gzip,deflate";
+  (*headers)["accept-encoding"] = "gzip, deflate";
   scoped_ptr<SpdyHeaderBlock> headers2(
       spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
   (*headers2)["user-agent"] = "";
-  (*headers2)["accept-encoding"] = "gzip,deflate";
+  (*headers2)["accept-encoding"] = "gzip, deflate";
 
   // Setup writes/reads to www.google.com
-  scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyFrame(
-      kSynStartHeader, headers.Pass()));
-  scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyFrame(
-      kSynStartHeader, headers2.Pass()));
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true));
+  scoped_ptr<SpdyFrame> req2(
+      spdy_util_.ConstructSpdySyn(1, *headers2, LOWEST, false, true));
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReplyRedirect(1));
   MockWrite writes[] = {
     CreateMockWrite(*req, 1),
@@ -2534,31 +2476,33 @@ TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) {
                           writes2, arraysize(writes2));
 
   // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
-  HttpStreamFactory::set_force_spdy_over_ssl(false);
-  HttpStreamFactory::set_force_spdy_always(true);
   TestDelegate d;
   {
-    SpdyURLRequestContext spdy_url_request_context(GetParam().protocol);
-    net::URLRequest r(GURL("http://www.google.com/"),
-                      DEFAULT_PRIORITY,
-                      &d,
-                      &spdy_url_request_context);
+    SpdyURLRequestContext spdy_url_request_context(
+        GetParam().protocol,
+        false  /* force_spdy_over_ssl*/,
+        true  /* force_spdy_always */);
+    scoped_ptr<URLRequest> r(
+        spdy_url_request_context.CreateRequest(GURL("http://www.google.com/"),
+                                               DEFAULT_PRIORITY,
+                                               &d,
+                                               NULL));
     spdy_url_request_context.socket_factory().
         AddSocketDataProvider(&data);
     spdy_url_request_context.socket_factory().
         AddSocketDataProvider(&data2);
 
     d.set_quit_on_redirect(true);
-    r.Start();
+    r->Start();
     base::RunLoop().Run();
 
     EXPECT_EQ(1, d.received_redirect_count());
 
-    r.FollowDeferredRedirect();
+    r->FollowDeferredRedirect();
     base::RunLoop().Run();
     EXPECT_EQ(1, d.response_started_count());
     EXPECT_FALSE(d.received_data_before_response());
-    EXPECT_EQ(net::URLRequestStatus::SUCCESS, r.status().status());
+    EXPECT_EQ(net::URLRequestStatus::SUCCESS, r->status().status());
     std::string contents("hello!");
     EXPECT_EQ(contents, d.data_received());
   }
@@ -2571,16 +2515,14 @@ TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) {
 // Send a spdy request to www.google.com. Get a pushed stream that redirects to
 // www.foo.com.
 TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) {
-  const SpdyHeaderInfo kSynStartHeader = spdy_util_.MakeSpdyHeader(SYN_STREAM);
-
   scoped_ptr<SpdyHeaderBlock> headers(
       spdy_util_.ConstructGetHeaderBlock("http://www.google.com/"));
   (*headers)["user-agent"] = "";
-  (*headers)["accept-encoding"] = "gzip,deflate";
+  (*headers)["accept-encoding"] = "gzip, deflate";
 
   // Setup writes/reads to www.google.com
   scoped_ptr<SpdyFrame> req(
-      spdy_util_.ConstructSpdyFrame(kSynStartHeader, headers.Pass()));
+      spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true));
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> rep(
       spdy_util_.ConstructSpdyPush(NULL,
@@ -2609,9 +2551,9 @@ TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) {
   scoped_ptr<SpdyHeaderBlock> headers2(
       spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
   (*headers2)["user-agent"] = "";
-  (*headers2)["accept-encoding"] = "gzip,deflate";
+  (*headers2)["accept-encoding"] = "gzip, deflate";
   scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyFrame(kSynStartHeader, headers2.Pass()));
+      spdy_util_.ConstructSpdySyn(1, *headers2, LOWEST, false, true));
   scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes2[] = {
@@ -2628,43 +2570,47 @@ TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) {
                           writes2, arraysize(writes2));
 
   // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
-  HttpStreamFactory::set_force_spdy_over_ssl(false);
-  HttpStreamFactory::set_force_spdy_always(true);
   TestDelegate d;
   TestDelegate d2;
-  SpdyURLRequestContext spdy_url_request_context(GetParam().protocol);
+  SpdyURLRequestContext spdy_url_request_context(
+      GetParam().protocol,
+      false  /* force_spdy_over_ssl*/,
+      true  /* force_spdy_always */);
   {
-    net::URLRequest r(GURL("http://www.google.com/"),
-                      DEFAULT_PRIORITY,
-                      &d,
-                      &spdy_url_request_context);
+    scoped_ptr<URLRequest> r(
+        spdy_url_request_context.CreateRequest(GURL("http://www.google.com/"),
+                                               DEFAULT_PRIORITY,
+                                               &d,
+                                               NULL));
     spdy_url_request_context.socket_factory().
         AddSocketDataProvider(&data);
 
-    r.Start();
+    r->Start();
     base::RunLoop().Run();
 
     EXPECT_EQ(0, d.received_redirect_count());
     std::string contents("hello!");
     EXPECT_EQ(contents, d.data_received());
 
-    net::URLRequest r2(GURL("http://www.google.com/foo.dat"),
-                       DEFAULT_PRIORITY,
-                       &d2,
-                       &spdy_url_request_context);
+    scoped_ptr<URLRequest> r2(
+        spdy_url_request_context.CreateRequest(
+            GURL("http://www.google.com/foo.dat"),
+            DEFAULT_PRIORITY,
+            &d2,
+            NULL));
     spdy_url_request_context.socket_factory().
         AddSocketDataProvider(&data2);
 
     d2.set_quit_on_redirect(true);
-    r2.Start();
+    r2->Start();
     base::RunLoop().Run();
     EXPECT_EQ(1, d2.received_redirect_count());
 
-    r2.FollowDeferredRedirect();
+    r2->FollowDeferredRedirect();
     base::RunLoop().Run();
     EXPECT_EQ(1, d2.response_started_count());
     EXPECT_FALSE(d2.received_data_before_response());
-    EXPECT_EQ(net::URLRequestStatus::SUCCESS, r2.status().status());
+    EXPECT_EQ(net::URLRequestStatus::SUCCESS, r2->status().status());
     std::string contents2("hello!");
     EXPECT_EQ(contents2, d2.data_received());
   }
@@ -3059,10 +3005,11 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
 
 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
   if (spdy_util_.spdy_version() == SPDY4) {
-    // TODO(jgraettinger): We don't support associated stream
-    // checks in SPDY4 yet.
+    // PUSH_PROMISE with stream id 0 is connection-level error.
+    // TODO(baranovich): Test session going away.
     return;
   }
+
   scoped_ptr<SpdyFrame> stream1_syn(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> stream1_body(
@@ -3124,11 +3071,6 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
 }
 
 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
-  if (spdy_util_.spdy_version() == SPDY4) {
-    // TODO(jgraettinger): We don't support associated stream
-    // checks in SPDY4 yet.
-    return;
-  }
   scoped_ptr<SpdyFrame> stream1_syn(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> stream1_body(
@@ -3207,15 +3149,8 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushNoURL) {
   (*incomplete_headers)["hello"] = "bye";
   (*incomplete_headers)[spdy_util_.GetStatusKey()] = "200 OK";
   (*incomplete_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
-  scoped_ptr<SpdyFrame> stream2_syn(
-      spdy_util_.ConstructSpdyControlFrame(incomplete_headers.Pass(),
-                                           false,
-                                           2,  // Stream ID
-                                           LOWEST,
-                                           SYN_STREAM,
-                                           CONTROL_FLAG_NONE,
-                                           // Associated stream ID
-                                           1));
+  scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame(
+      incomplete_headers.Pass(), 2, 1));
   MockRead reads[] = {
     CreateMockRead(*stream1_reply, 2),
     CreateMockRead(*stream2_syn, 3),
@@ -3288,16 +3223,20 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) {
   test_cases[0].expected_headers["cookie"] += "val2";
   test_cases[0].expected_headers["hello"] = "bye";
   test_cases[0].expected_headers["status"] = "200";
-  test_cases[0].expected_headers["version"] = "HTTP/1.1";
 
   test_cases[1].expected_headers["hello"] = "bye";
   test_cases[1].expected_headers["status"] = "200";
-  test_cases[1].expected_headers["version"] = "HTTP/1.1";
 
   test_cases[2].expected_headers["cookie"] = "val1,val2";
   test_cases[2].expected_headers["hello"] = "bye";
   test_cases[2].expected_headers["status"] = "200";
-  test_cases[2].expected_headers["version"] = "HTTP/1.1";
+
+  if (spdy_util_.spdy_version() < SPDY4) {
+    // SPDY4/HTTP2 eliminates use of the :version header.
+    test_cases[0].expected_headers["version"] = "HTTP/1.1";
+    test_cases[1].expected_headers["version"] = "HTTP/1.1";
+    test_cases[2].expected_headers["version"] = "HTTP/1.1";
+  }
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
     scoped_ptr<SpdyFrame> req(
@@ -3346,23 +3285,8 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) {
 // Verify that various SynReply headers parse vary fields correctly
 // through the HTTP layer, and the response matches the request.
 TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
-  static const SpdyHeaderInfo syn_reply_info = {
-    SYN_REPLY,                              // Syn Reply
-    1,                                      // Stream ID
-    0,                                      // Associated Stream ID
-    ConvertRequestPriorityToSpdyPriority(
-        LOWEST, spdy_util_.spdy_version()),
-    kSpdyCredentialSlotUnused,
-    CONTROL_FLAG_NONE,                      // Control Flags
-    false,                                  // Compressed
-    RST_STREAM_INVALID,                     // Status
-    NULL,                                   // Data
-    0,                                      // Data Length
-    DATA_FLAG_NONE                          // Data Flags
-  };
   // Modify the following data to change/add test cases:
   struct SynReplyTests {
-    const SpdyHeaderInfo* syn_reply;
     bool vary_matches;
     int num_headers[2];
     const char* extra_headers[2][16];
@@ -3370,7 +3294,6 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
     // Test the case of a multi-valued cookie.  When the value is delimited
     // with NUL characters, it needs to be unfolded into multiple headers.
     {
-      &syn_reply_info,
       true,
       { 1, 4 },
       { { "cookie",   "val1,val2",
@@ -3384,7 +3307,6 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
         }
       }
     }, {    // Multiple vary fields.
-      &syn_reply_info,
       true,
       { 2, 5 },
       { { "friend",   "barney",
@@ -3400,7 +3322,6 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
         }
       }
     }, {    // Test a '*' vary field.
-      &syn_reply_info,
       false,
       { 1, 4 },
       { { "cookie",   "val1,val2",
@@ -3414,7 +3335,6 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
         }
       }
     }, {    // Multiple comma-separated vary fields.
-      &syn_reply_info,
       true,
       { 2, 4 },
       { { "friend",   "barney",
@@ -3443,12 +3363,12 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
     };
 
     // Construct the reply.
+    SpdyHeaderBlock reply_headers;
+    AppendToHeaderBlock(test_cases[i].extra_headers[1],
+                        test_cases[i].num_headers[1],
+                        &reply_headers);
     scoped_ptr<SpdyFrame> frame_reply(
-      spdy_util_.ConstructSpdyFrame(*test_cases[i].syn_reply,
-                                    test_cases[i].extra_headers[1],
-                                    test_cases[i].num_headers[1],
-                                    NULL,
-                                    0));
+        spdy_util_.ConstructSpdyReply(1, reply_headers));
 
     scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
     MockRead reads[] = {
@@ -3503,10 +3423,6 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
     }
 
     // Construct the expected header reply string.
-    SpdyHeaderBlock reply_headers;
-    AppendToHeaderBlock(test_cases[i].extra_headers[1],
-                        test_cases[i].num_headers[1],
-                        &reply_headers);
     std::string expected_reply =
         spdy_util_.ConstructSpdyReplyString(reply_headers);
     EXPECT_EQ(expected_reply, lines) << i;
@@ -3515,21 +3431,6 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) {
 
 // Verify that we don't crash on invalid SynReply responses.
 TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) {
-  const SpdyHeaderInfo kSynStartHeader = {
-    SYN_REPLY,              // Kind = SynReply
-    1,                      // Stream ID
-    0,                      // Associated stream ID
-    ConvertRequestPriorityToSpdyPriority(
-        LOWEST, spdy_util_.spdy_version()),
-    kSpdyCredentialSlotUnused,
-    CONTROL_FLAG_NONE,      // Control Flags
-    false,                  // Compressed
-    RST_STREAM_INVALID,     // Status
-    NULL,                   // Data
-    0,                      // Length
-    DATA_FLAG_NONE          // Data Flags
-  };
-
   struct InvalidSynReplyTests {
     int num_headers;
     const char* headers[10];
@@ -3564,12 +3465,11 @@ TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) {
       CreateMockWrite(*rst),
     };
 
-    scoped_ptr<SpdyFrame> resp(
-       spdy_util_.ConstructSpdyFrame(kSynStartHeader,
-                                     NULL, 0,
-                                     test_cases[i].headers,
-                                     test_cases[i].num_headers));
-    scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
+    // Construct the reply.
+    SpdyHeaderBlock reply_headers;
+    AppendToHeaderBlock(
+        test_cases[i].headers, test_cases[i].num_headers, &reply_headers);
+    scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyReply(1, reply_headers));
     MockRead reads[] = {
       CreateMockRead(*resp),
       MockRead(ASYNC, 0, 0)  // EOF
@@ -3648,25 +3548,22 @@ TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionErrorSpdy4) {
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
   size_t right_size =
-      (spdy_util_.spdy_version() < SPDY4) ?
-      syn_reply_wrong_length->size() - framer.GetControlFrameHeaderSize() :
-      syn_reply_wrong_length->size();
+      syn_reply_wrong_length->size() - framer.GetControlFrameHeaderSize();
   size_t wrong_size = right_size - 4;
   test::SetFrameLength(syn_reply_wrong_length.get(),
                        wrong_size,
                        spdy_util_.spdy_version());
 
-  // TODO(jgraettinger): SpdySession::OnError() should send a GOAWAY before
-  // breaking the connection.
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = {
-    CreateMockWrite(*req),
-  };
+  scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+      0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
+  MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)};
 
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockRead reads[] = {
-    MockRead(ASYNC, syn_reply_wrong_length->data(), wrong_size),
+    MockRead(ASYNC, syn_reply_wrong_length->data(),
+             syn_reply_wrong_length->size() - 4),
   };
 
   DelayedSocketData data(1, reads, arraysize(reads),
@@ -3675,6 +3572,55 @@ TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionErrorSpdy4) {
                                      BoundNetLog(), GetParam(), NULL);
   helper.RunToCompletion(&data);
   TransactionHelperResult out = helper.output();
+  EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv);
+}
+
+TEST_P(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) {
+  if (GetParam().protocol < kProtoSPDY4) {
+    // Decompression failures are a stream error in SPDY3 and above.
+    return;
+  }
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+  scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+      0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
+  MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)};
+
+  // Read HEADERS with corrupted payload.
+  scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+  memset(resp->data() + 12, 0xff, resp->size() - 12);
+  MockRead reads[] = {CreateMockRead(*resp)};
+
+  DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
+  NormalSpdyTransactionHelper helper(
+      CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
+  helper.RunToCompletion(&data);
+  TransactionHelperResult out = helper.output();
+  EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv);
+}
+
+TEST_P(SpdyNetworkTransactionTest, GoAwayOnFrameSizeError) {
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+  scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+      0, GOAWAY_PROTOCOL_ERROR, "Framer error: 1 (INVALID_CONTROL_FRAME)."));
+  MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)};
+
+  // Read WINDOW_UPDATE with incorrectly-sized payload.
+  // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME,
+  // which is mapped to a protocol error, and not a frame size error.
+  scoped_ptr<SpdyFrame> bad_window_update(
+      spdy_util_.ConstructSpdyWindowUpdate(1, 1));
+  test::SetFrameLength(bad_window_update.get(),
+                       bad_window_update->size() - 1,
+                       spdy_util_.spdy_version());
+  MockRead reads[] = {CreateMockRead(*bad_window_update)};
+
+  DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
+  NormalSpdyTransactionHelper helper(
+      CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
+  helper.RunToCompletion(&data);
+  TransactionHelperResult out = helper.output();
   EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
 }
 
@@ -3683,14 +3629,16 @@ TEST_P(SpdyNetworkTransactionTest, WriteError) {
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   MockWrite writes[] = {
-    // We'll write 10 bytes successfully
-    MockWrite(ASYNC, req->data(), 10, 0),
-    // Followed by ERROR!
-    MockWrite(ASYNC, ERR_FAILED, 1),
+      // We'll write 10 bytes successfully
+      MockWrite(ASYNC, req->data(), 10, 0),
+      // Followed by ERROR!
+      MockWrite(ASYNC, ERR_FAILED, 1),
+      // Session drains and attempts to write a GOAWAY: Another ERROR!
+      MockWrite(ASYNC, ERR_FAILED, 2),
   };
 
   MockRead reads[] = {
-    MockRead(ASYNC, 0, 2)  // EOF
+      MockRead(ASYNC, 0, 3)  // EOF
   };
 
   DeterministicSocketData data(reads, arraysize(reads),
@@ -3746,11 +3694,9 @@ TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) {
   }
   scoped_ptr<SpdyFrame> compressed(
       spdy_util_.ConstructSpdyGet(NULL, 0, true, 1, LOWEST, true));
-  scoped_ptr<SpdyFrame> rst(
-      spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
-  MockWrite writes[] = {
-    CreateMockWrite(*compressed),
-  };
+  scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+      0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE)."));
+  MockWrite writes[] = {CreateMockWrite(*compressed), CreateMockWrite(*goaway)};
 
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
@@ -3767,7 +3713,7 @@ TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) {
                                      BoundNetLog(), GetParam(), session_deps);
   helper.RunToCompletion(&data);
   TransactionHelperResult out = helper.output();
-  EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+  EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv);
   data.Reset();
 }
 
@@ -3843,9 +3789,12 @@ TEST_P(SpdyNetworkTransactionTest, NetLog) {
   expected.push_back(std::string(spdy_util_.GetHostKey()) + ": www.google.com");
   expected.push_back(std::string(spdy_util_.GetPathKey()) + ": /");
   expected.push_back(std::string(spdy_util_.GetSchemeKey()) + ": http");
-  expected.push_back(std::string(spdy_util_.GetVersionKey()) + ": HTTP/1.1");
   expected.push_back(std::string(spdy_util_.GetMethodKey()) + ": GET");
   expected.push_back("user-agent: Chrome");
+  if (spdy_util_.spdy_version() < SPDY4) {
+    // SPDY4/HTTP2 eliminates use of the :version header.
+    expected.push_back(std::string(spdy_util_.GetVersionKey()) + ": HTTP/1.1");
+  }
   EXPECT_EQ(expected.size(), header_list->GetSize());
   for (std::vector<std::string>::const_iterator it = expected.begin();
        it != expected.end();
@@ -4057,22 +4006,13 @@ TEST_P(SpdyNetworkTransactionTest, BufferedAll) {
   MockWrite writes[] = { CreateMockWrite(*req) };
 
   // 5 data frames in a single read.
-  SpdySynReplyIR reply_ir(1);
-  reply_ir.SetHeader(spdy_util_.GetStatusKey(), "200");
-  reply_ir.SetHeader(spdy_util_.GetVersionKey(), "HTTP/1.1");
-
-  scoped_ptr<SpdyFrame> syn_reply(framer.SerializeFrame(reply_ir));
+  scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> data_frame(
       framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
   scoped_ptr<SpdyFrame> data_frame_fin(
       framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN));
-  const SpdyFrame* frames[5] = {
-    syn_reply.get(),
-    data_frame.get(),
-    data_frame.get(),
-    data_frame.get(),
-    data_frame_fin.get()
-  };
+  const SpdyFrame* frames[5] = {reply.get(), data_frame.get(), data_frame.get(),
+                                data_frame.get(), data_frame_fin.get()};
   char combined_frames[200];
   int combined_frames_len =
       CombineFrames(frames, arraysize(frames),
@@ -4239,7 +4179,9 @@ TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) {
 
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
-  MockWrite writes[] = { CreateMockWrite(*req) };
+  scoped_ptr<SpdyFrame> rst(
+      spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
+  MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*rst)};
 
   // NOTE: We don't FIN the stream.
   scoped_ptr<SpdyFrame> data_frame(
@@ -4303,8 +4245,7 @@ TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) {
 // the settings in the HttpServerProperties.
 TEST_P(SpdyNetworkTransactionTest, SettingsSaved) {
   if (spdy_util_.spdy_version() >= SPDY4) {
-    // SPDY4 doesn't support flags on individual settings, and
-    // has no concept of settings persistence.
+    // SPDY4 doesn't support settings persistence.
     return;
   }
   static const SpdyHeaderInfo kSynReplyInfo = {
@@ -4411,6 +4352,10 @@ TEST_P(SpdyNetworkTransactionTest, SettingsSaved) {
 // Test that when there are settings saved that they are sent back to the
 // server upon session establishment.
 TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) {
+  if (spdy_util_.spdy_version() >= SPDY4) {
+    // SPDY4 doesn't support settings persistence.
+    return;
+  }
   static const SpdyHeaderInfo kSynReplyInfo = {
     SYN_REPLY,                              // Syn Reply
     1,                                      // Stream ID
@@ -4441,9 +4386,9 @@ TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) {
   EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings(
       host_port_pair).empty());
 
-  const SpdySettingsIds kSampleId1 = SETTINGS_UPLOAD_BANDWIDTH;
+  const SpdySettingsIds kSampleId1 = SETTINGS_MAX_CONCURRENT_STREAMS;
   unsigned int kSampleValue1 = 0x0a0a0a0a;
-  const SpdySettingsIds kSampleId2 = SETTINGS_ROUND_TRIP_TIME;
+  const SpdySettingsIds kSampleId2 = SETTINGS_INITIAL_WINDOW_SIZE;
   unsigned int kSampleValue2 = 0x0c0c0c0c;
 
   // First add a persisted setting.
@@ -4488,7 +4433,7 @@ TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) {
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
 
   std::vector<MockWrite> writes;
-  if (GetParam().protocol == kProtoHTTP2Draft04) {
+  if (GetParam().protocol == kProtoSPDY4) {
     writes.push_back(
         MockWrite(ASYNC,
                   kHttp2ConnectionHeaderPrefix,
@@ -4770,12 +4715,12 @@ TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
   // Check that the SpdySession is still in the SpdySessionPool.
   HostPortPair host_port_pair("www.google.com", helper.port());
   SpdySessionKey session_pool_key_direct(
-      host_port_pair, ProxyServer::Direct(), kPrivacyModeDisabled);
+      host_port_pair, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
   EXPECT_TRUE(HasSpdySession(spdy_session_pool, session_pool_key_direct));
   SpdySessionKey session_pool_key_proxy(
       host_port_pair,
       ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP),
-      kPrivacyModeDisabled);
+      PRIVACY_MODE_DISABLED);
   EXPECT_FALSE(HasSpdySession(spdy_session_pool, session_pool_key_proxy));
 
   // Set up data for the proxy connection.
@@ -4970,7 +4915,7 @@ TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
 
 // Test that turning SPDY on and off works properly.
 TEST_P(SpdyNetworkTransactionTest, SpdyOnOffToggle) {
-  net::HttpStreamFactory::set_spdy_enabled(true);
+  HttpStreamFactory::set_spdy_enabled(true);
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   MockWrite spdy_writes[] = { CreateMockWrite(*req) };
@@ -5117,13 +5062,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithHeaders) {
   spdy_util_.AddUrlToHeaderBlock(
       "http://www.google.com/foo.dat", initial_headers.get());
   scoped_ptr<SpdyFrame> stream2_syn(
-      spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
-                                           false,
-                                           2,
-                                           LOWEST,
-                                           SYN_STREAM,
-                                           CONTROL_FLAG_NONE,
-                                           1));
+      spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
 
   scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
   (*late_headers)["hello"] = "bye";
@@ -5186,13 +5125,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) {
   spdy_util_.AddUrlToHeaderBlock(
       "http://www.google.com/foo.dat", initial_headers.get());
   scoped_ptr<SpdyFrame> stream2_syn(
-      spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
-                                           false,
-                                           2,
-                                           LOWEST,
-                                           SYN_STREAM,
-                                           CONTROL_FLAG_NONE,
-                                           1));
+      spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
 
   scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
   (*late_headers)["hello"] = "bye";
@@ -5297,6 +5230,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) {
   EXPECT_TRUE(data.at_write_eof());
 }
 
+// TODO(baranovich): HTTP 2 does not allow multiple HEADERS frames
 TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
   // We push a stream and attempt to claim it before the headers come down.
   scoped_ptr<SpdyFrame> stream1_syn(
@@ -5308,16 +5242,14 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
   };
 
   scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
+  if (spdy_util_.spdy_version() < SPDY4) {
+    // In SPDY4 PUSH_PROMISE headers won't show up in the response headers.
+    (*initial_headers)["alpha"] = "beta";
+  }
   spdy_util_.AddUrlToHeaderBlock(
       "http://www.google.com/foo.dat", initial_headers.get());
   scoped_ptr<SpdyFrame> stream2_syn(
-      spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
-                                           false,
-                                           2,
-                                           LOWEST,
-                                           SYN_STREAM,
-                                           CONTROL_FLAG_NONE,
-                                           1));
+      spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
 
   scoped_ptr<SpdyHeaderBlock> middle_headers(new SpdyHeaderBlock());
   (*middle_headers)["hello"] = "bye";
@@ -5332,7 +5264,10 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
 
   scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
   (*late_headers)[spdy_util_.GetStatusKey()] = "200";
-  (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
+  if (spdy_util_.spdy_version() < SPDY4) {
+    // SPDY4/HTTP2 eliminates use of the :version header.
+    (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
+  }
   scoped_ptr<SpdyFrame> stream2_headers2(
       spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(),
                                            false,
@@ -5421,22 +5356,11 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) {
   EXPECT_TRUE(response2.headers.get() != NULL);
   EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine());
 
-  // Verify we got all the headers
-  if (spdy_util_.spdy_version() < SPDY3) {
-    EXPECT_TRUE(response2.headers->HasHeaderValue(
-        "url",
-        "http://www.google.com/foo.dat"));
-  } else {
-    EXPECT_TRUE(response2.headers->HasHeaderValue(
-        "scheme", "http"));
-    EXPECT_TRUE(response2.headers->HasHeaderValue(
-        "host", "www.google.com"));
-    EXPECT_TRUE(response2.headers->HasHeaderValue(
-        "path", "/foo.dat"));
-  }
+  // Verify we got all the headers from all header blocks.
+  if (spdy_util_.spdy_version() < SPDY4)
+    EXPECT_TRUE(response2.headers->HasHeaderValue("alpha", "beta"));
   EXPECT_TRUE(response2.headers->HasHeaderValue("hello", "bye"));
   EXPECT_TRUE(response2.headers->HasHeaderValue("status", "200"));
-  EXPECT_TRUE(response2.headers->HasHeaderValue("version", "HTTP/1.1"));
 
   // Read the final EOF (which will close the session)
   data.RunFor(1);
@@ -5460,13 +5384,7 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushWithNoStatusHeaderFrames) {
   spdy_util_.AddUrlToHeaderBlock(
       "http://www.google.com/foo.dat", initial_headers.get());
   scoped_ptr<SpdyFrame> stream2_syn(
-      spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
-                                           false,
-                                           2,
-                                           LOWEST,
-                                           SYN_STREAM,
-                                           CONTROL_FLAG_NONE,
-                                           1));
+      spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1));
 
   scoped_ptr<SpdyHeaderBlock> middle_headers(new SpdyHeaderBlock());
   (*middle_headers)["hello"] = "bye";
@@ -5565,21 +5483,11 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyWithHeaders) {
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
   MockWrite writes[] = {
-    CreateMockWrite(*req),
-    CreateMockWrite(*rst),
- };
+      CreateMockWrite(*req), CreateMockWrite(*rst),
+  };
 
-  scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
-  (*initial_headers)[spdy_util_.GetStatusKey()] = "200 OK";
-  (*initial_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
   scoped_ptr<SpdyFrame> stream1_reply(
-      spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
-                                           false,
-                                           1,
-                                           LOWEST,
-                                           SYN_REPLY,
-                                           CONTROL_FLAG_NONE,
-                                           0));
+      spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
 
   scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
   (*late_headers)["hello"] = "bye";
@@ -5619,17 +5527,8 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyWithLateHeaders) {
     CreateMockWrite(*rst),
   };
 
-  scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock());
-  (*initial_headers)[spdy_util_.GetStatusKey()] = "200 OK";
-  (*initial_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1";
   scoped_ptr<SpdyFrame> stream1_reply(
-      spdy_util_.ConstructSpdyControlFrame(initial_headers.Pass(),
-                                           false,
-                                           1,
-                                           LOWEST,
-                                           SYN_REPLY,
-                                           CONTROL_FLAG_NONE,
-                                           0));
+      spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
 
   scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock());
   (*late_headers)["hello"] = "bye";
@@ -5663,11 +5562,6 @@ TEST_P(SpdyNetworkTransactionTest, SynReplyWithLateHeaders) {
 }
 
 TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) {
-  if (spdy_util_.spdy_version() == SPDY4) {
-    // TODO(jgraettinger): We don't support associated stream
-    // checks in SPDY4 yet.
-    return;
-  }
   // In this test we want to verify that we can't accidentally push content
   // which can't be pushed by this content server.
   // This test assumes that:
@@ -6371,6 +6265,9 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
   if (GetParam().protocol >= kProtoSPDY31)
     reads.push_back(CreateMockRead(*session_window_update, i++));
 
+  scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
+  writes.push_back(CreateMockWrite(*settings_ack, i++));
+
   writes.push_back(CreateMockWrite(*body3, i++));
 
   scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
@@ -6422,7 +6319,7 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
   // since we're send-stalled.
   EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
 
-  data.RunFor(6);   // Read in SETTINGS frame to unstall.
+  data.RunFor(7);   // Read in SETTINGS frame to unstall.
   rv = callback.WaitForResult();
   helper.VerifyDataConsumed();
   // If stream is NULL, that means it was unstalled and closed.
@@ -6495,6 +6392,9 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
 
   reads.push_back(CreateMockRead(*window_update_init_size, i++));
 
+  scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
+  writes.push_back(CreateMockWrite(*settings_ack, i++));
+
   writes.push_back(CreateMockWrite(*body3, i++));
 
   scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
@@ -6547,9 +6447,176 @@ TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
   EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
 
   // Read in WINDOW_UPDATE or SETTINGS frame.
-  data.RunFor((GetParam().protocol >= kProtoSPDY31) ? 8 : 7);
+  data.RunFor((GetParam().protocol >= kProtoSPDY31) ? 9 : 8);
   rv = callback.WaitForResult();
   helper.VerifyDataConsumed();
 }
 
+TEST_P(SpdyNetworkTransactionTest, GoAwayOnOddPushStreamId) {
+  if (spdy_util_.spdy_version() < SPDY3)
+    return;
+
+  scoped_ptr<SpdyHeaderBlock> push_headers(new SpdyHeaderBlock);
+  spdy_util_.AddUrlToHeaderBlock("http://www.google.com/a.dat",
+                                 push_headers.get());
+  scoped_ptr<SpdyFrame> push(
+      spdy_util_.ConstructInitialSpdyPushFrame(push_headers.Pass(), 3, 1));
+  MockRead reads[] = {CreateMockRead(*push, 1)};
+
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+  scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+      0, GOAWAY_PROTOCOL_ERROR, "Odd push stream id."));
+  MockWrite writes[] = {
+      CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2),
+  };
+
+  DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
+  NormalSpdyTransactionHelper helper(
+      CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
+  helper.RunToCompletion(&data);
+  TransactionHelperResult out = helper.output();
+  EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+}
+
+TEST_P(SpdyNetworkTransactionTest,
+       GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted) {
+  if (spdy_util_.spdy_version() < SPDY3)
+    return;
+
+  scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush(
+      NULL, 0, 4, 1, "http://www.google.com/a.dat"));
+  scoped_ptr<SpdyHeaderBlock> push_b_headers(new SpdyHeaderBlock);
+  spdy_util_.AddUrlToHeaderBlock("http://www.google.com/b.dat",
+                                 push_b_headers.get());
+  scoped_ptr<SpdyFrame> push_b(
+      spdy_util_.ConstructInitialSpdyPushFrame(push_b_headers.Pass(), 2, 1));
+  MockRead reads[] = {
+      CreateMockRead(*push_a, 1), CreateMockRead(*push_b, 2),
+  };
+
+  scoped_ptr<SpdyFrame> req(
+      spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+  scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(
+      4,
+      GOAWAY_PROTOCOL_ERROR,
+      "New push stream id must be greater than the last accepted."));
+  MockWrite writes[] = {
+      CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 3),
+  };
+
+  DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes));
+  NormalSpdyTransactionHelper helper(
+      CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
+  helper.RunToCompletion(&data);
+  TransactionHelperResult out = helper.output();
+  EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv);
+}
+
+class SpdyNetworkTransactionNoTLSUsageCheckTest
+    : public SpdyNetworkTransactionTest {
+ protected:
+  void RunNoTLSUsageCheckTest(scoped_ptr<SSLSocketDataProvider> ssl_provider) {
+    // Construct the request.
+    scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyGet(
+        "https://www.google.com/", false, 1, LOWEST));
+    MockWrite writes[] = {CreateMockWrite(*req)};
+
+    scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+    scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
+    MockRead reads[] = {
+        CreateMockRead(*resp), CreateMockRead(*body),
+        MockRead(ASYNC, 0, 0)  // EOF
+    };
+
+    DelayedSocketData data(
+        1, reads, arraysize(reads), writes, arraysize(writes));
+    HttpRequestInfo request;
+    request.method = "GET";
+    request.url = GURL("https://www.google.com/");
+    NormalSpdyTransactionHelper helper(
+        request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
+    helper.RunToCompletionWithSSLData(&data, ssl_provider.Pass());
+    TransactionHelperResult out = helper.output();
+    EXPECT_EQ(OK, out.rv);
+    EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
+    EXPECT_EQ("hello!", out.response_data);
+  }
+};
+
+//-----------------------------------------------------------------------------
+// All tests are run with three different connection types: SPDY after NPN
+// negotiation, SPDY without SSL, and SPDY with SSL.
+//
+// TODO(akalin): Use ::testing::Combine() when we are able to use
+// <tr1/tuple>.
+INSTANTIATE_TEST_CASE_P(
+    Spdy,
+    SpdyNetworkTransactionNoTLSUsageCheckTest,
+    ::testing::Values(SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2,
+                                                       SPDYNPN),
+                      SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNPN),
+                      SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN)));
+
+TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSVersionTooOld) {
+  scoped_ptr<SSLSocketDataProvider> ssl_provider(
+      new SSLSocketDataProvider(ASYNC, OK));
+  SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
+                                &ssl_provider->connection_status);
+
+  RunNoTLSUsageCheckTest(ssl_provider.Pass());
+}
+
+TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSCipherSuiteSucky) {
+  scoped_ptr<SSLSocketDataProvider> ssl_provider(
+      new SSLSocketDataProvider(ASYNC, OK));
+  // Set to TLS_RSA_WITH_NULL_MD5
+  SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider->connection_status);
+
+  RunNoTLSUsageCheckTest(ssl_provider.Pass());
+}
+
+class SpdyNetworkTransactionTLSUsageCheckTest
+    : public SpdyNetworkTransactionTest {
+ protected:
+  void RunTLSUsageCheckTest(scoped_ptr<SSLSocketDataProvider> ssl_provider) {
+    scoped_ptr<SpdyFrame> goaway(
+        spdy_util_.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY, ""));
+    MockWrite writes[] = {CreateMockWrite(*goaway)};
+
+    DelayedSocketData data(1, NULL, 0, writes, arraysize(writes));
+    HttpRequestInfo request;
+    request.method = "GET";
+    request.url = GURL("https://www.google.com/");
+    NormalSpdyTransactionHelper helper(
+        request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL);
+    helper.RunToCompletionWithSSLData(&data, ssl_provider.Pass());
+    TransactionHelperResult out = helper.output();
+    EXPECT_EQ(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY, out.rv);
+  }
+};
+
+INSTANTIATE_TEST_CASE_P(
+    Spdy,
+    SpdyNetworkTransactionTLSUsageCheckTest,
+    ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNPN)));
+
+TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
+  scoped_ptr<SSLSocketDataProvider> ssl_provider(
+      new SSLSocketDataProvider(ASYNC, OK));
+  SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
+                                &ssl_provider->connection_status);
+
+  RunTLSUsageCheckTest(ssl_provider.Pass());
+}
+
+TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSCipherSuiteSucky) {
+  scoped_ptr<SSLSocketDataProvider> ssl_provider(
+      new SSLSocketDataProvider(ASYNC, OK));
+  // Set to TLS_RSA_WITH_NULL_MD5
+  SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider->connection_status);
+
+  RunTLSUsageCheckTest(ssl_provider.Pass());
+}
+
 }  // namespace net