Revert "Merged all Chromoting Host code into remoting_core.dll (Windows)."
[chromium-blink-merge.git] / net / spdy / spdy_http_stream_spdy3_unittest.cc
blob4c312476b39dcb2ce0bd3b0d1a94a3a8e9866721
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/capturing_net_log.h"
14 #include "net/base/default_server_bound_cert_store.h"
15 #include "net/base/load_timing_info.h"
16 #include "net/base/load_timing_info_test_util.h"
17 #include "net/base/upload_data_stream.h"
18 #include "net/base/upload_element_reader.h"
19 #include "net/http/http_request_info.h"
20 #include "net/http/http_response_headers.h"
21 #include "net/http/http_response_info.h"
22 #include "net/spdy/spdy_credential_builder.h"
23 #include "net/spdy/spdy_http_utils.h"
24 #include "net/spdy/spdy_session.h"
25 #include "net/spdy/spdy_test_util_spdy3.h"
26 #include "testing/gtest/include/gtest/gtest.h"
28 using namespace net::test_spdy3;
30 namespace net {
32 namespace {
34 // Tests the load timing of a stream that's connected and is not the first
35 // request sent on a connection.
36 void TestLoadTimingReused(const HttpStream& stream) {
37 LoadTimingInfo load_timing_info;
38 EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
40 EXPECT_TRUE(load_timing_info.socket_reused);
41 EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
43 ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
44 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
47 // Tests the load timing of a stream that's connected and using a fresh
48 // connection.
49 void TestLoadTimingNotReused(const HttpStream& stream) {
50 LoadTimingInfo load_timing_info;
51 EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
53 EXPECT_FALSE(load_timing_info.socket_reused);
54 EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
56 ExpectConnectTimingHasTimes(load_timing_info.connect_timing,
57 CONNECT_TIMING_HAS_DNS_TIMES);
58 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
61 } // namespace
63 class SpdyHttpStreamSpdy3Test : public testing::Test {
64 public:
65 SpdyHttpStreamSpdy3Test() {
66 session_deps_.net_log = &net_log_;
69 DeterministicSocketData* deterministic_data() {
70 return deterministic_data_.get();
73 OrderedSocketData* data() { return data_.get(); }
75 protected:
76 virtual void TearDown() {
77 UploadDataStream::ResetMergeChunks();
78 MessageLoop::current()->RunUntilIdle();
81 void set_merge_chunks(bool merge) {
82 UploadDataStream::set_merge_chunks(merge);
85 // Initializes the session using DeterministicSocketData. It's advisable
86 // to use this function rather than the OrderedSocketData, since the
87 // DeterministicSocketData behaves in a reasonable manner.
88 int InitSessionDeterministic(MockRead* reads, size_t reads_count,
89 MockWrite* writes, size_t writes_count,
90 HostPortPair& host_port_pair) {
91 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
92 deterministic_data_.reset(
93 new DeterministicSocketData(reads, reads_count, writes, writes_count));
94 session_deps_.deterministic_socket_factory->AddSocketDataProvider(
95 deterministic_data_.get());
96 http_session_ =
97 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
98 session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
99 transport_params_ = new TransportSocketParams(host_port_pair,
100 MEDIUM, false, false,
101 OnHostResolutionCallback());
102 TestCompletionCallback callback;
103 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
104 EXPECT_EQ(ERR_IO_PENDING,
105 connection->Init(host_port_pair.ToString(),
106 transport_params_,
107 MEDIUM,
108 callback.callback(),
109 http_session_->GetTransportSocketPool(
110 HttpNetworkSession::NORMAL_SOCKET_POOL),
111 BoundNetLog()));
112 EXPECT_EQ(OK, callback.WaitForResult());
113 return session_->InitializeWithSocket(connection.release(), false, OK);
116 // Initializes the session using the finicky OrderedSocketData class.
117 int InitSession(MockRead* reads, size_t reads_count,
118 MockWrite* writes, size_t writes_count,
119 HostPortPair& host_port_pair) {
120 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
121 data_.reset(new OrderedSocketData(reads, reads_count,
122 writes, writes_count));
123 session_deps_.socket_factory->AddSocketDataProvider(data_.get());
124 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
125 session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
126 transport_params_ = new TransportSocketParams(host_port_pair,
127 MEDIUM, false, false,
128 OnHostResolutionCallback());
129 TestCompletionCallback callback;
130 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
131 EXPECT_EQ(ERR_IO_PENDING,
132 connection->Init(host_port_pair.ToString(),
133 transport_params_,
134 MEDIUM,
135 callback.callback(),
136 http_session_->GetTransportSocketPool(
137 HttpNetworkSession::NORMAL_SOCKET_POOL),
138 BoundNetLog()));
139 EXPECT_EQ(OK, callback.WaitForResult());
140 return session_->InitializeWithSocket(connection.release(), false, OK);
143 void TestSendCredentials(
144 ServerBoundCertService* server_bound_cert_service,
145 const std::string& cert,
146 const std::string& proof);
148 CapturingNetLog net_log_;
149 SpdySessionDependencies session_deps_;
150 scoped_ptr<OrderedSocketData> data_;
151 scoped_ptr<DeterministicSocketData> deterministic_data_;
152 scoped_refptr<HttpNetworkSession> http_session_;
153 scoped_refptr<SpdySession> session_;
154 scoped_refptr<TransportSocketParams> transport_params_;
156 private:
157 MockECSignatureCreatorFactory ec_signature_creator_factory_;
160 TEST_F(SpdyHttpStreamSpdy3Test, SendRequest) {
161 scoped_ptr<SpdyFrame> req(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
162 MockWrite writes[] = {
163 CreateMockWrite(*req.get(), 1),
165 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
166 MockRead reads[] = {
167 CreateMockRead(*resp, 2),
168 MockRead(SYNCHRONOUS, 0, 3) // EOF
171 HostPortPair host_port_pair("www.google.com", 80);
172 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
173 EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
174 host_port_pair));
176 HttpRequestInfo request;
177 request.method = "GET";
178 request.url = GURL("http://www.google.com/");
179 TestCompletionCallback callback;
180 HttpResponseInfo response;
181 HttpRequestHeaders headers;
182 BoundNetLog net_log;
183 scoped_ptr<SpdyHttpStream> http_stream(
184 new SpdyHttpStream(session_.get(), true));
185 // Make sure getting load timing information the stream early does not crash.
186 LoadTimingInfo load_timing_info;
187 EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
189 ASSERT_EQ(
191 http_stream->InitializeStream(&request, net_log, CompletionCallback()));
192 EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
194 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
195 callback.callback()));
196 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
197 EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
199 // This triggers the MockWrite and read 2
200 callback.WaitForResult();
202 // Can get timing information once the stream connects.
203 TestLoadTimingNotReused(*http_stream);
205 // This triggers read 3. The empty read causes the session to shut down.
206 data()->CompleteRead();
208 // Because we abandoned the stream, we don't expect to find a session in the
209 // pool anymore.
210 EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
211 EXPECT_TRUE(data()->at_read_eof());
212 EXPECT_TRUE(data()->at_write_eof());
214 TestLoadTimingNotReused(*http_stream);
215 http_stream->Close(true);
216 // Test that there's no crash when trying to get the load timing after the
217 // stream has been closed.
218 TestLoadTimingNotReused(*http_stream);
221 TEST_F(SpdyHttpStreamSpdy3Test, LoadTimingTwoRequests) {
222 scoped_ptr<SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, LOWEST));
223 scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST));
224 MockWrite writes[] = {
225 CreateMockWrite(*req1, 0),
226 CreateMockWrite(*req2, 1),
228 scoped_ptr<SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1));
229 scoped_ptr<SpdyFrame> body1(ConstructSpdyBodyFrame(1, "", 0, true));
230 scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
231 scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(3, "", 0, true));
232 MockRead reads[] = {
233 CreateMockRead(*resp1, 2),
234 CreateMockRead(*body1, 3),
235 CreateMockRead(*resp2, 4),
236 CreateMockRead(*body2, 5),
237 MockRead(ASYNC, 0, 6) // EOF
240 HostPortPair host_port_pair("www.google.com", 80);
241 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
242 ASSERT_EQ(OK, InitSessionDeterministic(reads, arraysize(reads),
243 writes, arraysize(writes),
244 host_port_pair));
246 HttpRequestInfo request1;
247 request1.method = "GET";
248 request1.url = GURL("http://www.google.com/");
249 TestCompletionCallback callback1;
250 HttpResponseInfo response1;
251 HttpRequestHeaders headers1;
252 scoped_ptr<SpdyHttpStream> http_stream1(
253 new SpdyHttpStream(session_.get(), true));
255 ASSERT_EQ(OK,
256 http_stream1->InitializeStream(&request1, BoundNetLog(),
257 CompletionCallback()));
258 EXPECT_EQ(ERR_IO_PENDING, http_stream1->SendRequest(headers1, &response1,
259 callback1.callback()));
260 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
262 HttpRequestInfo request2;
263 request2.method = "GET";
264 request2.url = GURL("http://www.google.com/");
265 TestCompletionCallback callback2;
266 HttpResponseInfo response2;
267 HttpRequestHeaders headers2;
268 scoped_ptr<SpdyHttpStream> http_stream2(
269 new SpdyHttpStream(session_.get(), true));
271 ASSERT_EQ(OK,
272 http_stream2->InitializeStream(&request2, BoundNetLog(),
273 CompletionCallback()));
274 EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers2, &response2,
275 callback2.callback()));
276 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
278 // First write.
279 deterministic_data()->RunFor(1);
280 EXPECT_LE(0, callback1.WaitForResult());
282 TestLoadTimingNotReused(*http_stream1);
283 LoadTimingInfo load_timing_info1;
284 LoadTimingInfo load_timing_info2;
285 EXPECT_TRUE(http_stream1->GetLoadTimingInfo(&load_timing_info1));
286 EXPECT_FALSE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
288 // Second write.
289 deterministic_data()->RunFor(1);
290 EXPECT_LE(0, callback2.WaitForResult());
291 TestLoadTimingReused(*http_stream2);
292 EXPECT_TRUE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
293 EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
295 // All the reads.
296 deterministic_data()->RunFor(6);
298 // Read stream 1 to completion, before making sure we can still read load
299 // timing from both streams.
300 scoped_refptr<IOBuffer> buf1(new IOBuffer(1));
301 ASSERT_EQ(0, http_stream1->ReadResponseBody(buf1, 1, callback1.callback()));
303 // Stream 1 has been read to completion.
304 TestLoadTimingNotReused(*http_stream1);
305 // Stream 2 still has queued body data.
306 TestLoadTimingReused(*http_stream2);
309 TEST_F(SpdyHttpStreamSpdy3Test, SendChunkedPost) {
310 set_merge_chunks(false);
312 scoped_ptr<SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0));
313 scoped_ptr<SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, false));
314 scoped_ptr<SpdyFrame> chunk2(ConstructSpdyBodyFrame(1, true));
315 MockWrite writes[] = {
316 CreateMockWrite(*req.get(), 0),
317 CreateMockWrite(*chunk1, 1), // POST upload frames
318 CreateMockWrite(*chunk2, 2),
320 scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
321 MockRead reads[] = {
322 CreateMockRead(*resp, 3),
323 CreateMockRead(*chunk1, 4),
324 CreateMockRead(*chunk2, 5),
325 MockRead(SYNCHRONOUS, 0, 6) // EOF
328 HostPortPair host_port_pair("www.google.com", 80);
329 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
330 EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
331 host_port_pair));
333 UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
334 upload_stream.AppendChunk(kUploadData, kUploadDataSize, false);
335 upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
337 HttpRequestInfo request;
338 request.method = "POST";
339 request.url = GURL("http://www.google.com/");
340 request.upload_data_stream = &upload_stream;
342 ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
344 TestCompletionCallback callback;
345 HttpResponseInfo response;
346 HttpRequestHeaders headers;
347 BoundNetLog net_log;
348 SpdyHttpStream http_stream(session_.get(), true);
349 ASSERT_EQ(
351 http_stream.InitializeStream(&request, net_log, CompletionCallback()));
353 EXPECT_EQ(ERR_IO_PENDING, http_stream.SendRequest(
354 headers, &response, callback.callback()));
355 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
357 // This triggers the MockWrite and read 2
358 callback.WaitForResult();
360 // This triggers read 3. The empty read causes the session to shut down.
361 data()->CompleteRead();
362 MessageLoop::current()->RunUntilIdle();
364 // Because we abandoned the stream, we don't expect to find a session in the
365 // pool anymore.
366 EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
367 EXPECT_TRUE(data()->at_read_eof());
368 EXPECT_TRUE(data()->at_write_eof());
371 // Test to ensure the SpdyStream state machine does not get confused when a
372 // chunk becomes available while a write is pending.
373 TEST_F(SpdyHttpStreamSpdy3Test, DelayedSendChunkedPost) {
374 set_merge_chunks(false);
376 const char kUploadData1[] = "12345678";
377 const int kUploadData1Size = arraysize(kUploadData1)-1;
378 scoped_ptr<SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0));
379 scoped_ptr<SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, false));
380 scoped_ptr<SpdyFrame> chunk2(
381 ConstructSpdyBodyFrame(1, kUploadData1, kUploadData1Size, false));
382 scoped_ptr<SpdyFrame> chunk3(ConstructSpdyBodyFrame(1, true));
383 MockWrite writes[] = {
384 CreateMockWrite(*req.get(), 0),
385 CreateMockWrite(*chunk1, 1), // POST upload frames
386 CreateMockWrite(*chunk2, 2),
387 CreateMockWrite(*chunk3, 3),
389 scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
390 MockRead reads[] = {
391 CreateMockRead(*resp, 4),
392 CreateMockRead(*chunk1, 5),
393 CreateMockRead(*chunk2, 6),
394 CreateMockRead(*chunk3, 7),
395 MockRead(ASYNC, 0, 8) // EOF
398 HostPortPair host_port_pair("www.google.com", 80);
399 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
401 ASSERT_EQ(OK, InitSessionDeterministic(reads, arraysize(reads),
402 writes, arraysize(writes),
403 host_port_pair));
405 UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
407 HttpRequestInfo request;
408 request.method = "POST";
409 request.url = GURL("http://www.google.com/");
410 request.upload_data_stream = &upload_stream;
412 ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
413 upload_stream.AppendChunk(kUploadData, kUploadDataSize, false);
415 BoundNetLog net_log;
416 scoped_ptr<SpdyHttpStream> http_stream(
417 new SpdyHttpStream(session_.get(), true));
418 ASSERT_EQ(OK, http_stream->InitializeStream(&request,
419 net_log,
420 CompletionCallback()));
422 TestCompletionCallback callback;
423 HttpRequestHeaders headers;
424 HttpResponseInfo response;
425 // This will attempt to Write() the initial request and headers, which will
426 // complete asynchronously.
427 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
428 callback.callback()));
429 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
431 // Complete the initial request write and the first chunk.
432 deterministic_data()->RunFor(2);
433 ASSERT_TRUE(callback.have_result());
434 EXPECT_GT(callback.WaitForResult(), 0);
436 // Now append the final two chunks which will enqueue two more writes.
437 upload_stream.AppendChunk(kUploadData1, kUploadData1Size, false);
438 upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
440 // Finish writing all the chunks.
441 deterministic_data()->RunFor(2);
443 // Read response headers.
444 deterministic_data()->RunFor(1);
445 ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
447 // Read and check |chunk1| response.
448 deterministic_data()->RunFor(1);
449 scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
450 ASSERT_EQ(kUploadDataSize,
451 http_stream->ReadResponseBody(buf1,
452 kUploadDataSize,
453 callback.callback()));
454 EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
456 // Read and check |chunk2| response.
457 deterministic_data()->RunFor(1);
458 scoped_refptr<IOBuffer> buf2(new IOBuffer(kUploadData1Size));
459 ASSERT_EQ(kUploadData1Size,
460 http_stream->ReadResponseBody(buf2,
461 kUploadData1Size,
462 callback.callback()));
463 EXPECT_EQ(kUploadData1, std::string(buf2->data(), kUploadData1Size));
465 // Read and check |chunk3| response.
466 deterministic_data()->RunFor(1);
467 scoped_refptr<IOBuffer> buf3(new IOBuffer(kUploadDataSize));
468 ASSERT_EQ(kUploadDataSize,
469 http_stream->ReadResponseBody(buf3,
470 kUploadDataSize,
471 callback.callback()));
472 EXPECT_EQ(kUploadData, std::string(buf3->data(), kUploadDataSize));
474 // Finish reading the |EOF|.
475 deterministic_data()->RunFor(1);
476 ASSERT_TRUE(response.headers.get());
477 ASSERT_EQ(200, response.headers->response_code());
478 EXPECT_TRUE(deterministic_data()->at_read_eof());
479 EXPECT_TRUE(deterministic_data()->at_write_eof());
482 // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
483 // made available is handled correctly.
484 TEST_F(SpdyHttpStreamSpdy3Test, DelayedSendChunkedPostWithWindowUpdate) {
485 set_merge_chunks(false);
487 scoped_ptr<SpdyFrame> req(ConstructChunkedSpdyPost(NULL, 0));
488 scoped_ptr<SpdyFrame> chunk1(ConstructSpdyBodyFrame(1, true));
489 MockWrite writes[] = {
490 CreateMockWrite(*req.get(), 0),
491 CreateMockWrite(*chunk1, 1),
493 scoped_ptr<SpdyFrame> resp(ConstructSpdyPostSynReply(NULL, 0));
494 scoped_ptr<SpdyFrame> window_update(
495 ConstructSpdyWindowUpdate(1, kUploadDataSize));
496 MockRead reads[] = {
497 CreateMockRead(*window_update, 2),
498 CreateMockRead(*resp, 3),
499 CreateMockRead(*chunk1, 4),
500 MockRead(ASYNC, 0, 5) // EOF
503 HostPortPair host_port_pair("www.google.com", 80);
504 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
506 DeterministicSocketData data(reads, arraysize(reads),
507 writes, arraysize(writes));
509 DeterministicMockClientSocketFactory* socket_factory =
510 session_deps_.deterministic_socket_factory.get();
511 socket_factory->AddSocketDataProvider(&data);
513 http_session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
514 &session_deps_);
515 session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
516 transport_params_ = new TransportSocketParams(host_port_pair,
517 MEDIUM, false, false,
518 OnHostResolutionCallback());
520 TestCompletionCallback callback;
521 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
523 EXPECT_EQ(ERR_IO_PENDING,
524 connection->Init(host_port_pair.ToString(),
525 transport_params_,
526 MEDIUM,
527 callback.callback(),
528 http_session_->GetTransportSocketPool(
529 HttpNetworkSession::NORMAL_SOCKET_POOL),
530 BoundNetLog()));
532 callback.WaitForResult();
533 EXPECT_EQ(OK,
534 session_->InitializeWithSocket(connection.release(), false, OK));
536 UploadDataStream upload_stream(UploadDataStream::CHUNKED, 0);
538 HttpRequestInfo request;
539 request.method = "POST";
540 request.url = GURL("http://www.google.com/");
541 request.upload_data_stream = &upload_stream;
543 ASSERT_EQ(OK, upload_stream.Init(CompletionCallback()));
544 upload_stream.AppendChunk(kUploadData, kUploadDataSize, true);
546 BoundNetLog net_log;
547 scoped_ptr<SpdyHttpStream> http_stream(
548 new SpdyHttpStream(session_.get(), true));
549 ASSERT_EQ(OK, http_stream->InitializeStream(&request, net_log,
550 CompletionCallback()));
552 HttpRequestHeaders headers;
553 HttpResponseInfo response;
554 // This will attempt to Write() the initial request and headers, which will
555 // complete asynchronously.
556 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
557 callback.callback()));
558 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
560 // Complete the initial request write and first chunk.
561 data.RunFor(2);
562 ASSERT_TRUE(callback.have_result());
563 EXPECT_GT(callback.WaitForResult(), 0);
565 // Verify that the window size has decreased.
566 ASSERT_TRUE(http_stream->stream() != NULL);
567 EXPECT_NE(static_cast<int>(kSpdyStreamInitialWindowSize),
568 http_stream->stream()->send_window_size());
570 // Read window update.
571 data.RunFor(1);
573 // Verify the window update.
574 ASSERT_TRUE(http_stream->stream() != NULL);
575 EXPECT_EQ(static_cast<int>(kSpdyStreamInitialWindowSize),
576 http_stream->stream()->send_window_size());
578 // Read response headers.
579 data.RunFor(1);
580 ASSERT_EQ(OK, http_stream->ReadResponseHeaders(callback.callback()));
582 // Read and check |chunk1| response.
583 data.RunFor(1);
584 scoped_refptr<IOBuffer> buf1(new IOBuffer(kUploadDataSize));
585 ASSERT_EQ(kUploadDataSize,
586 http_stream->ReadResponseBody(buf1,
587 kUploadDataSize,
588 callback.callback()));
589 EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
591 // Finish reading the |EOF|.
592 data.RunFor(1);
593 ASSERT_TRUE(response.headers.get());
594 ASSERT_EQ(200, response.headers->response_code());
595 EXPECT_TRUE(data.at_read_eof());
596 EXPECT_TRUE(data.at_write_eof());
599 // Test case for bug: http://code.google.com/p/chromium/issues/detail?id=50058
600 TEST_F(SpdyHttpStreamSpdy3Test, SpdyURLTest) {
601 const char * const full_url = "http://www.google.com/foo?query=what#anchor";
602 const char * const base_url = "http://www.google.com/foo?query=what";
603 scoped_ptr<SpdyFrame> req(ConstructSpdyGet(base_url, false, 1, LOWEST));
604 MockWrite writes[] = {
605 CreateMockWrite(*req.get(), 1),
607 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
608 MockRead reads[] = {
609 CreateMockRead(*resp, 2),
610 MockRead(SYNCHRONOUS, 0, 3) // EOF
613 HostPortPair host_port_pair("www.google.com", 80);
614 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
615 EXPECT_EQ(OK, InitSession(reads, arraysize(reads), writes, arraysize(writes),
616 host_port_pair));
618 HttpRequestInfo request;
619 request.method = "GET";
620 request.url = GURL(full_url);
621 TestCompletionCallback callback;
622 HttpResponseInfo response;
623 HttpRequestHeaders headers;
624 BoundNetLog net_log;
625 scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(session_, true));
626 ASSERT_EQ(
628 http_stream->InitializeStream(&request, net_log, CompletionCallback()));
630 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
631 callback.callback()));
633 const SpdyHeaderBlock& spdy_header =
634 http_stream->stream()->spdy_headers();
635 if (spdy_header.find(":path") != spdy_header.end())
636 EXPECT_EQ("/foo?query=what", spdy_header.find(":path")->second);
637 else
638 FAIL() << "No url is set in spdy_header!";
640 // This triggers the MockWrite and read 2
641 callback.WaitForResult();
643 // This triggers read 3. The empty read causes the session to shut down.
644 data()->CompleteRead();
646 // Because we abandoned the stream, we don't expect to find a session in the
647 // pool anymore.
648 EXPECT_FALSE(http_session_->spdy_session_pool()->HasSession(pair));
649 EXPECT_TRUE(data()->at_read_eof());
650 EXPECT_TRUE(data()->at_write_eof());
653 namespace {
655 void GetECServerBoundCertAndProof(
656 const std::string& origin,
657 ServerBoundCertService* server_bound_cert_service,
658 std::string* cert,
659 std::string* proof) {
660 TestCompletionCallback callback;
661 std::vector<uint8> requested_cert_types;
662 requested_cert_types.push_back(CLIENT_CERT_ECDSA_SIGN);
663 SSLClientCertType cert_type;
664 std::string key;
665 ServerBoundCertService::RequestHandle request_handle;
666 int rv = server_bound_cert_service->GetDomainBoundCert(
667 origin, requested_cert_types, &cert_type, &key, cert, callback.callback(),
668 &request_handle);
669 EXPECT_EQ(ERR_IO_PENDING, rv);
670 EXPECT_EQ(OK, callback.WaitForResult());
671 EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, cert_type);
673 SpdyCredential credential;
674 SpdyCredentialBuilder::Build(MockClientSocket::kTlsUnique, cert_type, key,
675 *cert, 2, &credential);
677 cert->assign(credential.certs[0]);
678 proof->assign(credential.proof);
681 } // namespace
683 // Constructs a standard SPDY SYN_STREAM frame for a GET request with
684 // a credential set.
685 SpdyFrame* ConstructCredentialRequestFrame(size_t slot, const GURL& url,
686 SpdyStreamId stream_id) {
687 const SpdyHeaderInfo syn_headers = {
688 SYN_STREAM,
689 stream_id,
691 ConvertRequestPriorityToSpdyPriority(LOWEST, 3),
692 slot,
693 CONTROL_FLAG_FIN,
694 false,
695 INVALID,
696 NULL,
698 DATA_FLAG_NONE
701 // TODO(rch): this is ugly. Clean up.
702 std::string str_path = url.PathForRequest();
703 std::string str_scheme = url.scheme();
704 std::string str_host = url.host();
705 if (url.has_port()) {
706 str_host += ":";
707 str_host += url.port();
709 scoped_array<char> req(new char[str_path.size() + 1]);
710 scoped_array<char> scheme(new char[str_scheme.size() + 1]);
711 scoped_array<char> host(new char[str_host.size() + 1]);
712 memcpy(req.get(), str_path.c_str(), str_path.size());
713 memcpy(scheme.get(), str_scheme.c_str(), str_scheme.size());
714 memcpy(host.get(), str_host.c_str(), str_host.size());
715 req.get()[str_path.size()] = '\0';
716 scheme.get()[str_scheme.size()] = '\0';
717 host.get()[str_host.size()] = '\0';
719 const char* const headers[] = {
720 ":method",
721 "GET",
722 ":path",
723 req.get(),
724 ":host",
725 host.get(),
726 ":scheme",
727 scheme.get(),
728 ":version",
729 "HTTP/1.1"
731 return ConstructSpdyPacket(
732 syn_headers, NULL, 0, headers, arraysize(headers)/2);
735 // TODO(rch): When openssl supports server bound certifictes, this
736 // guard can be removed
737 #if !defined(USE_OPENSSL)
738 // Test that if we request a resource for a new origin on a session that
739 // used domain bound certificates, that we send a CREDENTIAL frame for
740 // the new domain before we send the new request.
741 void SpdyHttpStreamSpdy3Test::TestSendCredentials(
742 ServerBoundCertService* server_bound_cert_service,
743 const std::string& cert,
744 const std::string& proof) {
745 const char* kUrl1 = "https://www.google.com/";
746 const char* kUrl2 = "https://www.gmail.com/";
748 SpdyCredential cred;
749 cred.slot = 2;
750 cred.proof = proof;
751 cred.certs.push_back(cert);
753 scoped_ptr<SpdyFrame> req(ConstructCredentialRequestFrame(
754 1, GURL(kUrl1), 1));
755 scoped_ptr<SpdyFrame> credential(ConstructSpdyCredential(cred));
756 scoped_ptr<SpdyFrame> req2(ConstructCredentialRequestFrame(
757 2, GURL(kUrl2), 3));
758 MockWrite writes[] = {
759 CreateMockWrite(*req.get(), 0),
760 CreateMockWrite(*credential.get(), 2),
761 CreateMockWrite(*req2.get(), 3),
764 scoped_ptr<SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
765 scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3));
766 MockRead reads[] = {
767 CreateMockRead(*resp, 1),
768 CreateMockRead(*resp2, 4),
769 MockRead(SYNCHRONOUS, 0, 5) // EOF
772 HostPortPair host_port_pair(HostPortPair::FromURL(GURL(kUrl1)));
773 HostPortProxyPair pair(host_port_pair, ProxyServer::Direct());
775 DeterministicMockClientSocketFactory* socket_factory =
776 session_deps_.deterministic_socket_factory.get();
777 DeterministicSocketData data(reads, arraysize(reads),
778 writes, arraysize(writes));
779 socket_factory->AddSocketDataProvider(&data);
780 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
781 ssl.channel_id_sent = true;
782 ssl.server_bound_cert_service = server_bound_cert_service;
783 ssl.protocol_negotiated = kProtoSPDY3;
784 socket_factory->AddSSLSocketDataProvider(&ssl);
785 http_session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic(
786 &session_deps_);
787 session_ = http_session_->spdy_session_pool()->Get(pair, BoundNetLog());
788 transport_params_ = new TransportSocketParams(host_port_pair,
789 MEDIUM, false, false,
790 OnHostResolutionCallback());
791 TestCompletionCallback callback;
792 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
793 SSLConfig ssl_config;
794 scoped_refptr<SOCKSSocketParams> socks_params;
795 scoped_refptr<HttpProxySocketParams> http_proxy_params;
796 scoped_refptr<SSLSocketParams> ssl_params(
797 new SSLSocketParams(transport_params_,
798 socks_params,
799 http_proxy_params,
800 ProxyServer::SCHEME_DIRECT,
801 host_port_pair,
802 ssl_config,
804 false,
805 false));
806 EXPECT_EQ(ERR_IO_PENDING,
807 connection->Init(host_port_pair.ToString(),
808 ssl_params,
809 MEDIUM,
810 callback.callback(),
811 http_session_->GetSSLSocketPool(
812 HttpNetworkSession::NORMAL_SOCKET_POOL),
813 BoundNetLog()));
814 callback.WaitForResult();
815 EXPECT_EQ(OK,
816 session_->InitializeWithSocket(connection.release(), true, OK));
818 HttpRequestInfo request;
819 request.method = "GET";
820 request.url = GURL(kUrl1);
821 HttpResponseInfo response;
822 HttpRequestHeaders headers;
823 BoundNetLog net_log;
824 scoped_ptr<SpdyHttpStream> http_stream(
825 new SpdyHttpStream(session_.get(), true));
826 ASSERT_EQ(
828 http_stream->InitializeStream(&request, net_log, CompletionCallback()));
830 // EXPECT_FALSE(session_->NeedsCredentials(request.url));
831 // GURL new_origin(kUrl2);
832 // EXPECT_TRUE(session_->NeedsCredentials(new_origin));
834 EXPECT_EQ(ERR_IO_PENDING, http_stream->SendRequest(headers, &response,
835 callback.callback()));
836 EXPECT_TRUE(http_session_->spdy_session_pool()->HasSession(pair));
838 data.RunFor(2);
839 callback.WaitForResult();
841 // Start up second request for resource on a new origin.
842 scoped_ptr<SpdyHttpStream> http_stream2(
843 new SpdyHttpStream(session_.get(), true));
844 request.url = GURL(kUrl2);
845 ASSERT_EQ(
847 http_stream2->InitializeStream(&request, net_log, CompletionCallback()));
848 EXPECT_EQ(ERR_IO_PENDING, http_stream2->SendRequest(headers, &response,
849 callback.callback()));
850 data.RunFor(2);
851 callback.WaitForResult();
853 EXPECT_EQ(ERR_IO_PENDING, http_stream2->ReadResponseHeaders(
854 callback.callback()));
855 data.RunFor(1);
856 EXPECT_EQ(OK, callback.WaitForResult());
857 ASSERT_TRUE(response.headers.get() != NULL);
858 ASSERT_EQ(200, response.headers->response_code());
861 TEST_F(SpdyHttpStreamSpdy3Test, SendCredentialsEC) {
862 scoped_refptr<base::SequencedWorkerPool> sequenced_worker_pool =
863 new base::SequencedWorkerPool(1, "SpdyHttpStreamSpdy3Test");
864 scoped_ptr<ServerBoundCertService> server_bound_cert_service(
865 new ServerBoundCertService(new DefaultServerBoundCertStore(NULL),
866 sequenced_worker_pool));
867 std::string cert;
868 std::string proof;
869 GetECServerBoundCertAndProof("http://www.gmail.com/",
870 server_bound_cert_service.get(),
871 &cert, &proof);
873 TestSendCredentials(server_bound_cert_service.get(), cert, proof);
875 sequenced_worker_pool->Shutdown();
878 #endif // !defined(USE_OPENSSL)
880 // TODO(willchan): Write a longer test for SpdyStream that exercises all
881 // methods.
883 } // namespace net