#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"
#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"
#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"
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
: 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 {
}
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);
}
void FinishDefaultTest() {
- output_.rv = callback.WaitForResult();
+ output_.rv = callback_.WaitForResult();
if (output_.rv != OK) {
session_->spdy_session_pool()->CloseCurrentSessions(net::ERR_ABORTED);
return;
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) {
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_;
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(
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 =
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));
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,
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),
};
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),
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),
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),
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[] = {
CreateMockRead(*resp),
CreateMockRead(*body),
CreateMockRead(*fbody),
- CreateMockRead(*resp2, 7),
+ CreateMockRead(*resp2, 8),
CreateMockRead(*body2),
CreateMockRead(*fbody2),
MockRead(ASYNC, 0, 0), // EOF
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[] = {
CreateMockRead(*resp),
CreateMockRead(*body),
CreateMockRead(*fin_body),
- CreateMockRead(*resp2, 7),
+ CreateMockRead(*resp2, 8),
MockRead(ASYNC, ERR_CONNECTION_RESET, 0), // Abort!
};
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),
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),
// 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),
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),
// 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),
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());
}
// 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,
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[] = {
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());
}
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(
}
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(
(*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),
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(
// 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];
// 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",
}
}
}, { // Multiple vary fields.
- &syn_reply_info,
true,
{ 2, 5 },
{ { "friend", "barney",
}
}
}, { // Test a '*' vary field.
- &syn_reply_info,
false,
{ 1, 4 },
{ { "cookie", "val1,val2",
}
}
}, { // Multiple comma-separated vary fields.
- &syn_reply_info,
true,
{ 2, 4 },
{ { "friend", "barney",
};
// 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[] = {
}
// 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;
// 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];
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
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),
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);
}
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),
}
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));
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();
}
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();
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),
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(
// 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 = {
// 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
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.
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,
// 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.
// 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) };
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";
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";
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(
};
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";
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,
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);
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";
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";
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";
}
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:
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));
// 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.
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));
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