1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/spdy/spdy_http_stream.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/threading/sequenced_worker_pool.h"
9 #include "crypto/ec_private_key.h"
10 #include "crypto/ec_signature_creator.h"
11 #include "crypto/signature_creator.h"
12 #include "net/base/asn1_util.h"
13 #include "net/base/default_server_bound_cert_store.h"
14 #include "net/base/upload_data_stream.h"
15 #include "net/base/upload_element_reader.h"
16 #include "net/http/http_request_info.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/http/http_response_info.h"
19 #include "net/spdy/spdy_credential_builder.h"
20 #include "net/spdy/spdy_http_utils.h"
21 #include "net/spdy/spdy_session.h"
22 #include "net/spdy/spdy_test_util_spdy3.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 using namespace net::test_spdy3
;
29 class SpdyHttpStreamSpdy3Test
: public testing::Test
{
31 OrderedSocketData
* data() { return data_
.get(); }
34 virtual void TearDown() {
35 UploadDataStream::ResetMergeChunks();
36 MessageLoop::current()->RunUntilIdle();
39 void set_merge_chunks(bool merge
) {
40 UploadDataStream::set_merge_chunks(merge
);
43 int InitSession(MockRead
* reads
, size_t reads_count
,
44 MockWrite
* writes
, size_t writes_count
,
45 HostPortPair
& host_port_pair
) {
46 HostPortProxyPair
pair(host_port_pair
, ProxyServer::Direct());
47 data_
.reset(new OrderedSocketData(reads
, reads_count
,
48 writes
, writes_count
));
49 session_deps_
.socket_factory
->AddSocketDataProvider(data_
.get());
50 http_session_
= SpdySessionDependencies::SpdyCreateSession(&session_deps_
);
51 session_
= http_session_
->spdy_session_pool()->Get(pair
, BoundNetLog());
52 transport_params_
= new TransportSocketParams(host_port_pair
,
54 OnHostResolutionCallback());
55 TestCompletionCallback callback
;
56 scoped_ptr
<ClientSocketHandle
> connection(new ClientSocketHandle
);
57 EXPECT_EQ(ERR_IO_PENDING
,
58 connection
->Init(host_port_pair
.ToString(),
62 http_session_
->GetTransportSocketPool(
63 HttpNetworkSession::NORMAL_SOCKET_POOL
),
65 EXPECT_EQ(OK
, callback
.WaitForResult());
66 return session_
->InitializeWithSocket(connection
.release(), false, OK
);
69 void TestSendCredentials(
70 ServerBoundCertService
* server_bound_cert_service
,
71 const std::string
& cert
,
72 const std::string
& proof
);
74 SpdySessionDependencies session_deps_
;
75 scoped_ptr
<OrderedSocketData
> data_
;
76 scoped_refptr
<HttpNetworkSession
> http_session_
;
77 scoped_refptr
<SpdySession
> session_
;
78 scoped_refptr
<TransportSocketParams
> transport_params_
;
81 MockECSignatureCreatorFactory ec_signature_creator_factory_
;
84 TEST_F(SpdyHttpStreamSpdy3Test
, SendRequest
) {
85 scoped_ptr
<SpdyFrame
> req(ConstructSpdyGet(NULL
, 0, false, 1, LOWEST
));
86 MockWrite writes
[] = {
87 CreateMockWrite(*req
.get(), 1),
89 scoped_ptr
<SpdyFrame
> resp(ConstructSpdyGetSynReply(NULL
, 0, 1));
91 CreateMockRead(*resp
, 2),
92 MockRead(SYNCHRONOUS
, 0, 3) // EOF
95 HostPortPair
host_port_pair("www.google.com", 80);
96 HostPortProxyPair
pair(host_port_pair
, ProxyServer::Direct());
97 EXPECT_EQ(OK
, InitSession(reads
, arraysize(reads
), writes
, arraysize(writes
),
100 HttpRequestInfo request
;
101 request
.method
= "GET";
102 request
.url
= GURL("http://www.google.com/");
103 TestCompletionCallback callback
;
104 HttpResponseInfo response
;
105 HttpRequestHeaders headers
;
107 scoped_ptr
<SpdyHttpStream
> http_stream(
108 new SpdyHttpStream(session_
.get(), true));
111 http_stream
->InitializeStream(&request
, net_log
, CompletionCallback()));
113 EXPECT_EQ(ERR_IO_PENDING
, http_stream
->SendRequest(headers
, &response
,
114 callback
.callback()));
115 EXPECT_TRUE(http_session_
->spdy_session_pool()->HasSession(pair
));
117 // This triggers the MockWrite and read 2
118 callback
.WaitForResult();
120 // This triggers read 3. The empty read causes the session to shut down.
121 data()->CompleteRead();
123 // Because we abandoned the stream, we don't expect to find a session in the
125 EXPECT_FALSE(http_session_
->spdy_session_pool()->HasSession(pair
));
126 EXPECT_TRUE(data()->at_read_eof());
127 EXPECT_TRUE(data()->at_write_eof());
130 TEST_F(SpdyHttpStreamSpdy3Test
, SendChunkedPost
) {
131 set_merge_chunks(false);
133 scoped_ptr
<SpdyFrame
> req(ConstructChunkedSpdyPost(NULL
, 0));
134 scoped_ptr
<SpdyFrame
> chunk1(ConstructSpdyBodyFrame(1, false));
135 scoped_ptr
<SpdyFrame
> chunk2(ConstructSpdyBodyFrame(1, true));
136 MockWrite writes
[] = {
137 CreateMockWrite(*req
.get(), 0),
138 CreateMockWrite(*chunk1
, 1), // POST upload frames
139 CreateMockWrite(*chunk2
, 2),
141 scoped_ptr
<SpdyFrame
> resp(ConstructSpdyPostSynReply(NULL
, 0));
143 CreateMockRead(*resp
, 3),
144 CreateMockRead(*chunk1
, 4),
145 CreateMockRead(*chunk2
, 5),
146 MockRead(SYNCHRONOUS
, 0, 6) // EOF
149 HostPortPair
host_port_pair("www.google.com", 80);
150 HostPortProxyPair
pair(host_port_pair
, ProxyServer::Direct());
151 EXPECT_EQ(OK
, InitSession(reads
, arraysize(reads
), writes
, arraysize(writes
),
154 UploadDataStream
upload_stream(UploadDataStream::CHUNKED
, 0);
155 upload_stream
.AppendChunk(kUploadData
, kUploadDataSize
, false);
156 upload_stream
.AppendChunk(kUploadData
, kUploadDataSize
, true);
158 HttpRequestInfo request
;
159 request
.method
= "POST";
160 request
.url
= GURL("http://www.google.com/");
161 request
.upload_data_stream
= &upload_stream
;
163 ASSERT_EQ(OK
, upload_stream
.Init(CompletionCallback()));
165 TestCompletionCallback callback
;
166 HttpResponseInfo response
;
167 HttpRequestHeaders headers
;
169 SpdyHttpStream
http_stream(session_
.get(), true);
172 http_stream
.InitializeStream(&request
, net_log
, CompletionCallback()));
174 EXPECT_EQ(ERR_IO_PENDING
, http_stream
.SendRequest(
175 headers
, &response
, callback
.callback()));
176 EXPECT_TRUE(http_session_
->spdy_session_pool()->HasSession(pair
));
178 // This triggers the MockWrite and read 2
179 callback
.WaitForResult();
181 // This triggers read 3. The empty read causes the session to shut down.
182 data()->CompleteRead();
183 MessageLoop::current()->RunUntilIdle();
185 // Because we abandoned the stream, we don't expect to find a session in the
187 EXPECT_FALSE(http_session_
->spdy_session_pool()->HasSession(pair
));
188 EXPECT_TRUE(data()->at_read_eof());
189 EXPECT_TRUE(data()->at_write_eof());
192 // Test to ensure the SpdyStream state machine does not get confused when a
193 // chunk becomes available while a write is pending.
194 TEST_F(SpdyHttpStreamSpdy3Test
, DelayedSendChunkedPost
) {
195 set_merge_chunks(false);
197 const char kUploadData1
[] = "12345678";
198 const int kUploadData1Size
= arraysize(kUploadData1
)-1;
199 scoped_ptr
<SpdyFrame
> req(ConstructChunkedSpdyPost(NULL
, 0));
200 scoped_ptr
<SpdyFrame
> chunk1(ConstructSpdyBodyFrame(1, false));
201 scoped_ptr
<SpdyFrame
> chunk2(
202 ConstructSpdyBodyFrame(1, kUploadData1
, kUploadData1Size
, false));
203 scoped_ptr
<SpdyFrame
> chunk3(ConstructSpdyBodyFrame(1, true));
204 MockWrite writes
[] = {
205 CreateMockWrite(*req
.get(), 0),
206 CreateMockWrite(*chunk1
, 1), // POST upload frames
207 CreateMockWrite(*chunk2
, 2),
208 CreateMockWrite(*chunk3
, 3),
210 scoped_ptr
<SpdyFrame
> resp(ConstructSpdyPostSynReply(NULL
, 0));
212 CreateMockRead(*resp
, 4),
213 CreateMockRead(*chunk1
, 5),
214 CreateMockRead(*chunk2
, 6),
215 CreateMockRead(*chunk3
, 7),
216 MockRead(ASYNC
, 0, 8) // EOF
219 HostPortPair
host_port_pair("www.google.com", 80);
220 HostPortProxyPair
pair(host_port_pair
, ProxyServer::Direct());
222 DeterministicSocketData
data(reads
, arraysize(reads
),
223 writes
, arraysize(writes
));
225 DeterministicMockClientSocketFactory
* socket_factory
=
226 session_deps_
.deterministic_socket_factory
.get();
227 socket_factory
->AddSocketDataProvider(&data
);
229 http_session_
= SpdySessionDependencies::SpdyCreateSessionDeterministic(
231 session_
= http_session_
->spdy_session_pool()->Get(pair
, BoundNetLog());
232 transport_params_
= new TransportSocketParams(host_port_pair
,
233 MEDIUM
, false, false,
234 OnHostResolutionCallback());
236 TestCompletionCallback callback
;
237 scoped_ptr
<ClientSocketHandle
> connection(new ClientSocketHandle
);
239 EXPECT_EQ(ERR_IO_PENDING
,
240 connection
->Init(host_port_pair
.ToString(),
244 http_session_
->GetTransportSocketPool(
245 HttpNetworkSession::NORMAL_SOCKET_POOL
),
248 callback
.WaitForResult();
250 session_
->InitializeWithSocket(connection
.release(), false, OK
));
252 UploadDataStream
upload_stream(UploadDataStream::CHUNKED
, 0);
254 HttpRequestInfo request
;
255 request
.method
= "POST";
256 request
.url
= GURL("http://www.google.com/");
257 request
.upload_data_stream
= &upload_stream
;
259 ASSERT_EQ(OK
, upload_stream
.Init(CompletionCallback()));
260 upload_stream
.AppendChunk(kUploadData
, kUploadDataSize
, false);
263 scoped_ptr
<SpdyHttpStream
> http_stream(
264 new SpdyHttpStream(session_
.get(), true));
265 ASSERT_EQ(OK
, http_stream
->InitializeStream(&request
,
267 CompletionCallback()));
269 HttpRequestHeaders headers
;
270 HttpResponseInfo response
;
271 // This will attempt to Write() the initial request and headers, which will
272 // complete asynchronously.
273 EXPECT_EQ(ERR_IO_PENDING
, http_stream
->SendRequest(headers
, &response
,
274 callback
.callback()));
275 EXPECT_TRUE(http_session_
->spdy_session_pool()->HasSession(pair
));
277 // Complete the initial request write and the first chunk.
279 ASSERT_TRUE(callback
.have_result());
280 EXPECT_GT(callback
.WaitForResult(), 0);
282 // Now append the final two chunks which will enqueue two more writes.
283 upload_stream
.AppendChunk(kUploadData1
, kUploadData1Size
, false);
284 upload_stream
.AppendChunk(kUploadData
, kUploadDataSize
, true);
286 // Finish writing all the chunks.
289 // Read response headers.
291 ASSERT_EQ(OK
, http_stream
->ReadResponseHeaders(callback
.callback()));
293 // Read and check |chunk1| response.
295 scoped_refptr
<IOBuffer
> buf1(new IOBuffer(kUploadDataSize
));
296 ASSERT_EQ(kUploadDataSize
,
297 http_stream
->ReadResponseBody(buf1
,
299 callback
.callback()));
300 EXPECT_EQ(kUploadData
, std::string(buf1
->data(), kUploadDataSize
));
302 // Read and check |chunk2| response.
304 scoped_refptr
<IOBuffer
> buf2(new IOBuffer(kUploadData1Size
));
305 ASSERT_EQ(kUploadData1Size
,
306 http_stream
->ReadResponseBody(buf2
,
308 callback
.callback()));
309 EXPECT_EQ(kUploadData1
, std::string(buf2
->data(), kUploadData1Size
));
311 // Read and check |chunk3| response.
313 scoped_refptr
<IOBuffer
> buf3(new IOBuffer(kUploadDataSize
));
314 ASSERT_EQ(kUploadDataSize
,
315 http_stream
->ReadResponseBody(buf3
,
317 callback
.callback()));
318 EXPECT_EQ(kUploadData
, std::string(buf3
->data(), kUploadDataSize
));
320 // Finish reading the |EOF|.
322 ASSERT_TRUE(response
.headers
.get());
323 ASSERT_EQ(200, response
.headers
->response_code());
324 EXPECT_TRUE(data
.at_read_eof());
325 EXPECT_TRUE(data
.at_write_eof());
328 // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
329 // made available is handled correctly.
330 TEST_F(SpdyHttpStreamSpdy3Test
, DelayedSendChunkedPostWithWindowUpdate
) {
331 set_merge_chunks(false);
333 scoped_ptr
<SpdyFrame
> req(ConstructChunkedSpdyPost(NULL
, 0));
334 scoped_ptr
<SpdyFrame
> chunk1(ConstructSpdyBodyFrame(1, true));
335 MockWrite writes
[] = {
336 CreateMockWrite(*req
.get(), 0),
337 CreateMockWrite(*chunk1
, 1),
339 scoped_ptr
<SpdyFrame
> resp(ConstructSpdyPostSynReply(NULL
, 0));
340 scoped_ptr
<SpdyFrame
> window_update(
341 ConstructSpdyWindowUpdate(1, kUploadDataSize
));
343 CreateMockRead(*window_update
, 2),
344 CreateMockRead(*resp
, 3),
345 CreateMockRead(*chunk1
, 4),
346 MockRead(ASYNC
, 0, 5) // EOF
349 HostPortPair
host_port_pair("www.google.com", 80);
350 HostPortProxyPair
pair(host_port_pair
, ProxyServer::Direct());
352 DeterministicSocketData
data(reads
, arraysize(reads
),
353 writes
, arraysize(writes
));
355 DeterministicMockClientSocketFactory
* socket_factory
=
356 session_deps_
.deterministic_socket_factory
.get();
357 socket_factory
->AddSocketDataProvider(&data
);
359 http_session_
= SpdySessionDependencies::SpdyCreateSessionDeterministic(
361 session_
= http_session_
->spdy_session_pool()->Get(pair
, BoundNetLog());
362 transport_params_
= new TransportSocketParams(host_port_pair
,
363 MEDIUM
, false, false,
364 OnHostResolutionCallback());
366 TestCompletionCallback callback
;
367 scoped_ptr
<ClientSocketHandle
> connection(new ClientSocketHandle
);
369 EXPECT_EQ(ERR_IO_PENDING
,
370 connection
->Init(host_port_pair
.ToString(),
374 http_session_
->GetTransportSocketPool(
375 HttpNetworkSession::NORMAL_SOCKET_POOL
),
378 callback
.WaitForResult();
380 session_
->InitializeWithSocket(connection
.release(), false, OK
));
382 UploadDataStream
upload_stream(UploadDataStream::CHUNKED
, 0);
384 HttpRequestInfo request
;
385 request
.method
= "POST";
386 request
.url
= GURL("http://www.google.com/");
387 request
.upload_data_stream
= &upload_stream
;
389 ASSERT_EQ(OK
, upload_stream
.Init(CompletionCallback()));
390 upload_stream
.AppendChunk(kUploadData
, kUploadDataSize
, true);
393 scoped_ptr
<SpdyHttpStream
> http_stream(
394 new SpdyHttpStream(session_
.get(), true));
395 ASSERT_EQ(OK
, http_stream
->InitializeStream(&request
, net_log
,
396 CompletionCallback()));
398 HttpRequestHeaders headers
;
399 HttpResponseInfo response
;
400 // This will attempt to Write() the initial request and headers, which will
401 // complete asynchronously.
402 EXPECT_EQ(ERR_IO_PENDING
, http_stream
->SendRequest(headers
, &response
,
403 callback
.callback()));
404 EXPECT_TRUE(http_session_
->spdy_session_pool()->HasSession(pair
));
406 // Complete the initial request write and first chunk.
408 ASSERT_TRUE(callback
.have_result());
409 EXPECT_GT(callback
.WaitForResult(), 0);
411 // Verify that the window size has decreased.
412 ASSERT_TRUE(http_stream
->stream() != NULL
);
413 EXPECT_NE(static_cast<int>(kSpdyStreamInitialWindowSize
),
414 http_stream
->stream()->send_window_size());
416 // Read window update.
419 // Verify the window update.
420 ASSERT_TRUE(http_stream
->stream() != NULL
);
421 EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize
),
422 http_stream
->stream()->send_window_size());
424 // Read response headers.
426 ASSERT_EQ(OK
, http_stream
->ReadResponseHeaders(callback
.callback()));
428 // Read and check |chunk1| response.
430 scoped_refptr
<IOBuffer
> buf1(new IOBuffer(kUploadDataSize
));
431 ASSERT_EQ(kUploadDataSize
,
432 http_stream
->ReadResponseBody(buf1
,
434 callback
.callback()));
435 EXPECT_EQ(kUploadData
, std::string(buf1
->data(), kUploadDataSize
));
437 // Finish reading the |EOF|.
439 ASSERT_TRUE(response
.headers
.get());
440 ASSERT_EQ(200, response
.headers
->response_code());
441 EXPECT_TRUE(data
.at_read_eof());
442 EXPECT_TRUE(data
.at_write_eof());
445 // Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
446 TEST_F(SpdyHttpStreamSpdy3Test
, SpdyURLTest
) {
447 const char * const full_url
= "http://www.google.com/foo?query=what#anchor";
448 const char * const base_url
= "http://www.google.com/foo?query=what";
449 scoped_ptr
<SpdyFrame
> req(ConstructSpdyGet(base_url
, false, 1, LOWEST
));
450 MockWrite writes
[] = {
451 CreateMockWrite(*req
.get(), 1),
453 scoped_ptr
<SpdyFrame
> resp(ConstructSpdyGetSynReply(NULL
, 0, 1));
455 CreateMockRead(*resp
, 2),
456 MockRead(SYNCHRONOUS
, 0, 3) // EOF
459 HostPortPair
host_port_pair("www.google.com", 80);
460 HostPortProxyPair
pair(host_port_pair
, ProxyServer::Direct());
461 EXPECT_EQ(OK
, InitSession(reads
, arraysize(reads
), writes
, arraysize(writes
),
464 HttpRequestInfo request
;
465 request
.method
= "GET";
466 request
.url
= GURL(full_url
);
467 TestCompletionCallback callback
;
468 HttpResponseInfo response
;
469 HttpRequestHeaders headers
;
471 scoped_ptr
<SpdyHttpStream
> http_stream(new SpdyHttpStream(session_
, true));
474 http_stream
->InitializeStream(&request
, net_log
, CompletionCallback()));
476 EXPECT_EQ(ERR_IO_PENDING
, http_stream
->SendRequest(headers
, &response
,
477 callback
.callback()));
479 const SpdyHeaderBlock
& spdy_header
=
480 http_stream
->stream()->spdy_headers();
481 if (spdy_header
.find(":path") != spdy_header
.end())
482 EXPECT_EQ("/foo?query=what", spdy_header
.find(":path")->second
);
484 FAIL() << "No url is set in spdy_header!";
486 // This triggers the MockWrite and read 2
487 callback
.WaitForResult();
489 // This triggers read 3. The empty read causes the session to shut down.
490 data()->CompleteRead();
492 // Because we abandoned the stream, we don't expect to find a session in the
494 EXPECT_FALSE(http_session_
->spdy_session_pool()->HasSession(pair
));
495 EXPECT_TRUE(data()->at_read_eof());
496 EXPECT_TRUE(data()->at_write_eof());
501 void GetECServerBoundCertAndProof(
502 const std::string
& origin
,
503 ServerBoundCertService
* server_bound_cert_service
,
505 std::string
* proof
) {
506 TestCompletionCallback callback
;
507 std::vector
<uint8
> requested_cert_types
;
508 requested_cert_types
.push_back(CLIENT_CERT_ECDSA_SIGN
);
509 SSLClientCertType cert_type
;
511 ServerBoundCertService::RequestHandle request_handle
;
512 int rv
= server_bound_cert_service
->GetDomainBoundCert(
513 origin
, requested_cert_types
, &cert_type
, &key
, cert
, callback
.callback(),
515 EXPECT_EQ(ERR_IO_PENDING
, rv
);
516 EXPECT_EQ(OK
, callback
.WaitForResult());
517 EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN
, cert_type
);
519 SpdyCredential credential
;
520 SpdyCredentialBuilder::Build(MockClientSocket::kTlsUnique
, cert_type
, key
,
521 *cert
, 2, &credential
);
523 cert
->assign(credential
.certs
[0]);
524 proof
->assign(credential
.proof
);
529 // Constructs a standard SPDY SYN_STREAM frame for a GET request with
531 SpdyFrame
* ConstructCredentialRequestFrame(size_t slot
, const GURL
& url
,
532 SpdyStreamId stream_id
) {
533 const SpdyHeaderInfo syn_headers
= {
537 ConvertRequestPriorityToSpdyPriority(LOWEST
, 3),
547 // TODO(rch): this is ugly. Clean up.
548 std::string str_path
= url
.PathForRequest();
549 std::string str_scheme
= url
.scheme();
550 std::string str_host
= url
.host();
551 if (url
.has_port()) {
553 str_host
+= url
.port();
555 scoped_array
<char> req(new char[str_path
.size() + 1]);
556 scoped_array
<char> scheme(new char[str_scheme
.size() + 1]);
557 scoped_array
<char> host(new char[str_host
.size() + 1]);
558 memcpy(req
.get(), str_path
.c_str(), str_path
.size());
559 memcpy(scheme
.get(), str_scheme
.c_str(), str_scheme
.size());
560 memcpy(host
.get(), str_host
.c_str(), str_host
.size());
561 req
.get()[str_path
.size()] = '\0';
562 scheme
.get()[str_scheme
.size()] = '\0';
563 host
.get()[str_host
.size()] = '\0';
565 const char* const headers
[] = {
577 return ConstructSpdyPacket(
578 syn_headers
, NULL
, 0, headers
, arraysize(headers
)/2);
581 // TODO(rch): When openssl supports server bound certifictes, this
582 // guard can be removed
583 #if !defined(USE_OPENSSL)
584 // Test that if we request a resource for a new origin on a session that
585 // used domain bound certificates, that we send a CREDENTIAL frame for
586 // the new domain before we send the new request.
587 void SpdyHttpStreamSpdy3Test::TestSendCredentials(
588 ServerBoundCertService
* server_bound_cert_service
,
589 const std::string
& cert
,
590 const std::string
& proof
) {
591 const char* kUrl1
= "https://www.google.com/";
592 const char* kUrl2
= "https://www.gmail.com/";
597 cred
.certs
.push_back(cert
);
599 scoped_ptr
<SpdyFrame
> req(ConstructCredentialRequestFrame(
601 scoped_ptr
<SpdyFrame
> credential(ConstructSpdyCredential(cred
));
602 scoped_ptr
<SpdyFrame
> req2(ConstructCredentialRequestFrame(
604 MockWrite writes
[] = {
605 CreateMockWrite(*req
.get(), 0),
606 CreateMockWrite(*credential
.get(), 2),
607 CreateMockWrite(*req2
.get(), 3),
610 scoped_ptr
<SpdyFrame
> resp(ConstructSpdyGetSynReply(NULL
, 0, 1));
611 scoped_ptr
<SpdyFrame
> resp2(ConstructSpdyGetSynReply(NULL
, 0, 3));
613 CreateMockRead(*resp
, 1),
614 CreateMockRead(*resp2
, 4),
615 MockRead(SYNCHRONOUS
, 0, 5) // EOF
618 HostPortPair
host_port_pair(HostPortPair::FromURL(GURL(kUrl1
)));
619 HostPortProxyPair
pair(host_port_pair
, ProxyServer::Direct());
621 DeterministicMockClientSocketFactory
* socket_factory
=
622 session_deps_
.deterministic_socket_factory
.get();
623 DeterministicSocketData
data(reads
, arraysize(reads
),
624 writes
, arraysize(writes
));
625 socket_factory
->AddSocketDataProvider(&data
);
626 SSLSocketDataProvider
ssl(SYNCHRONOUS
, OK
);
627 ssl
.channel_id_sent
= true;
628 ssl
.server_bound_cert_service
= server_bound_cert_service
;
629 ssl
.protocol_negotiated
= kProtoSPDY3
;
630 socket_factory
->AddSSLSocketDataProvider(&ssl
);
631 http_session_
= SpdySessionDependencies::SpdyCreateSessionDeterministic(
633 session_
= http_session_
->spdy_session_pool()->Get(pair
, BoundNetLog());
634 transport_params_
= new TransportSocketParams(host_port_pair
,
635 MEDIUM
, false, false,
636 OnHostResolutionCallback());
637 TestCompletionCallback callback
;
638 scoped_ptr
<ClientSocketHandle
> connection(new ClientSocketHandle
);
639 SSLConfig ssl_config
;
640 scoped_refptr
<SOCKSSocketParams
> socks_params
;
641 scoped_refptr
<HttpProxySocketParams
> http_proxy_params
;
642 scoped_refptr
<SSLSocketParams
> ssl_params(
643 new SSLSocketParams(transport_params_
,
646 ProxyServer::SCHEME_DIRECT
,
652 EXPECT_EQ(ERR_IO_PENDING
,
653 connection
->Init(host_port_pair
.ToString(),
657 http_session_
->GetSSLSocketPool(
658 HttpNetworkSession::NORMAL_SOCKET_POOL
),
660 callback
.WaitForResult();
662 session_
->InitializeWithSocket(connection
.release(), true, OK
));
664 HttpRequestInfo request
;
665 request
.method
= "GET";
666 request
.url
= GURL(kUrl1
);
667 HttpResponseInfo response
;
668 HttpRequestHeaders headers
;
670 scoped_ptr
<SpdyHttpStream
> http_stream(
671 new SpdyHttpStream(session_
.get(), true));
674 http_stream
->InitializeStream(&request
, net_log
, CompletionCallback()));
676 // EXPECT_FALSE(session_->NeedsCredentials(request.url));
677 // GURL new_origin(kUrl2);
678 // EXPECT_TRUE(session_->NeedsCredentials(new_origin));
680 EXPECT_EQ(ERR_IO_PENDING
, http_stream
->SendRequest(headers
, &response
,
681 callback
.callback()));
682 EXPECT_TRUE(http_session_
->spdy_session_pool()->HasSession(pair
));
685 callback
.WaitForResult();
687 // Start up second request for resource on a new origin.
688 scoped_ptr
<SpdyHttpStream
> http_stream2(
689 new SpdyHttpStream(session_
.get(), true));
690 request
.url
= GURL(kUrl2
);
693 http_stream2
->InitializeStream(&request
, net_log
, CompletionCallback()));
694 EXPECT_EQ(ERR_IO_PENDING
, http_stream2
->SendRequest(headers
, &response
,
695 callback
.callback()));
697 callback
.WaitForResult();
699 EXPECT_EQ(ERR_IO_PENDING
, http_stream2
->ReadResponseHeaders(
700 callback
.callback()));
702 EXPECT_EQ(OK
, callback
.WaitForResult());
703 ASSERT_TRUE(response
.headers
.get() != NULL
);
704 ASSERT_EQ(200, response
.headers
->response_code());
707 TEST_F(SpdyHttpStreamSpdy3Test
, SendCredentialsEC
) {
708 scoped_refptr
<base::SequencedWorkerPool
> sequenced_worker_pool
=
709 new base::SequencedWorkerPool(1, "SpdyHttpStreamSpdy3Test");
710 scoped_ptr
<ServerBoundCertService
> server_bound_cert_service(
711 new ServerBoundCertService(new DefaultServerBoundCertStore(NULL
),
712 sequenced_worker_pool
));
715 GetECServerBoundCertAndProof("http://www.gmail.com/",
716 server_bound_cert_service
.get(),
719 TestSendCredentials(server_bound_cert_service
.get(), cert
, proof
);
721 sequenced_worker_pool
->Shutdown();
724 #endif // !defined(USE_OPENSSL)
726 // TODO(willchan): Write a longer test for SpdyStream that exercises all