summaryrefslogtreecommitdiffstats
path: root/chromium/net/spdy/spdy_network_transaction_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/spdy/spdy_network_transaction_unittest.cc')
-rw-r--r--chromium/net/spdy/spdy_network_transaction_unittest.cc729
1 files changed, 483 insertions, 246 deletions
diff --git a/chromium/net/spdy/spdy_network_transaction_unittest.cc b/chromium/net/spdy/spdy_network_transaction_unittest.cc
index bf9fbce45b6..f11cb656a9c 100644
--- a/chromium/net/spdy/spdy_network_transaction_unittest.cc
+++ b/chromium/net/spdy/spdy_network_transaction_unittest.cc
@@ -12,6 +12,7 @@
#include "base/memory/scoped_vector.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
+#include "base/strings/string_piece.h"
#include "base/test/test_file_util.h"
#include "net/base/auth.h"
#include "net/base/net_log_unittest.h"
@@ -22,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"
@@ -32,7 +33,9 @@
#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"
//-----------------------------------------------------------------------------
@@ -40,6 +43,10 @@
namespace net {
namespace {
+
+using testing::Each;
+using testing::Eq;
+
const char kRequestUrl[] = "http://www.google.com/";
enum SpdyNetworkTransactionTestSSLType {
@@ -63,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));
+ 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
@@ -80,20 +117,25 @@ 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 {
@@ -159,50 +201,30 @@ 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);
@@ -210,7 +232,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;
@@ -290,17 +312,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) {
@@ -373,7 +413,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_;
@@ -440,7 +480,7 @@ class SpdyNetworkTransactionTest
base::FilePath file_path;
CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
CHECK_EQ(static_cast<int>(kUploadDataSize),
- file_util::WriteFile(file_path, kUploadData, kUploadDataSize));
+ base::WriteFile(file_path, kUploadData, kUploadDataSize));
ScopedVector<UploadElementReader> element_readers;
element_readers.push_back(
@@ -467,7 +507,7 @@ class SpdyNetworkTransactionTest
base::FilePath file_path;
CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
CHECK_EQ(static_cast<int>(kUploadDataSize),
- file_util::WriteFile(file_path, kUploadData, kUploadDataSize));
+ base::WriteFile(file_path, kUploadData, kUploadDataSize));
CHECK(file_util::MakeFileUnreadable(file_path));
ScopedVector<UploadElementReader> element_readers;
@@ -496,7 +536,7 @@ class SpdyNetworkTransactionTest
base::FilePath file_path;
CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path));
CHECK_EQ(static_cast<int>(kUploadDataSize),
- file_util::WriteFile(file_path, kUploadData, kUploadDataSize));
+ base::WriteFile(file_path, kUploadData, kUploadDataSize));
ScopedVector<UploadElementReader> element_readers;
element_readers.push_back(
@@ -573,7 +613,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 =
@@ -690,24 +730,26 @@ 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));
@@ -1060,9 +1102,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,
@@ -1132,9 +1172,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),
};
@@ -1144,10 +1186,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),
@@ -1270,8 +1312,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),
@@ -1281,12 +1325,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),
@@ -1412,8 +1456,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[] = {
@@ -1421,7 +1468,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
@@ -1546,8 +1593,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[] = {
@@ -1555,7 +1605,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!
};
@@ -1959,6 +2009,7 @@ TEST_P(SpdyNetworkTransactionTest, DelayedChunkedPost) {
// Test that a POST without any post data works.
TEST_P(SpdyNetworkTransactionTest, NullPost) {
+ BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
// Setup the request
HttpRequestInfo request;
request.method = "POST";
@@ -1968,10 +2019,14 @@ TEST_P(SpdyNetworkTransactionTest, NullPost) {
// When request.upload_data_stream is NULL for post, content-length is
// expected to be 0.
- scoped_ptr<SpdyFrame> req(
- spdy_util_.ConstructSpdyPost(kRequestUrl, 1, 0, LOWEST, NULL, 0));
- // Set the FIN bit since there will be no body.
- test::SetFrameFlags(req.get(), CONTROL_FLAG_FIN, spdy_util_.spdy_version());
+ 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));
+
MockWrite writes[] = {
CreateMockWrite(*req),
};
@@ -1998,6 +2053,7 @@ TEST_P(SpdyNetworkTransactionTest, NullPost) {
// Test that a simple POST works.
TEST_P(SpdyNetworkTransactionTest, EmptyPost) {
+ BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
// Create an empty UploadDataStream.
ScopedVector<UploadElementReader> element_readers;
UploadDataStream stream(element_readers.Pass(), 0);
@@ -2009,11 +2065,15 @@ TEST_P(SpdyNetworkTransactionTest, EmptyPost) {
request.upload_data_stream = &stream;
const uint64 kContentLength = 0;
- scoped_ptr<SpdyFrame> req(
- spdy_util_.ConstructSpdyPost(
- kRequestUrl, 1, kContentLength, LOWEST, NULL, 0));
- // Set the FIN bit since there will be no body.
- test::SetFrameFlags(req.get(), CONTROL_FLAG_FIN, spdy_util_.spdy_version());
+
+ 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));
+
MockWrite writes[] = {
CreateMockWrite(*req),
};
@@ -2037,57 +2097,50 @@ TEST_P(SpdyNetworkTransactionTest, EmptyPost) {
EXPECT_EQ("hello!", out.response_data);
}
-// While we're doing a post, the server sends back a SYN_REPLY.
-TEST_P(SpdyNetworkTransactionTest, PostWithEarlySynReply) {
- static const char upload[] = { "hello!" };
- ScopedVector<UploadElementReader> element_readers;
- element_readers.push_back(
- new UploadBytesElementReader(upload, sizeof(upload)));
- UploadDataStream stream(element_readers.Pass(), 0);
-
- // Setup the request
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL(kRequestUrl);
- request.upload_data_stream = &stream;
-
- scoped_ptr<SpdyFrame> stream_reply(
- spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
- MockRead reads[] = {
- CreateMockRead(*stream_reply, 1),
- MockRead(ASYNC, 0, 4) // EOF
- };
-
- scoped_ptr<SpdyFrame> req(
- spdy_util_.ConstructSpdyPost(
- kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0));
+// While we're doing a post, the server sends the reply before upload completes.
+TEST_P(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
+ scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
- scoped_ptr<SpdyFrame> rst(
- spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
CreateMockWrite(*req, 0),
- CreateMockWrite(*body, 2),
- CreateMockWrite(*rst, 3)
+ CreateMockWrite(*body, 3),
+ };
+ scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0));
+ MockRead reads[] = {
+ CreateMockRead(*resp, 1),
+ CreateMockRead(*body, 2),
+ MockRead(ASYNC, 0, 4) // EOF
};
+ // Write the request headers, and read the complete response
+ // while still waiting for chunked request data.
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
- NormalSpdyTransactionHelper helper(CreatePostRequest(), DEFAULT_PRIORITY,
+ NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(),
+ DEFAULT_PRIORITY,
BoundNetLog(), GetParam(), NULL);
helper.SetDeterministic();
helper.RunPreTestSetup();
helper.AddDeterministicData(&data);
- HttpNetworkTransaction* trans = helper.trans();
- TestCompletionCallback callback;
- int rv = trans->Start(
- &CreatePostRequest(), callback.callback(), BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
+ ASSERT_TRUE(helper.StartDefaultTest());
- data.RunFor(4);
- rv = callback.WaitForResult();
- EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv);
- data.RunFor(1);
+ // Process the request headers, SYN_REPLY, and response body.
+ // The request body is still in flight.
+ data.RunFor(3);
+
+ const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
+ EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
+
+ // Finish sending the request body.
+ helper.request().upload_data_stream->AppendChunk(
+ kUploadData, kUploadDataSize, true);
+ data.RunFor(2);
+
+ std::string response_body;
+ EXPECT_EQ(OK, ReadTransaction(helper.trans(), &response_body));
+ EXPECT_EQ(kUploadData, response_body);
+ helper.VerifyDataConsumed();
}
// The client upon cancellation tries to send a RST_STREAM frame. The mock
@@ -2155,7 +2208,7 @@ TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
scoped_ptr<SpdyFrame> rst(
- spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_STREAM_IN_USE));
+ spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
MockWrite writes[] = {
CreateMockWrite(*req),
CreateMockWrite(*rst),
@@ -2511,11 +2564,12 @@ 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);
+ 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,
@@ -2605,11 +2659,12 @@ 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,
@@ -3035,6 +3090,12 @@ TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
}
TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
+ if (spdy_util_.spdy_version() == SPDY4) {
+ // 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(
@@ -3174,15 +3235,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),
@@ -3255,16 +3309,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(
@@ -3553,7 +3611,12 @@ TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) {
}
// Verify that we don't crash on some corrupt frames.
+// TODO(jgraettinger): SPDY4 and up treats a header decompression failure as a
+// connection error. I'd like to backport this behavior to SPDY3 as well.
TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionError) {
+ if (spdy_util_.spdy_version() >= SPDY4) {
+ return;
+ }
// This is the length field that's too short.
scoped_ptr<SpdyFrame> syn_reply_wrong_length(
spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
@@ -3600,19 +3663,107 @@ TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionError) {
}
}
+// SPDY4 treats a header decompression failure as a connection-level error.
+TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionErrorSpdy4) {
+ if (spdy_util_.spdy_version() < SPDY4) {
+ return;
+ }
+ // This is the length field that's too short.
+ scoped_ptr<SpdyFrame> syn_reply_wrong_length(
+ spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
+ size_t right_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());
+
+ 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)};
+
+ scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
+ MockRead reads[] = {
+ MockRead(ASYNC, syn_reply_wrong_length->data(),
+ syn_reply_wrong_length->size() - 4),
+ };
+
+ 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, 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);
+}
+
// Test that we shutdown correctly on write errors.
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),
@@ -3662,13 +3813,15 @@ TEST_P(SpdyNetworkTransactionTest, PartialWrite) {
// In this test, we enable compression, but get a uncompressed SynReply from
// the server. Verify that teardown is all clean.
TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) {
+ if (spdy_util_.spdy_version() >= SPDY4) {
+ // HPACK doesn't use deflate compression.
+ return;
+ }
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));
@@ -3685,7 +3838,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();
}
@@ -3761,9 +3914,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();
@@ -3975,11 +4131,11 @@ TEST_P(SpdyNetworkTransactionTest, BufferedAll) {
MockWrite writes[] = { CreateMockWrite(*req) };
// 5 data frames in a single read.
- scoped_ptr<SpdyFrame> syn_reply(
- spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- // turn off FIN bit
- test::SetFrameFlags(
- syn_reply.get(), CONTROL_FLAG_NONE, spdy_util_.spdy_version());
+ 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> data_frame(
framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE));
scoped_ptr<SpdyFrame> data_frame_fin(
@@ -4157,7 +4313,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(
@@ -4198,21 +4356,16 @@ TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) {
// Read Data
TestCompletionCallback read_callback;
- do {
- const int kReadSize = 256;
- scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kReadSize));
- rv = trans->Read(buf.get(), kReadSize, read_callback.callback());
- if (rv == net::ERR_IO_PENDING) {
- // Complete the read now, which causes buffering to start.
- data.CompleteRead();
- // Destroy the transaction, causing the stream to get cancelled
- // and orphaning the buffered IO task.
- helper.ResetTrans();
- break;
- }
- // We shouldn't get here in this test.
- FAIL() << "Unexpected read: " << rv;
- } while (rv > 0);
+ const int kReadSize = 256;
+ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kReadSize));
+ rv = trans->Read(buf.get(), kReadSize, read_callback.callback());
+ ASSERT_EQ(net::ERR_IO_PENDING, rv) << "Unexpected read: " << rv;
+
+ // Complete the read now, which causes buffering to start.
+ data.CompleteRead();
+ // Destroy the transaction, causing the stream to get cancelled
+ // and orphaning the buffered IO task.
+ helper.ResetTrans();
// Flush the MessageLoop; this will cause the buffered IO task
// to run for the final time.
@@ -4225,6 +4378,11 @@ TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) {
// Test that if the server requests persistence of settings, that we save
// 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.
+ return;
+ }
static const SpdyHeaderInfo kSynReplyInfo = {
SYN_REPLY, // Syn Reply
1, // Stream ID
@@ -4329,6 +4487,7 @@ 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) {
+ // TODO(jgraettinger): Remove settings persistence mechanisms altogether.
static const SpdyHeaderInfo kSynReplyInfo = {
SYN_REPLY, // Syn Reply
1, // Stream ID
@@ -4359,9 +4518,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.
@@ -4406,7 +4565,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,
@@ -4688,12 +4847,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.
@@ -4888,7 +5047,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) };
@@ -5005,7 +5164,8 @@ TEST_P(SpdyNetworkTransactionTest, SpdyBasicAuth) {
EXPECT_EQ("MyRealm", auth_challenge->realm);
// Restart with a username/password.
- AuthCredentials credentials(ASCIIToUTF16("foo"), ASCIIToUTF16("bar"));
+ AuthCredentials credentials(base::ASCIIToUTF16("foo"),
+ base::ASCIIToUTF16("bar"));
TestCompletionCallback callback_restart;
const int rv_restart = trans->RestartWithAuth(
credentials, callback_restart.callback());
@@ -5034,13 +5194,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";
@@ -5103,13 +5257,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";
@@ -5214,6 +5362,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(
@@ -5225,16 +5374,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";
@@ -5249,7 +5396,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,
@@ -5338,22 +5488,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);
@@ -5377,13 +5516,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";
@@ -5951,16 +6084,15 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
if (GetParam().protocol < kProtoSPDY3)
return;
- // Set the data in the body frame large enough to trigger sending a
- // WINDOW_UPDATE by the stream.
- const std::string body_data(kSpdyStreamInitialWindowSize / 2 + 1, 'x');
+ // Amount of body required to trigger a sent window update.
+ const size_t kTargetSize = kSpdyStreamInitialWindowSize / 2 + 1;
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
scoped_ptr<SpdyFrame> session_window_update(
- spdy_util_.ConstructSpdyWindowUpdate(0, body_data.size()));
+ spdy_util_.ConstructSpdyWindowUpdate(0, kTargetSize));
scoped_ptr<SpdyFrame> window_update(
- spdy_util_.ConstructSpdyWindowUpdate(1, body_data.size()));
+ spdy_util_.ConstructSpdyWindowUpdate(1, kTargetSize));
std::vector<MockWrite> writes;
writes.push_back(CreateMockWrite(*req));
@@ -5968,23 +6100,23 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
writes.push_back(CreateMockWrite(*session_window_update));
writes.push_back(CreateMockWrite(*window_update));
+ std::vector<MockRead> reads;
scoped_ptr<SpdyFrame> resp(
spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
- scoped_ptr<SpdyFrame> body_no_fin(
- spdy_util_.ConstructSpdyBodyFrame(
- 1, body_data.data(), body_data.size(), false));
- scoped_ptr<SpdyFrame> body_fin(
- spdy_util_.ConstructSpdyBodyFrame(1, NULL, 0, true));
- MockRead reads[] = {
- CreateMockRead(*resp),
- CreateMockRead(*body_no_fin),
- MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause
- CreateMockRead(*body_fin),
- MockRead(ASYNC, ERR_IO_PENDING, 0), // Force a pause
- MockRead(ASYNC, 0, 0) // EOF
- };
+ reads.push_back(CreateMockRead(*resp));
+
+ ScopedVector<SpdyFrame> body_frames;
+ const std::string body_data(4096, 'x');
+ for (size_t remaining = kTargetSize; remaining != 0;) {
+ size_t frame_size = std::min(remaining, body_data.size());
+ body_frames.push_back(spdy_util_.ConstructSpdyBodyFrame(
+ 1, body_data.data(), frame_size, false));
+ reads.push_back(CreateMockRead(*body_frames.back()));
+ remaining -= frame_size;
+ }
+ reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, 0)); // Yield.
- DelayedSocketData data(1, reads, arraysize(reads),
+ DelayedSocketData data(1, vector_as_array(&reads), reads.size(),
vector_as_array(&writes), writes.size());
NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY,
@@ -6005,9 +6137,9 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
ASSERT_TRUE(stream != NULL);
ASSERT_TRUE(stream->stream() != NULL);
- EXPECT_EQ(
- static_cast<int>(kSpdyStreamInitialWindowSize - body_data.size()),
- stream->stream()->recv_window_size());
+ // All data has been read, but not consumed. The window reflects this.
+ EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize - kTargetSize),
+ stream->stream()->recv_window_size());
const HttpResponseInfo* response = trans->GetResponseInfo();
ASSERT_TRUE(response != NULL);
@@ -6017,22 +6149,15 @@ TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
// Issue a read which will cause a WINDOW_UPDATE to be sent and window
// size increased to default.
- scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(body_data.size()));
- rv = trans->Read(buf.get(), body_data.size(), CompletionCallback());
- EXPECT_EQ(static_cast<int>(body_data.size()), rv);
- std::string content(buf->data(), buf->data() + body_data.size());
- EXPECT_EQ(body_data, content);
-
- // Schedule the reading of empty data frame with FIN
- data.CompleteRead();
-
- // Force write of WINDOW_UPDATE which was scheduled during the above
- // read.
+ scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kTargetSize));
+ EXPECT_EQ(static_cast<int>(kTargetSize),
+ trans->Read(buf.get(), kTargetSize, CompletionCallback()));
+ EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize),
+ stream->stream()->recv_window_size());
+ EXPECT_THAT(base::StringPiece(buf->data(), kTargetSize), Each(Eq('x')));
+
+ // Allow scheduled WINDOW_UPDATE frames to write.
base::RunLoop().RunUntilIdle();
-
- // Read EOF.
- data.CompleteRead();
-
helper.VerifyDataConsumed();
}
@@ -6291,6 +6416,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));
@@ -6342,7 +6470,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.
@@ -6415,6 +6543,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));
@@ -6467,9 +6598,115 @@ 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();
}
+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