blob: 70c406dd584fa5afcdc07a0535d3b6c5b1b59bf0 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/spdy/spdy_http_stream.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/sequenced_worker_pool.h"
#include "crypto/ec_private_key.h"
#include "crypto/ec_signature_creator.h"
#include "crypto/signature_creator.h"
#include "net/base/asn1_util.h"
#include "net/base/default_server_bound_cert_store.h"
#include "net/base/upload_data_stream.h"
#include "net/base/upload_element_reader.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/spdy/spdy_credential_builder.h"
#include "net/spdy/spdy_http_utils.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_test_util_spdy3.h"
#include "testing/gtest/include/gtest/gtest.h"
using namespace net::test_spdy3;
namespace net {
class SpdyHttpStreamSpdy3Test : public testing::Test {
public:
OrderedSocketData* data() { return data_.get(); }
protected:
virtual void TearDown() {
UploadDataStream::ResetMergeChunks();
MessageLoop::current()->RunUntilIdle();
}
void set_merge_chunks(bool merge) {
UploadDataStream::set_merge_chunks(merge);
}
int InitSession(MockRead* reads, size_t reads_count,
MockWrite* writes, size_t writes_count,
HostPortPair& host_port_pair) {
HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
data_.reset(new OrderedSocketData(reads, reads_count,
writes, writes_count));
session_deps_.socket_factory->AddSocketDataProvider(data_.get());
http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
transport_params_ = new TransportSocketParams(host_port_pair,
MEDIUM, false, false,
OnHostResolutionCallback());
TestCompletionCallback callback;
scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
EXPECT_EQ(ERR_IO_PENDING,
connection->Init(host_port_pair.ToString(),
transport_params_,
MEDIUM,
callback.callback(),
http_session_->GetTransportSocketPool(
HttpNetworkSession::NORMAL_SOCKET_POOL),
BoundNetLog()));
EXPECT_EQ(OK, callback.WaitForResult());
return session_->InitializeWithSocket(connection.release(), false, OK);
}
void TestSendCredentials(
ServerBoundCertService* server_bound_cert_service,
const std::string& cert,
const std::string& proof);
SpdySessionDependencies session_deps_;
scoped_ptr<OrderedSocketData> data_;
scoped_refptr<HttpNetworkSession> http_session_;
scoped_refptr<SpdySession> session_;
scoped_refptr<TransportSocketParams> transport_params_;
private:
MockECSignatureCreatorFactory ec_signature_creator_factory_;
};
TEST_F(SpdyHttpStreamSpdy3Test, SendRequest) {
scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
MockWrite writes[] = {
CreateMockWrite(*req.get(), 1),
};
scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
MockRead reads[] = {
CreateMockRead(*resp, 2),
MockRead(SYNCHRONOUS, 0, 3) // EOF
};
HostPortPair host_port_pair("www.google.com", 80);
HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
host_port_pair));
HttpRequestInfo request;
request.method = "GET";
request.url = GURL("http://www.google.com/");
TestCompletionCallback callback;
HttpResponseInfo response;
HttpRequestHeaders headers;
BoundNetLog net_log;
scoped_ptr<SpdyHttpStream> http_stream(
new SpdyHttpStream(session_.get(), true));
ASSERT_EQ(
OK,
http_stream->InitializeStream(&request, net_log, CompletionCallback()));
EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
callback.callback()));
EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
// This triggers the MockWrite and read 2
callback.WaitForResult();
// This triggers read 3. The empty read causes the session to shut down.
data()->CompleteRead();
// Because we abandoned the stream, we don't expect to find a session in the
// pool anymore.
EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
EXPECT_TRUE(data()->at_read_eof());
EXPECT_TRUE(data()->at_write_eof());
}
TEST_F(SpdyHttpStreamSpdy3Test, SendChunkedPost) {
set_merge_chunks(false);
scoped_ptr<SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0));
scoped_ptr<SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, false));
scoped_ptr<SpdyFrame> chunk2(ConstructSpdyBodyFrame(1, true));
MockWrite writes[] = {
CreateMockWrite(*req.get(), 0),
CreateMockWrite(*chunk1, 1), // POST upload frames
CreateMockWrite(*chunk2, 2),
};
scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
MockRead reads[] = {
CreateMockRead(*resp, 3),
CreateMockRead(*chunk1, 4),
CreateMockRead(*chunk2, 5),
MockRead(SYNCHRONOUS, 0, 6) // EOF
};
HostPortPair host_port_pair("www.google.com", 80);
HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
host_port_pair));
UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
upload_stream.AppendChunk(kUploadData, kUploadDataSize, false);
upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
HttpRequestInfo request;
request.method = "POST";
request.url = GURL("http://www.google.com/");
request.upload_data_stream = &upload_stream;
ASSERT_EQ(OK, upload_stream.InitSync());
TestCompletionCallback callback;
HttpResponseInfo response;
HttpRequestHeaders headers;
BoundNetLog net_log;
SpdyHttpStream http_stream(session_.get(), true);
ASSERT_EQ(
OK,
http_stream.InitializeStream(&request, net_log, CompletionCallback()));
EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest(
headers, &response, callback.callback()));
EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
// This triggers the MockWrite and read 2
callback.WaitForResult();
// This triggers read 3. The empty read causes the session to shut down.
data()->CompleteRead();
MessageLoop::current()->RunUntilIdle();
// Because we abandoned the stream, we don't expect to find a session in the
// pool anymore.
EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
EXPECT_TRUE(data()->at_read_eof());
EXPECT_TRUE(data()->at_write_eof());
}
// Test to ensure the SpdyStream state machine does not get confused when a
// chunk becomes available while a write is pending.
TEST_F(SpdyHttpStreamSpdy3Test, DelayedSendChunkedPost) {
set_merge_chunks(false);
const char kUploadData1[] = "12345678";
const int kUploadData1Size = arraysize(kUploadData1)-1;
scoped_ptr<SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0));
scoped_ptr<SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, false));
scoped_ptr<SpdyFrame> chunk2(
ConstructSpdyBodyFrame(1, kUploadData1, kUploadData1Size, false));
scoped_ptr<SpdyFrame> chunk3(ConstructSpdyBodyFrame(1, true));
MockWrite writes[] = {
CreateMockWrite(*req.get(), 0),
CreateMockWrite(*chunk1, 1), // POST upload frames
CreateMockWrite(*chunk2, 2),
CreateMockWrite(*chunk3, 3),
};
scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
MockRead reads[] = {
CreateMockRead(*resp, 4),
CreateMockRead(*chunk1, 5),
CreateMockRead(*chunk2, 6),
CreateMockRead(*chunk3, 7),
MockRead(ASYNC, 0, 8) // EOF
};
HostPortPair host_port_pair("www.google.com", 80);
HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
DeterministicMockClientSocketFactory* socket_factory =
session_deps_.deterministic_socket_factory.get();
socket_factory->AddSocketDataProvider(&data);
http_session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
&session_deps_);
session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
transport_params_ = new TransportSocketParams(host_port_pair,
MEDIUM, false, false,
OnHostResolutionCallback());
TestCompletionCallback callback;
scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
EXPECT_EQ(ERR_IO_PENDING,
connection->Init(host_port_pair.ToString(),
transport_params_,
MEDIUM,
callback.callback(),
http_session_->GetTransportSocketPool(
HttpNetworkSession::NORMAL_SOCKET_POOL),
BoundNetLog()));
callback.WaitForResult();
EXPECT_EQ(OK,
session_->InitializeWithSocket(connection.release(), false, OK));
UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
HttpRequestInfo request;
request.method = "POST";
request.url = GURL("http://www.google.com/");
request.upload_data_stream = &upload_stream;
ASSERT_EQ(OK, upload_stream.InitSync());
upload_stream.AppendChunk(kUploadData, kUploadDataSize, false);
BoundNetLog net_log;
scoped_ptr<SpdyHttpStream> http_stream(
new SpdyHttpStream(session_.get(), true));
ASSERT_EQ(OK, http_stream->InitializeStream(&request,
net_log,
CompletionCallback()));
HttpRequestHeaders headers;
HttpResponseInfo response;
// This will attempt to Write() the initial request and headers, which will
// complete asynchronously.
EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
callback.callback()));
EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
// Complete the initial request write and the first chunk.
data.RunFor(2);
ASSERT_TRUE(callback.have_result());
EXPECT_GT(callback.WaitForResult(), 0);
// Now append the final two chunks which will enqueue two more writes.
upload_stream.AppendChunk(kUploadData1, kUploadData1Size, false);
upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
// Finish writing all the chunks.
data.RunFor(2);
// Read response headers.
data.RunFor(1);
ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
// Read and check |chunk1| response.
data.RunFor(1);
scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
ASSERT_EQ(kUploadDataSize,
http_stream->ReadResponseBody(buf1,
kUploadDataSize,
callback.callback()));
EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
// Read and check |chunk2| response.
data.RunFor(1);
scoped_refptr<IOBuffer> buf2(new IOBuffer(kUploadData1Size));
ASSERT_EQ(kUploadData1Size,
http_stream->ReadResponseBody(buf2,
kUploadData1Size,
callback.callback()));
EXPECT_EQ(kUploadData1, std::string(buf2->data(), kUploadData1Size));
// Read and check |chunk3| response.
data.RunFor(1);
scoped_refptr<IOBuffer> buf3(new IOBuffer(kUploadDataSize));
ASSERT_EQ(kUploadDataSize,
http_stream->ReadResponseBody(buf3,
kUploadDataSize,
callback.callback()));
EXPECT_EQ(kUploadData, std::string(buf3->data(), kUploadDataSize));
// Finish reading the |EOF|.
data.RunFor(1);
ASSERT_TRUE(response.headers.get());
ASSERT_EQ(200, response.headers->response_code());
EXPECT_TRUE(data.at_read_eof());
EXPECT_TRUE(data.at_write_eof());
}
// Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
// made available is handled correctly.
TEST_F(SpdyHttpStreamSpdy3Test, DelayedSendChunkedPostWithWindowUpdate) {
set_merge_chunks(false);
scoped_ptr<SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0));
scoped_ptr<SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, true));
MockWrite writes[] = {
CreateMockWrite(*req.get(), 0),
CreateMockWrite(*chunk1, 1),
};
scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
scoped_ptr<SpdyFrame> window_update(
ConstructSpdyWindowUpdate(1, kUploadDataSize));
MockRead reads[] = {
CreateMockRead(*window_update, 2),
CreateMockRead(*resp, 3),
CreateMockRead(*chunk1, 4),
MockRead(ASYNC, 0, 5) // EOF
};
HostPortPair host_port_pair("www.google.com", 80);
HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
DeterministicMockClientSocketFactory* socket_factory =
session_deps_.deterministic_socket_factory.get();
socket_factory->AddSocketDataProvider(&data);
http_session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
&session_deps_);
session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
transport_params_ = new TransportSocketParams(host_port_pair,
MEDIUM, false, false,
OnHostResolutionCallback());
TestCompletionCallback callback;
scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
EXPECT_EQ(ERR_IO_PENDING,
connection->Init(host_port_pair.ToString(),
transport_params_,
MEDIUM,
callback.callback(),
http_session_->GetTransportSocketPool(
HttpNetworkSession::NORMAL_SOCKET_POOL),
BoundNetLog()));
callback.WaitForResult();
EXPECT_EQ(OK,
session_->InitializeWithSocket(connection.release(), false, OK));
UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
HttpRequestInfo request;
request.method = "POST";
request.url = GURL("http://www.google.com/");
request.upload_data_stream = &upload_stream;
ASSERT_EQ(OK, upload_stream.InitSync());
upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
BoundNetLog net_log;
scoped_ptr<SpdyHttpStream> http_stream(
new SpdyHttpStream(session_.get(), true));
ASSERT_EQ(OK, http_stream->InitializeStream(&request, net_log,
CompletionCallback()));
HttpRequestHeaders headers;
HttpResponseInfo response;
// This will attempt to Write() the initial request and headers, which will
// complete asynchronously.
EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
callback.callback()));
EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
// Complete the initial request write and first chunk.
data.RunFor(2);
ASSERT_TRUE(callback.have_result());
EXPECT_GT(callback.WaitForResult(), 0);
// Verify that the window size has decreased.
ASSERT_TRUE(http_stream->stream() != NULL);
EXPECT_NE(static_cast<int>(kSpdyStreamInitialWindowSize),
http_stream->stream()->send_window_size());
// Read window update.
data.RunFor(1);
// Verify the window update.
ASSERT_TRUE(http_stream->stream() != NULL);
EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize),
http_stream->stream()->send_window_size());
// Read response headers.
data.RunFor(1);
ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
// Read and check |chunk1| response.
data.RunFor(1);
scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
ASSERT_EQ(kUploadDataSize,
http_stream->ReadResponseBody(buf1,
kUploadDataSize,
callback.callback()));
EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
// Finish reading the |EOF|.
data.RunFor(1);
ASSERT_TRUE(response.headers.get());
ASSERT_EQ(200, response.headers->response_code());
EXPECT_TRUE(data.at_read_eof());
EXPECT_TRUE(data.at_write_eof());
}
// Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
TEST_F(SpdyHttpStreamSpdy3Test, SpdyURLTest) {
const char * const full_url = "http://www.google.com/foo?query=what#anchor";
const char * const base_url = "http://www.google.com/foo?query=what";
scoped_ptr<SpdyFrame> req(ConstructSpdyGet(base_url, false, 1, LOWEST));
MockWrite writes[] = {
CreateMockWrite(*req.get(), 1),
};
scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
MockRead reads[] = {
CreateMockRead(*resp, 2),
MockRead(SYNCHRONOUS, 0, 3) // EOF
};
HostPortPair host_port_pair("www.google.com", 80);
HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
host_port_pair));
HttpRequestInfo request;
request.method = "GET";
request.url = GURL(full_url);
TestCompletionCallback callback;
HttpResponseInfo response;
HttpRequestHeaders headers;
BoundNetLog net_log;
scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
ASSERT_EQ(
OK,
http_stream->InitializeStream(&request, net_log, CompletionCallback()));
EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
callback.callback()));
const SpdyHeaderBlock& spdy_header =
http_stream->stream()->spdy_headers();
if (spdy_header.find(":path") != spdy_header.end())
EXPECT_EQ("/foo?query=what", spdy_header.find(":path")->second);
else
FAIL() << "No url is set in spdy_header!";
// This triggers the MockWrite and read 2
callback.WaitForResult();
// This triggers read 3. The empty read causes the session to shut down.
data()->CompleteRead();
// Because we abandoned the stream, we don't expect to find a session in the
// pool anymore.
EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
EXPECT_TRUE(data()->at_read_eof());
EXPECT_TRUE(data()->at_write_eof());
}
namespace {
void GetECServerBoundCertAndProof(
const std::string& origin,
ServerBoundCertService* server_bound_cert_service,
std::string* cert,
std::string* proof) {
TestCompletionCallback callback;
std::vector<uint8> requested_cert_types;
requested_cert_types.push_back(CLIENT_CERT_ECDSA_SIGN);
SSLClientCertType cert_type;
std::string key;
ServerBoundCertService::RequestHandle request_handle;
int rv = server_bound_cert_service->GetDomainBoundCert(
origin, requested_cert_types, &cert_type, &key, cert, callback.callback(),
&request_handle);
EXPECT_EQ(ERR_IO_PENDING, rv);
EXPECT_EQ(OK, callback.WaitForResult());
EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, cert_type);
SpdyCredential credential;
SpdyCredentialBuilder::Build(MockClientSocket::kTlsUnique, cert_type, key,
*cert, 2, &credential);
cert->assign(credential.certs[0]);
proof->assign(credential.proof);
}
} // namespace
// Constructs a standard SPDY SYN_STREAM frame for a GET request with
// a credential set.
SpdyFrame* ConstructCredentialRequestFrame(int slot, const GURL& url,
int stream_id) {
const SpdyHeaderInfo syn_headers = {
SYN_STREAM,
stream_id,
0,
ConvertRequestPriorityToSpdyPriority(LOWEST, 3),
slot,
CONTROL_FLAG_FIN,
false,
INVALID,
NULL,
0,
DATA_FLAG_NONE
};
// TODO(rch): this is ugly. Clean up.
std::string str_path = url.PathForRequest();
std::string str_scheme = url.scheme();
std::string str_host = url.host();
if (url.has_port()) {
str_host += ":";
str_host += url.port();
}
scoped_array<char> req(new char[str_path.size() + 1]);
scoped_array<char> scheme(new char[str_scheme.size() + 1]);
scoped_array<char> host(new char[str_host.size() + 1]);
memcpy(req.get(), str_path.c_str(), str_path.size());
memcpy(scheme.get(), str_scheme.c_str(), str_scheme.size());
memcpy(host.get(), str_host.c_str(), str_host.size());
req.get()[str_path.size()] = '\0';
scheme.get()[str_scheme.size()] = '\0';
host.get()[str_host.size()] = '\0';
const char* const headers[] = {
":method",
"GET",
":path",
req.get(),
":host",
host.get(),
":scheme",
scheme.get(),
":version",
"HTTP/1.1"
};
return ConstructSpdyPacket(
syn_headers, NULL, 0, headers, arraysize(headers)/2);
}
// TODO(rch): When openssl supports server bound certifictes, this
// guard can be removed
#if !defined(USE_OPENSSL)
// Test that if we request a resource for a new origin on a session that
// used domain bound certificates, that we send a CREDENTIAL frame for
// the new domain before we send the new request.
void SpdyHttpStreamSpdy3Test::TestSendCredentials(
ServerBoundCertService* server_bound_cert_service,
const std::string& cert,
const std::string& proof) {
const char* kUrl1 = "https://www.google.com/";
const char* kUrl2 = "https://www.gmail.com/";
SpdyCredential cred;
cred.slot = 2;
cred.proof = proof;
cred.certs.push_back(cert);
scoped_ptr<SpdyFrame> req(ConstructCredentialRequestFrame(
1, GURL(kUrl1), 1));
scoped_ptr<SpdyFrame> credential(ConstructSpdyCredential(cred));
scoped_ptr<SpdyFrame> req2(ConstructCredentialRequestFrame(
2, GURL(kUrl2), 3));
MockWrite writes[] = {
CreateMockWrite(*req.get(), 0),
CreateMockWrite(*credential.get(), 2),
CreateMockWrite(*req2.get(), 3),
};
scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
MockRead reads[] = {
CreateMockRead(*resp, 1),
CreateMockRead(*resp2, 4),
MockRead(SYNCHRONOUS, 0, 5) // EOF
};
HostPortPair host_port_pair(HostPortPair::FromURL(GURL(kUrl1)));
HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
DeterministicMockClientSocketFactory* socket_factory =
session_deps_.deterministic_socket_factory.get();
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
socket_factory->AddSocketDataProvider(&data);
SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
ssl.channel_id_sent = true;
ssl.server_bound_cert_service = server_bound_cert_service;
ssl.protocol_negotiated = kProtoSPDY3;
socket_factory->AddSSLSocketDataProvider(&ssl);
http_session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
&session_deps_);
session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
transport_params_ = new TransportSocketParams(host_port_pair,
MEDIUM, false, false,
OnHostResolutionCallback());
TestCompletionCallback callback;
scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
SSLConfig ssl_config;
scoped_refptr<SOCKSSocketParams> socks_params;
scoped_refptr<HttpProxySocketParams> http_proxy_params;
scoped_refptr<SSLSocketParams> ssl_params(
new SSLSocketParams(transport_params_,
socks_params,
http_proxy_params,
ProxyServer::SCHEME_DIRECT,
host_port_pair,
ssl_config,
0,
false,
false));
EXPECT_EQ(ERR_IO_PENDING,
connection->Init(host_port_pair.ToString(),
ssl_params,
MEDIUM,
callback.callback(),
http_session_->GetSSLSocketPool(
HttpNetworkSession::NORMAL_SOCKET_POOL),
BoundNetLog()));
callback.WaitForResult();
EXPECT_EQ(OK,
session_->InitializeWithSocket(connection.release(), true, OK));
HttpRequestInfo request;
request.method = "GET";
request.url = GURL(kUrl1);
HttpResponseInfo response;
HttpRequestHeaders headers;
BoundNetLog net_log;
scoped_ptr<SpdyHttpStream> http_stream(
new SpdyHttpStream(session_.get(), true));
ASSERT_EQ(
OK,
http_stream->InitializeStream(&request, net_log, CompletionCallback()));
// EXPECT_FALSE(session_->NeedsCredentials(request.url));
// GURL new_origin(kUrl2);
// EXPECT_TRUE(session_->NeedsCredentials(new_origin));
EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
callback.callback()));
EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
data.RunFor(2);
callback.WaitForResult();
// Start up second request for resource on a new origin.
scoped_ptr<SpdyHttpStream> http_stream2(
new SpdyHttpStream(session_.get(), true));
request.url = GURL(kUrl2);
ASSERT_EQ(
OK,
http_stream2->InitializeStream(&request, net_log, CompletionCallback()));
EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers, &response,
callback.callback()));
data.RunFor(2);
callback.WaitForResult();
EXPECT_EQ(ERR_IO_PENDING, http_stream2->ReadResponseHeaders(
callback.callback()));
data.RunFor(1);
EXPECT_EQ(OK, callback.WaitForResult());
ASSERT_TRUE(response.headers.get() != NULL);
ASSERT_EQ(200, response.headers->response_code());
}
TEST_F(SpdyHttpStreamSpdy3Test, SendCredentialsEC) {
scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool =
new base::SequencedWorkerPool(1, "SpdyHttpStreamSpdy3Test");
scoped_ptr<ServerBoundCertService> server_bound_cert_service(
new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
sequenced_worker_pool));
std::string cert;
std::string proof;
GetECServerBoundCertAndProof("http://www.gmail.com/",
server_bound_cert_service.get(),
&cert, &proof);
TestSendCredentials(server_bound_cert_service.get(), cert, proof);
sequenced_worker_pool->Shutdown();
}
#endif // !defined(USE_OPENSSL)
// TODO(willchan): Write a longer test for SpdyStream that exercises all
// methods.
} // namespace net