OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include <string> | |
6 #include <vector> | |
7 | |
8 #include "base/bind.h" | |
9 #include "base/bind_helpers.h" | |
10 #include "base/files/file_util.h" | |
11 #include "base/files/scoped_temp_dir.h" | |
12 #include "base/memory/scoped_vector.h" | |
13 #include "base/run_loop.h" | |
14 #include "base/stl_util.h" | |
15 #include "base/strings/string_piece.h" | |
16 #include "base/test/test_file_util.h" | |
17 #include "net/base/auth.h" | |
18 #include "net/base/chunked_upload_data_stream.h" | |
19 #include "net/base/elements_upload_data_stream.h" | |
20 #include "net/base/net_log_unittest.h" | |
21 #include "net/base/request_priority.h" | |
22 #include "net/base/upload_bytes_element_reader.h" | |
23 #include "net/base/upload_file_element_reader.h" | |
24 #include "net/http/http_network_session_peer.h" | |
25 #include "net/http/http_network_transaction.h" | |
26 #include "net/http/http_server_properties.h" | |
27 #include "net/http/http_transaction_test_util.h" | |
28 #include "net/socket/client_socket_pool_base.h" | |
29 #include "net/socket/next_proto.h" | |
30 #include "net/spdy/buffered_spdy_framer.h" | |
31 #include "net/spdy/spdy_http_stream.h" | |
32 #include "net/spdy/spdy_http_utils.h" | |
33 #include "net/spdy/spdy_session.h" | |
34 #include "net/spdy/spdy_session_pool.h" | |
35 #include "net/spdy/spdy_test_util_common.h" | |
36 #include "net/spdy/spdy_test_utils.h" | |
37 #include "net/ssl/ssl_connection_status_flags.h" | |
38 #include "net/url_request/url_request_test_util.h" | |
39 #include "testing/gmock/include/gmock/gmock.h" | |
40 #include "testing/platform_test.h" | |
41 | |
42 //----------------------------------------------------------------------------- | |
43 | |
44 namespace net { | |
45 | |
46 namespace { | |
47 | |
48 using testing::Each; | |
49 using testing::Eq; | |
50 | |
51 const char kRequestUrl[] = "http://www.google.com/"; | |
52 | |
53 enum SpdyNetworkTransactionTestSSLType { | |
54 SPDYNPN, | |
55 SPDYNOSSL, | |
56 SPDYSSL, | |
57 }; | |
58 | |
59 struct SpdyNetworkTransactionTestParams { | |
60 SpdyNetworkTransactionTestParams() | |
61 : protocol(kProtoSPDY31), | |
62 ssl_type(SPDYNPN) {} | |
63 | |
64 SpdyNetworkTransactionTestParams( | |
65 NextProto protocol, | |
66 SpdyNetworkTransactionTestSSLType ssl_type) | |
67 : protocol(protocol), | |
68 ssl_type(ssl_type) {} | |
69 | |
70 NextProto protocol; | |
71 SpdyNetworkTransactionTestSSLType ssl_type; | |
72 }; | |
73 | |
74 void UpdateSpdySessionDependencies( | |
75 SpdyNetworkTransactionTestParams test_params, | |
76 SpdySessionDependencies* session_deps) { | |
77 switch (test_params.ssl_type) { | |
78 case SPDYNPN: | |
79 session_deps->http_server_properties.SetAlternateProtocol( | |
80 HostPortPair("www.google.com", 80), 443, | |
81 AlternateProtocolFromNextProto(test_params.protocol), 1); | |
82 session_deps->use_alternate_protocols = true; | |
83 session_deps->next_protos = SpdyNextProtos(); | |
84 break; | |
85 case SPDYNOSSL: | |
86 session_deps->force_spdy_over_ssl = false; | |
87 session_deps->force_spdy_always = true; | |
88 break; | |
89 case SPDYSSL: | |
90 session_deps->force_spdy_over_ssl = true; | |
91 session_deps->force_spdy_always = true; | |
92 break; | |
93 default: | |
94 NOTREACHED(); | |
95 } | |
96 } | |
97 | |
98 SpdySessionDependencies* CreateSpdySessionDependencies( | |
99 SpdyNetworkTransactionTestParams test_params) { | |
100 SpdySessionDependencies* session_deps = | |
101 new SpdySessionDependencies(test_params.protocol); | |
102 UpdateSpdySessionDependencies(test_params, session_deps); | |
103 return session_deps; | |
104 } | |
105 | |
106 SpdySessionDependencies* CreateSpdySessionDependencies( | |
107 SpdyNetworkTransactionTestParams test_params, | |
108 ProxyService* proxy_service) { | |
109 SpdySessionDependencies* session_deps = | |
110 new SpdySessionDependencies(test_params.protocol, proxy_service); | |
111 UpdateSpdySessionDependencies(test_params, session_deps); | |
112 return session_deps; | |
113 } | |
114 | |
115 } // namespace | |
116 | |
117 class SpdyNetworkTransactionTest | |
118 : public ::testing::TestWithParam<SpdyNetworkTransactionTestParams> { | |
119 protected: | |
120 SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol) { | |
121 } | |
122 | |
123 virtual ~SpdyNetworkTransactionTest() { | |
124 // UploadDataStream may post a deletion tasks back to the message loop on | |
125 // destruction. | |
126 upload_data_stream_.reset(); | |
127 base::RunLoop().RunUntilIdle(); | |
128 } | |
129 | |
130 void SetUp() override { | |
131 google_get_request_initialized_ = false; | |
132 google_post_request_initialized_ = false; | |
133 google_chunked_post_request_initialized_ = false; | |
134 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
135 } | |
136 | |
137 struct TransactionHelperResult { | |
138 int rv; | |
139 std::string status_line; | |
140 std::string response_data; | |
141 HttpResponseInfo response_info; | |
142 }; | |
143 | |
144 // A helper class that handles all the initial npn/ssl setup. | |
145 class NormalSpdyTransactionHelper { | |
146 public: | |
147 NormalSpdyTransactionHelper(const HttpRequestInfo& request, | |
148 RequestPriority priority, | |
149 const BoundNetLog& log, | |
150 SpdyNetworkTransactionTestParams test_params, | |
151 SpdySessionDependencies* session_deps) | |
152 : request_(request), | |
153 priority_(priority), | |
154 session_deps_(session_deps == NULL ? | |
155 CreateSpdySessionDependencies(test_params) : | |
156 session_deps), | |
157 session_(SpdySessionDependencies::SpdyCreateSession( | |
158 session_deps_.get())), | |
159 log_(log), | |
160 test_params_(test_params), | |
161 deterministic_(false), | |
162 spdy_enabled_(true) { | |
163 switch (test_params_.ssl_type) { | |
164 case SPDYNOSSL: | |
165 case SPDYSSL: | |
166 port_ = 80; | |
167 break; | |
168 case SPDYNPN: | |
169 port_ = 443; | |
170 break; | |
171 default: | |
172 NOTREACHED(); | |
173 } | |
174 } | |
175 | |
176 ~NormalSpdyTransactionHelper() { | |
177 // Any test which doesn't close the socket by sending it an EOF will | |
178 // have a valid session left open, which leaks the entire session pool. | |
179 // This is just fine - in fact, some of our tests intentionally do this | |
180 // so that we can check consistency of the SpdySessionPool as the test | |
181 // finishes. If we had put an EOF on the socket, the SpdySession would | |
182 // have closed and we wouldn't be able to check the consistency. | |
183 | |
184 // Forcefully close existing sessions here. | |
185 session()->spdy_session_pool()->CloseAllSessions(); | |
186 } | |
187 | |
188 void SetDeterministic() { | |
189 session_ = SpdySessionDependencies::SpdyCreateSessionDeterministic( | |
190 session_deps_.get()); | |
191 deterministic_ = true; | |
192 } | |
193 | |
194 void SetSpdyDisabled() { | |
195 spdy_enabled_ = false; | |
196 port_ = 80; | |
197 } | |
198 | |
199 void RunPreTestSetup() { | |
200 if (!session_deps_.get()) | |
201 session_deps_.reset(CreateSpdySessionDependencies(test_params_)); | |
202 if (!session_.get()) { | |
203 session_ = SpdySessionDependencies::SpdyCreateSession( | |
204 session_deps_.get()); | |
205 } | |
206 | |
207 // We're now ready to use SSL-npn SPDY. | |
208 trans_.reset(new HttpNetworkTransaction(priority_, session_.get())); | |
209 } | |
210 | |
211 // Start the transaction, read some data, finish. | |
212 void RunDefaultTest() { | |
213 if (!StartDefaultTest()) | |
214 return; | |
215 FinishDefaultTest(); | |
216 } | |
217 | |
218 bool StartDefaultTest() { | |
219 output_.rv = trans_->Start(&request_, callback_.callback(), log_); | |
220 | |
221 // We expect an IO Pending or some sort of error. | |
222 EXPECT_LT(output_.rv, 0); | |
223 return output_.rv == ERR_IO_PENDING; | |
224 } | |
225 | |
226 void FinishDefaultTest() { | |
227 output_.rv = callback_.WaitForResult(); | |
228 if (output_.rv != OK) { | |
229 session_->spdy_session_pool()->CloseCurrentSessions(net::ERR_ABORTED); | |
230 return; | |
231 } | |
232 | |
233 // Verify responses. | |
234 const HttpResponseInfo* response = trans_->GetResponseInfo(); | |
235 ASSERT_TRUE(response != NULL); | |
236 ASSERT_TRUE(response->headers.get() != NULL); | |
237 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
238 EXPECT_EQ(spdy_enabled_, response->was_fetched_via_spdy); | |
239 if (HttpStreamFactory::spdy_enabled()) { | |
240 EXPECT_EQ( | |
241 HttpResponseInfo::ConnectionInfoFromNextProto( | |
242 test_params_.protocol), | |
243 response->connection_info); | |
244 } else { | |
245 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1, | |
246 response->connection_info); | |
247 } | |
248 if (test_params_.ssl_type == SPDYNPN && spdy_enabled_) { | |
249 EXPECT_TRUE(response->was_npn_negotiated); | |
250 } else { | |
251 EXPECT_TRUE(!response->was_npn_negotiated); | |
252 } | |
253 // If SPDY is not enabled, a HTTP request should not be diverted | |
254 // over a SSL session. | |
255 if (!spdy_enabled_) { | |
256 EXPECT_EQ(request_.url.SchemeIs("https"), | |
257 response->was_npn_negotiated); | |
258 } | |
259 EXPECT_EQ("127.0.0.1", response->socket_address.host()); | |
260 EXPECT_EQ(port_, response->socket_address.port()); | |
261 output_.status_line = response->headers->GetStatusLine(); | |
262 output_.response_info = *response; // Make a copy so we can verify. | |
263 output_.rv = ReadTransaction(trans_.get(), &output_.response_data); | |
264 } | |
265 | |
266 void FinishDefaultTestWithoutVerification() { | |
267 output_.rv = callback_.WaitForResult(); | |
268 if (output_.rv != OK) | |
269 session_->spdy_session_pool()->CloseCurrentSessions(net::ERR_ABORTED); | |
270 } | |
271 | |
272 // Most tests will want to call this function. In particular, the MockReads | |
273 // should end with an empty read, and that read needs to be processed to | |
274 // ensure proper deletion of the spdy_session_pool. | |
275 void VerifyDataConsumed() { | |
276 for (DataVector::iterator it = data_vector_.begin(); | |
277 it != data_vector_.end(); ++it) { | |
278 EXPECT_TRUE((*it)->at_read_eof()) << "Read count: " | |
279 << (*it)->read_count() | |
280 << " Read index: " | |
281 << (*it)->read_index(); | |
282 EXPECT_TRUE((*it)->at_write_eof()) << "Write count: " | |
283 << (*it)->write_count() | |
284 << " Write index: " | |
285 << (*it)->write_index(); | |
286 } | |
287 } | |
288 | |
289 // Occasionally a test will expect to error out before certain reads are | |
290 // processed. In that case we want to explicitly ensure that the reads were | |
291 // not processed. | |
292 void VerifyDataNotConsumed() { | |
293 for (DataVector::iterator it = data_vector_.begin(); | |
294 it != data_vector_.end(); ++it) { | |
295 EXPECT_TRUE(!(*it)->at_read_eof()) << "Read count: " | |
296 << (*it)->read_count() | |
297 << " Read index: " | |
298 << (*it)->read_index(); | |
299 EXPECT_TRUE(!(*it)->at_write_eof()) << "Write count: " | |
300 << (*it)->write_count() | |
301 << " Write index: " | |
302 << (*it)->write_index(); | |
303 } | |
304 } | |
305 | |
306 void RunToCompletion(StaticSocketDataProvider* data) { | |
307 RunPreTestSetup(); | |
308 AddData(data); | |
309 RunDefaultTest(); | |
310 VerifyDataConsumed(); | |
311 } | |
312 | |
313 void RunToCompletionWithSSLData( | |
314 StaticSocketDataProvider* data, | |
315 scoped_ptr<SSLSocketDataProvider> ssl_provider) { | |
316 RunPreTestSetup(); | |
317 AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass()); | |
318 RunDefaultTest(); | |
319 VerifyDataConsumed(); | |
320 } | |
321 | |
322 void AddData(StaticSocketDataProvider* data) { | |
323 scoped_ptr<SSLSocketDataProvider> ssl_provider( | |
324 new SSLSocketDataProvider(ASYNC, OK)); | |
325 AddDataWithSSLSocketDataProvider(data, ssl_provider.Pass()); | |
326 } | |
327 | |
328 void AddDataWithSSLSocketDataProvider( | |
329 StaticSocketDataProvider* data, | |
330 scoped_ptr<SSLSocketDataProvider> ssl_provider) { | |
331 DCHECK(!deterministic_); | |
332 data_vector_.push_back(data); | |
333 if (test_params_.ssl_type == SPDYNPN) | |
334 ssl_provider->SetNextProto(test_params_.protocol); | |
335 | |
336 if (test_params_.ssl_type == SPDYNPN || | |
337 test_params_.ssl_type == SPDYSSL) { | |
338 session_deps_->socket_factory->AddSSLSocketDataProvider( | |
339 ssl_provider.get()); | |
340 } | |
341 ssl_vector_.push_back(ssl_provider.release()); | |
342 | |
343 session_deps_->socket_factory->AddSocketDataProvider(data); | |
344 if (test_params_.ssl_type == SPDYNPN) { | |
345 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
346 StaticSocketDataProvider* hanging_non_alternate_protocol_socket = | |
347 new StaticSocketDataProvider(NULL, 0, NULL, 0); | |
348 hanging_non_alternate_protocol_socket->set_connect_data( | |
349 never_finishing_connect); | |
350 session_deps_->socket_factory->AddSocketDataProvider( | |
351 hanging_non_alternate_protocol_socket); | |
352 alternate_vector_.push_back(hanging_non_alternate_protocol_socket); | |
353 } | |
354 } | |
355 | |
356 void AddDeterministicData(DeterministicSocketData* data) { | |
357 DCHECK(deterministic_); | |
358 data_vector_.push_back(data); | |
359 SSLSocketDataProvider* ssl_provider = | |
360 new SSLSocketDataProvider(ASYNC, OK); | |
361 if (test_params_.ssl_type == SPDYNPN) | |
362 ssl_provider->SetNextProto(test_params_.protocol); | |
363 | |
364 ssl_vector_.push_back(ssl_provider); | |
365 if (test_params_.ssl_type == SPDYNPN || | |
366 test_params_.ssl_type == SPDYSSL) { | |
367 session_deps_->deterministic_socket_factory-> | |
368 AddSSLSocketDataProvider(ssl_provider); | |
369 } | |
370 session_deps_->deterministic_socket_factory->AddSocketDataProvider(data); | |
371 if (test_params_.ssl_type == SPDYNPN) { | |
372 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
373 DeterministicSocketData* hanging_non_alternate_protocol_socket = | |
374 new DeterministicSocketData(NULL, 0, NULL, 0); | |
375 hanging_non_alternate_protocol_socket->set_connect_data( | |
376 never_finishing_connect); | |
377 session_deps_->deterministic_socket_factory->AddSocketDataProvider( | |
378 hanging_non_alternate_protocol_socket); | |
379 alternate_deterministic_vector_.push_back( | |
380 hanging_non_alternate_protocol_socket); | |
381 } | |
382 } | |
383 | |
384 void SetSession(const scoped_refptr<HttpNetworkSession>& session) { | |
385 session_ = session; | |
386 } | |
387 HttpNetworkTransaction* trans() { return trans_.get(); } | |
388 void ResetTrans() { trans_.reset(); } | |
389 TransactionHelperResult& output() { return output_; } | |
390 const HttpRequestInfo& request() const { return request_; } | |
391 const scoped_refptr<HttpNetworkSession>& session() const { | |
392 return session_; | |
393 } | |
394 scoped_ptr<SpdySessionDependencies>& session_deps() { | |
395 return session_deps_; | |
396 } | |
397 int port() const { return port_; } | |
398 SpdyNetworkTransactionTestParams test_params() const { | |
399 return test_params_; | |
400 } | |
401 | |
402 private: | |
403 typedef std::vector<StaticSocketDataProvider*> DataVector; | |
404 typedef ScopedVector<SSLSocketDataProvider> SSLVector; | |
405 typedef ScopedVector<StaticSocketDataProvider> AlternateVector; | |
406 typedef ScopedVector<DeterministicSocketData> AlternateDeterministicVector; | |
407 HttpRequestInfo request_; | |
408 RequestPriority priority_; | |
409 scoped_ptr<SpdySessionDependencies> session_deps_; | |
410 scoped_refptr<HttpNetworkSession> session_; | |
411 TransactionHelperResult output_; | |
412 scoped_ptr<StaticSocketDataProvider> first_transaction_; | |
413 SSLVector ssl_vector_; | |
414 TestCompletionCallback callback_; | |
415 scoped_ptr<HttpNetworkTransaction> trans_; | |
416 scoped_ptr<HttpNetworkTransaction> trans_http_; | |
417 DataVector data_vector_; | |
418 AlternateVector alternate_vector_; | |
419 AlternateDeterministicVector alternate_deterministic_vector_; | |
420 const BoundNetLog log_; | |
421 SpdyNetworkTransactionTestParams test_params_; | |
422 int port_; | |
423 bool deterministic_; | |
424 bool spdy_enabled_; | |
425 }; | |
426 | |
427 void ConnectStatusHelperWithExpectedStatus(const MockRead& status, | |
428 int expected_status); | |
429 | |
430 void ConnectStatusHelper(const MockRead& status); | |
431 | |
432 const HttpRequestInfo& CreateGetPushRequest() { | |
433 google_get_push_request_.method = "GET"; | |
434 google_get_push_request_.url = GURL("http://www.google.com/foo.dat"); | |
435 google_get_push_request_.load_flags = 0; | |
436 return google_get_push_request_; | |
437 } | |
438 | |
439 const HttpRequestInfo& CreateGetRequest() { | |
440 if (!google_get_request_initialized_) { | |
441 google_get_request_.method = "GET"; | |
442 google_get_request_.url = GURL(kDefaultURL); | |
443 google_get_request_.load_flags = 0; | |
444 google_get_request_initialized_ = true; | |
445 } | |
446 return google_get_request_; | |
447 } | |
448 | |
449 const HttpRequestInfo& CreateGetRequestWithUserAgent() { | |
450 if (!google_get_request_initialized_) { | |
451 google_get_request_.method = "GET"; | |
452 google_get_request_.url = GURL(kDefaultURL); | |
453 google_get_request_.load_flags = 0; | |
454 google_get_request_.extra_headers.SetHeader("User-Agent", "Chrome"); | |
455 google_get_request_initialized_ = true; | |
456 } | |
457 return google_get_request_; | |
458 } | |
459 | |
460 const HttpRequestInfo& CreatePostRequest() { | |
461 if (!google_post_request_initialized_) { | |
462 ScopedVector<UploadElementReader> element_readers; | |
463 element_readers.push_back( | |
464 new UploadBytesElementReader(kUploadData, kUploadDataSize)); | |
465 upload_data_stream_.reset( | |
466 new ElementsUploadDataStream(element_readers.Pass(), 0)); | |
467 | |
468 google_post_request_.method = "POST"; | |
469 google_post_request_.url = GURL(kDefaultURL); | |
470 google_post_request_.upload_data_stream = upload_data_stream_.get(); | |
471 google_post_request_initialized_ = true; | |
472 } | |
473 return google_post_request_; | |
474 } | |
475 | |
476 const HttpRequestInfo& CreateFilePostRequest() { | |
477 if (!google_post_request_initialized_) { | |
478 base::FilePath file_path; | |
479 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path)); | |
480 CHECK_EQ(static_cast<int>(kUploadDataSize), | |
481 base::WriteFile(file_path, kUploadData, kUploadDataSize)); | |
482 | |
483 ScopedVector<UploadElementReader> element_readers; | |
484 element_readers.push_back( | |
485 new UploadFileElementReader(base::MessageLoopProxy::current().get(), | |
486 file_path, | |
487 0, | |
488 kUploadDataSize, | |
489 base::Time())); | |
490 upload_data_stream_.reset( | |
491 new ElementsUploadDataStream(element_readers.Pass(), 0)); | |
492 | |
493 google_post_request_.method = "POST"; | |
494 google_post_request_.url = GURL(kDefaultURL); | |
495 google_post_request_.upload_data_stream = upload_data_stream_.get(); | |
496 google_post_request_initialized_ = true; | |
497 } | |
498 return google_post_request_; | |
499 } | |
500 | |
501 const HttpRequestInfo& CreateUnreadableFilePostRequest() { | |
502 if (google_post_request_initialized_) | |
503 return google_post_request_; | |
504 | |
505 base::FilePath file_path; | |
506 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path)); | |
507 CHECK_EQ(static_cast<int>(kUploadDataSize), | |
508 base::WriteFile(file_path, kUploadData, kUploadDataSize)); | |
509 CHECK(base::MakeFileUnreadable(file_path)); | |
510 | |
511 ScopedVector<UploadElementReader> element_readers; | |
512 element_readers.push_back( | |
513 new UploadFileElementReader(base::MessageLoopProxy::current().get(), | |
514 file_path, | |
515 0, | |
516 kUploadDataSize, | |
517 base::Time())); | |
518 upload_data_stream_.reset( | |
519 new ElementsUploadDataStream(element_readers.Pass(), 0)); | |
520 | |
521 google_post_request_.method = "POST"; | |
522 google_post_request_.url = GURL(kDefaultURL); | |
523 google_post_request_.upload_data_stream = upload_data_stream_.get(); | |
524 google_post_request_initialized_ = true; | |
525 return google_post_request_; | |
526 } | |
527 | |
528 const HttpRequestInfo& CreateComplexPostRequest() { | |
529 if (!google_post_request_initialized_) { | |
530 const int kFileRangeOffset = 1; | |
531 const int kFileRangeLength = 3; | |
532 CHECK_LT(kFileRangeOffset + kFileRangeLength, kUploadDataSize); | |
533 | |
534 base::FilePath file_path; | |
535 CHECK(base::CreateTemporaryFileInDir(temp_dir_.path(), &file_path)); | |
536 CHECK_EQ(static_cast<int>(kUploadDataSize), | |
537 base::WriteFile(file_path, kUploadData, kUploadDataSize)); | |
538 | |
539 ScopedVector<UploadElementReader> element_readers; | |
540 element_readers.push_back( | |
541 new UploadBytesElementReader(kUploadData, kFileRangeOffset)); | |
542 element_readers.push_back( | |
543 new UploadFileElementReader(base::MessageLoopProxy::current().get(), | |
544 file_path, | |
545 kFileRangeOffset, | |
546 kFileRangeLength, | |
547 base::Time())); | |
548 element_readers.push_back(new UploadBytesElementReader( | |
549 kUploadData + kFileRangeOffset + kFileRangeLength, | |
550 kUploadDataSize - (kFileRangeOffset + kFileRangeLength))); | |
551 upload_data_stream_.reset( | |
552 new ElementsUploadDataStream(element_readers.Pass(), 0)); | |
553 | |
554 google_post_request_.method = "POST"; | |
555 google_post_request_.url = GURL(kDefaultURL); | |
556 google_post_request_.upload_data_stream = upload_data_stream_.get(); | |
557 google_post_request_initialized_ = true; | |
558 } | |
559 return google_post_request_; | |
560 } | |
561 | |
562 const HttpRequestInfo& CreateChunkedPostRequest() { | |
563 if (!google_chunked_post_request_initialized_) { | |
564 upload_chunked_data_stream_.reset(new ChunkedUploadDataStream(0)); | |
565 google_chunked_post_request_.method = "POST"; | |
566 google_chunked_post_request_.url = GURL(kDefaultURL); | |
567 google_chunked_post_request_.upload_data_stream = | |
568 upload_chunked_data_stream_.get(); | |
569 google_chunked_post_request_initialized_ = true; | |
570 } | |
571 return google_chunked_post_request_; | |
572 } | |
573 | |
574 // Read the result of a particular transaction, knowing that we've got | |
575 // multiple transactions in the read pipeline; so as we read, we may have | |
576 // to skip over data destined for other transactions while we consume | |
577 // the data for |trans|. | |
578 int ReadResult(HttpNetworkTransaction* trans, | |
579 StaticSocketDataProvider* data, | |
580 std::string* result) { | |
581 const int kSize = 3000; | |
582 | |
583 int bytes_read = 0; | |
584 scoped_refptr<net::IOBufferWithSize> buf(new net::IOBufferWithSize(kSize)); | |
585 TestCompletionCallback callback; | |
586 while (true) { | |
587 int rv = trans->Read(buf.get(), kSize, callback.callback()); | |
588 if (rv == ERR_IO_PENDING) { | |
589 // Multiple transactions may be in the data set. Keep pulling off | |
590 // reads until we complete our callback. | |
591 while (!callback.have_result()) { | |
592 data->CompleteRead(); | |
593 base::RunLoop().RunUntilIdle(); | |
594 } | |
595 rv = callback.WaitForResult(); | |
596 } else if (rv <= 0) { | |
597 break; | |
598 } | |
599 result->append(buf->data(), rv); | |
600 bytes_read += rv; | |
601 } | |
602 return bytes_read; | |
603 } | |
604 | |
605 void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) { | |
606 // This lengthy block is reaching into the pool to dig out the active | |
607 // session. Once we have the session, we verify that the streams are | |
608 // all closed and not leaked at this point. | |
609 const GURL& url = helper.request().url; | |
610 int port = helper.test_params().ssl_type == SPDYNPN ? 443 : 80; | |
611 HostPortPair host_port_pair(url.host(), port); | |
612 SpdySessionKey key(host_port_pair, ProxyServer::Direct(), | |
613 PRIVACY_MODE_DISABLED); | |
614 BoundNetLog log; | |
615 const scoped_refptr<HttpNetworkSession>& session = helper.session(); | |
616 base::WeakPtr<SpdySession> spdy_session = | |
617 session->spdy_session_pool()->FindAvailableSession(key, log); | |
618 ASSERT_TRUE(spdy_session != NULL); | |
619 EXPECT_EQ(0u, spdy_session->num_active_streams()); | |
620 EXPECT_EQ(0u, spdy_session->num_unclaimed_pushed_streams()); | |
621 } | |
622 | |
623 void RunServerPushTest(OrderedSocketData* data, | |
624 HttpResponseInfo* response, | |
625 HttpResponseInfo* push_response, | |
626 const std::string& expected) { | |
627 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
628 BoundNetLog(), GetParam(), NULL); | |
629 helper.RunPreTestSetup(); | |
630 helper.AddData(data); | |
631 | |
632 HttpNetworkTransaction* trans = helper.trans(); | |
633 | |
634 // Start the transaction with basic parameters. | |
635 TestCompletionCallback callback; | |
636 int rv = trans->Start( | |
637 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
638 EXPECT_EQ(ERR_IO_PENDING, rv); | |
639 rv = callback.WaitForResult(); | |
640 | |
641 // Request the pushed path. | |
642 scoped_ptr<HttpNetworkTransaction> trans2( | |
643 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
644 rv = trans2->Start( | |
645 &CreateGetPushRequest(), callback.callback(), BoundNetLog()); | |
646 EXPECT_EQ(ERR_IO_PENDING, rv); | |
647 base::RunLoop().RunUntilIdle(); | |
648 | |
649 // The data for the pushed path may be coming in more than 1 frame. Compile | |
650 // the results into a single string. | |
651 | |
652 // Read the server push body. | |
653 std::string result2; | |
654 ReadResult(trans2.get(), data, &result2); | |
655 // Read the response body. | |
656 std::string result; | |
657 ReadResult(trans, data, &result); | |
658 | |
659 // Verify that we consumed all test data. | |
660 EXPECT_TRUE(data->at_read_eof()); | |
661 EXPECT_TRUE(data->at_write_eof()); | |
662 | |
663 // Verify that the received push data is same as the expected push data. | |
664 EXPECT_EQ(result2.compare(expected), 0) << "Received data: " | |
665 << result2 | |
666 << "||||| Expected data: " | |
667 << expected; | |
668 | |
669 // Verify the SYN_REPLY. | |
670 // Copy the response info, because trans goes away. | |
671 *response = *trans->GetResponseInfo(); | |
672 *push_response = *trans2->GetResponseInfo(); | |
673 | |
674 VerifyStreamsClosed(helper); | |
675 } | |
676 | |
677 static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper, | |
678 int result) { | |
679 helper->ResetTrans(); | |
680 } | |
681 | |
682 static void StartTransactionCallback( | |
683 const scoped_refptr<HttpNetworkSession>& session, | |
684 int result) { | |
685 scoped_ptr<HttpNetworkTransaction> trans( | |
686 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
687 TestCompletionCallback callback; | |
688 HttpRequestInfo request; | |
689 request.method = "GET"; | |
690 request.url = GURL("http://www.google.com/"); | |
691 request.load_flags = 0; | |
692 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
693 EXPECT_EQ(ERR_IO_PENDING, rv); | |
694 callback.WaitForResult(); | |
695 } | |
696 | |
697 ChunkedUploadDataStream* upload_chunked_data_stream() const { | |
698 return upload_chunked_data_stream_.get(); | |
699 } | |
700 | |
701 SpdyTestUtil spdy_util_; | |
702 | |
703 private: | |
704 scoped_ptr<ChunkedUploadDataStream> upload_chunked_data_stream_; | |
705 scoped_ptr<UploadDataStream> upload_data_stream_; | |
706 bool google_get_request_initialized_; | |
707 bool google_post_request_initialized_; | |
708 bool google_chunked_post_request_initialized_; | |
709 HttpRequestInfo google_get_request_; | |
710 HttpRequestInfo google_post_request_; | |
711 HttpRequestInfo google_chunked_post_request_; | |
712 HttpRequestInfo google_get_push_request_; | |
713 base::ScopedTempDir temp_dir_; | |
714 }; | |
715 | |
716 //----------------------------------------------------------------------------- | |
717 // All tests are run with three different connection types: SPDY after NPN | |
718 // negotiation, SPDY without SSL, and SPDY with SSL. | |
719 // | |
720 // TODO(akalin): Use ::testing::Combine() when we are able to use | |
721 // <tr1/tuple>. | |
722 INSTANTIATE_TEST_CASE_P( | |
723 Spdy, | |
724 SpdyNetworkTransactionTest, | |
725 ::testing::Values( | |
726 SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNOSSL), | |
727 SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYSSL), | |
728 SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN), | |
729 SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYNOSSL), | |
730 SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYSSL), | |
731 SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYNPN), | |
732 SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYNOSSL), | |
733 SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYSSL), | |
734 SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYNPN))); | |
735 | |
736 // Verify HttpNetworkTransaction constructor. | |
737 TEST_P(SpdyNetworkTransactionTest, Constructor) { | |
738 scoped_ptr<SpdySessionDependencies> session_deps( | |
739 CreateSpdySessionDependencies(GetParam())); | |
740 scoped_refptr<HttpNetworkSession> session( | |
741 SpdySessionDependencies::SpdyCreateSession(session_deps.get())); | |
742 scoped_ptr<HttpTransaction> trans( | |
743 new HttpNetworkTransaction(DEFAULT_PRIORITY, session.get())); | |
744 } | |
745 | |
746 TEST_P(SpdyNetworkTransactionTest, Get) { | |
747 // Construct the request. | |
748 scoped_ptr<SpdyFrame> req( | |
749 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
750 MockWrite writes[] = { CreateMockWrite(*req) }; | |
751 | |
752 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
753 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
754 MockRead reads[] = { | |
755 CreateMockRead(*resp), | |
756 CreateMockRead(*body), | |
757 MockRead(ASYNC, 0, 0) // EOF | |
758 }; | |
759 | |
760 DelayedSocketData data(1, reads, arraysize(reads), | |
761 writes, arraysize(writes)); | |
762 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
763 BoundNetLog(), GetParam(), NULL); | |
764 helper.RunToCompletion(&data); | |
765 TransactionHelperResult out = helper.output(); | |
766 EXPECT_EQ(OK, out.rv); | |
767 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
768 EXPECT_EQ("hello!", out.response_data); | |
769 } | |
770 | |
771 TEST_P(SpdyNetworkTransactionTest, GetAtEachPriority) { | |
772 for (RequestPriority p = MINIMUM_PRIORITY; p <= MAXIMUM_PRIORITY; | |
773 p = RequestPriority(p + 1)) { | |
774 // Construct the request. | |
775 scoped_ptr<SpdyFrame> req( | |
776 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, p, true)); | |
777 MockWrite writes[] = { CreateMockWrite(*req) }; | |
778 | |
779 SpdyPriority spdy_prio = 0; | |
780 EXPECT_TRUE(GetSpdyPriority(spdy_util_.spdy_version(), *req, &spdy_prio)); | |
781 // this repeats the RequestPriority-->SpdyPriority mapping from | |
782 // SpdyFramer::ConvertRequestPriorityToSpdyPriority to make | |
783 // sure it's being done right. | |
784 if (spdy_util_.spdy_version() < SPDY3) { | |
785 switch (p) { | |
786 case HIGHEST: | |
787 EXPECT_EQ(0, spdy_prio); | |
788 break; | |
789 case MEDIUM: | |
790 EXPECT_EQ(1, spdy_prio); | |
791 break; | |
792 case LOW: | |
793 case LOWEST: | |
794 EXPECT_EQ(2, spdy_prio); | |
795 break; | |
796 case IDLE: | |
797 EXPECT_EQ(3, spdy_prio); | |
798 break; | |
799 default: | |
800 FAIL(); | |
801 } | |
802 } else { | |
803 switch(p) { | |
804 case HIGHEST: | |
805 EXPECT_EQ(0, spdy_prio); | |
806 break; | |
807 case MEDIUM: | |
808 EXPECT_EQ(1, spdy_prio); | |
809 break; | |
810 case LOW: | |
811 EXPECT_EQ(2, spdy_prio); | |
812 break; | |
813 case LOWEST: | |
814 EXPECT_EQ(3, spdy_prio); | |
815 break; | |
816 case IDLE: | |
817 EXPECT_EQ(4, spdy_prio); | |
818 break; | |
819 default: | |
820 FAIL(); | |
821 } | |
822 } | |
823 | |
824 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
825 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
826 MockRead reads[] = { | |
827 CreateMockRead(*resp), | |
828 CreateMockRead(*body), | |
829 MockRead(ASYNC, 0, 0) // EOF | |
830 }; | |
831 | |
832 DelayedSocketData data(1, reads, arraysize(reads), | |
833 writes, arraysize(writes)); | |
834 HttpRequestInfo http_req = CreateGetRequest(); | |
835 | |
836 NormalSpdyTransactionHelper helper(http_req, p, BoundNetLog(), | |
837 GetParam(), NULL); | |
838 helper.RunToCompletion(&data); | |
839 TransactionHelperResult out = helper.output(); | |
840 EXPECT_EQ(OK, out.rv); | |
841 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
842 EXPECT_EQ("hello!", out.response_data); | |
843 } | |
844 } | |
845 | |
846 // Start three gets simultaniously; making sure that multiplexed | |
847 // streams work properly. | |
848 | |
849 // This can't use the TransactionHelper method, since it only | |
850 // handles a single transaction, and finishes them as soon | |
851 // as it launches them. | |
852 | |
853 // TODO(gavinp): create a working generalized TransactionHelper that | |
854 // can allow multiple streams in flight. | |
855 | |
856 TEST_P(SpdyNetworkTransactionTest, ThreeGets) { | |
857 scoped_ptr<SpdyFrame> req( | |
858 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
859 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
860 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false)); | |
861 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
862 | |
863 scoped_ptr<SpdyFrame> req2( | |
864 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); | |
865 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
866 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); | |
867 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
868 | |
869 scoped_ptr<SpdyFrame> req3( | |
870 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true)); | |
871 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5)); | |
872 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, false)); | |
873 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true)); | |
874 | |
875 MockWrite writes[] = { | |
876 CreateMockWrite(*req), | |
877 CreateMockWrite(*req2), | |
878 CreateMockWrite(*req3), | |
879 }; | |
880 MockRead reads[] = { | |
881 CreateMockRead(*resp, 1), | |
882 CreateMockRead(*body), | |
883 CreateMockRead(*resp2, 4), | |
884 CreateMockRead(*body2), | |
885 CreateMockRead(*resp3, 7), | |
886 CreateMockRead(*body3), | |
887 | |
888 CreateMockRead(*fbody), | |
889 CreateMockRead(*fbody2), | |
890 CreateMockRead(*fbody3), | |
891 | |
892 MockRead(ASYNC, 0, 0), // EOF | |
893 }; | |
894 OrderedSocketData data(reads, arraysize(reads), | |
895 writes, arraysize(writes)); | |
896 OrderedSocketData data_placeholder(NULL, 0, NULL, 0); | |
897 | |
898 BoundNetLog log; | |
899 TransactionHelperResult out; | |
900 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
901 BoundNetLog(), GetParam(), NULL); | |
902 helper.RunPreTestSetup(); | |
903 helper.AddData(&data); | |
904 // We require placeholder data because three get requests are sent out, so | |
905 // there needs to be three sets of SSL connection data. | |
906 helper.AddData(&data_placeholder); | |
907 helper.AddData(&data_placeholder); | |
908 scoped_ptr<HttpNetworkTransaction> trans1( | |
909 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
910 scoped_ptr<HttpNetworkTransaction> trans2( | |
911 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
912 scoped_ptr<HttpNetworkTransaction> trans3( | |
913 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
914 | |
915 TestCompletionCallback callback1; | |
916 TestCompletionCallback callback2; | |
917 TestCompletionCallback callback3; | |
918 | |
919 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
920 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
921 HttpRequestInfo httpreq3 = CreateGetRequest(); | |
922 | |
923 out.rv = trans1->Start(&httpreq1, callback1.callback(), log); | |
924 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
925 out.rv = trans2->Start(&httpreq2, callback2.callback(), log); | |
926 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
927 out.rv = trans3->Start(&httpreq3, callback3.callback(), log); | |
928 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
929 | |
930 out.rv = callback1.WaitForResult(); | |
931 ASSERT_EQ(OK, out.rv); | |
932 out.rv = callback3.WaitForResult(); | |
933 ASSERT_EQ(OK, out.rv); | |
934 | |
935 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
936 EXPECT_TRUE(response1->headers.get() != NULL); | |
937 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
938 out.status_line = response1->headers->GetStatusLine(); | |
939 out.response_info = *response1; | |
940 | |
941 trans2->GetResponseInfo(); | |
942 | |
943 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
944 helper.VerifyDataConsumed(); | |
945 EXPECT_EQ(OK, out.rv); | |
946 | |
947 EXPECT_EQ(OK, out.rv); | |
948 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
949 EXPECT_EQ("hello!hello!", out.response_data); | |
950 } | |
951 | |
952 TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBinding) { | |
953 scoped_ptr<SpdyFrame> req( | |
954 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
955 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
956 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false)); | |
957 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
958 | |
959 scoped_ptr<SpdyFrame> req2( | |
960 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); | |
961 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
962 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); | |
963 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
964 | |
965 MockWrite writes[] = { | |
966 CreateMockWrite(*req), | |
967 CreateMockWrite(*req2), | |
968 }; | |
969 MockRead reads[] = { | |
970 CreateMockRead(*resp, 1), | |
971 CreateMockRead(*body), | |
972 CreateMockRead(*resp2, 4), | |
973 CreateMockRead(*body2), | |
974 CreateMockRead(*fbody), | |
975 CreateMockRead(*fbody2), | |
976 MockRead(ASYNC, 0, 0), // EOF | |
977 }; | |
978 OrderedSocketData data(reads, arraysize(reads), | |
979 writes, arraysize(writes)); | |
980 | |
981 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING); | |
982 | |
983 OrderedSocketData data_placeholder(NULL, 0, NULL, 0); | |
984 data_placeholder.set_connect_data(never_finishing_connect); | |
985 | |
986 BoundNetLog log; | |
987 TransactionHelperResult out; | |
988 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
989 BoundNetLog(), GetParam(), NULL); | |
990 helper.RunPreTestSetup(); | |
991 helper.AddData(&data); | |
992 // We require placeholder data because two get requests are sent out, so | |
993 // there needs to be two sets of SSL connection data. | |
994 helper.AddData(&data_placeholder); | |
995 scoped_ptr<HttpNetworkTransaction> trans1( | |
996 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
997 scoped_ptr<HttpNetworkTransaction> trans2( | |
998 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
999 | |
1000 TestCompletionCallback callback1; | |
1001 TestCompletionCallback callback2; | |
1002 | |
1003 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
1004 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
1005 | |
1006 out.rv = trans1->Start(&httpreq1, callback1.callback(), log); | |
1007 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1008 out.rv = trans2->Start(&httpreq2, callback2.callback(), log); | |
1009 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1010 | |
1011 out.rv = callback1.WaitForResult(); | |
1012 ASSERT_EQ(OK, out.rv); | |
1013 out.rv = callback2.WaitForResult(); | |
1014 ASSERT_EQ(OK, out.rv); | |
1015 | |
1016 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
1017 EXPECT_TRUE(response1->headers.get() != NULL); | |
1018 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
1019 out.status_line = response1->headers->GetStatusLine(); | |
1020 out.response_info = *response1; | |
1021 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
1022 EXPECT_EQ(OK, out.rv); | |
1023 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1024 EXPECT_EQ("hello!hello!", out.response_data); | |
1025 | |
1026 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
1027 EXPECT_TRUE(response2->headers.get() != NULL); | |
1028 EXPECT_TRUE(response2->was_fetched_via_spdy); | |
1029 out.status_line = response2->headers->GetStatusLine(); | |
1030 out.response_info = *response2; | |
1031 out.rv = ReadTransaction(trans2.get(), &out.response_data); | |
1032 EXPECT_EQ(OK, out.rv); | |
1033 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1034 EXPECT_EQ("hello!hello!", out.response_data); | |
1035 | |
1036 helper.VerifyDataConsumed(); | |
1037 } | |
1038 | |
1039 TEST_P(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) { | |
1040 scoped_ptr<SpdyFrame> req( | |
1041 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
1042 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1043 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false)); | |
1044 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1045 | |
1046 scoped_ptr<SpdyFrame> req2( | |
1047 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); | |
1048 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
1049 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); | |
1050 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
1051 | |
1052 MockWrite writes[] = { | |
1053 CreateMockWrite(*req), | |
1054 CreateMockWrite(*req2), | |
1055 }; | |
1056 MockRead reads[] = { | |
1057 CreateMockRead(*resp, 1), | |
1058 CreateMockRead(*body), | |
1059 CreateMockRead(*resp2, 4), | |
1060 CreateMockRead(*body2), | |
1061 CreateMockRead(*fbody), | |
1062 CreateMockRead(*fbody2), | |
1063 MockRead(ASYNC, 0, 0), // EOF | |
1064 }; | |
1065 OrderedSocketData preconnect_data(reads, arraysize(reads), | |
1066 writes, arraysize(writes)); | |
1067 | |
1068 MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING); | |
1069 | |
1070 OrderedSocketData data_placeholder(NULL, 0, NULL, 0); | |
1071 data_placeholder.set_connect_data(never_finishing_connect); | |
1072 | |
1073 BoundNetLog log; | |
1074 TransactionHelperResult out; | |
1075 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
1076 BoundNetLog(), GetParam(), NULL); | |
1077 helper.RunPreTestSetup(); | |
1078 helper.AddData(&preconnect_data); | |
1079 // We require placeholder data because 3 connections are attempted (first is | |
1080 // the preconnect, 2nd and 3rd are the never finished connections. | |
1081 helper.AddData(&data_placeholder); | |
1082 helper.AddData(&data_placeholder); | |
1083 | |
1084 scoped_ptr<HttpNetworkTransaction> trans1( | |
1085 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1086 scoped_ptr<HttpNetworkTransaction> trans2( | |
1087 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1088 | |
1089 TestCompletionCallback callback1; | |
1090 TestCompletionCallback callback2; | |
1091 | |
1092 HttpRequestInfo httpreq = CreateGetRequest(); | |
1093 | |
1094 // Preconnect the first. | |
1095 SSLConfig preconnect_ssl_config; | |
1096 helper.session()->ssl_config_service()->GetSSLConfig(&preconnect_ssl_config); | |
1097 HttpStreamFactory* http_stream_factory = | |
1098 helper.session()->http_stream_factory(); | |
1099 helper.session()->GetNextProtos(&preconnect_ssl_config.next_protos); | |
1100 | |
1101 http_stream_factory->PreconnectStreams( | |
1102 1, httpreq, DEFAULT_PRIORITY, | |
1103 preconnect_ssl_config, preconnect_ssl_config); | |
1104 | |
1105 out.rv = trans1->Start(&httpreq, callback1.callback(), log); | |
1106 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1107 out.rv = trans2->Start(&httpreq, callback2.callback(), log); | |
1108 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1109 | |
1110 out.rv = callback1.WaitForResult(); | |
1111 ASSERT_EQ(OK, out.rv); | |
1112 out.rv = callback2.WaitForResult(); | |
1113 ASSERT_EQ(OK, out.rv); | |
1114 | |
1115 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
1116 EXPECT_TRUE(response1->headers.get() != NULL); | |
1117 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
1118 out.status_line = response1->headers->GetStatusLine(); | |
1119 out.response_info = *response1; | |
1120 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
1121 EXPECT_EQ(OK, out.rv); | |
1122 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1123 EXPECT_EQ("hello!hello!", out.response_data); | |
1124 | |
1125 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
1126 EXPECT_TRUE(response2->headers.get() != NULL); | |
1127 EXPECT_TRUE(response2->was_fetched_via_spdy); | |
1128 out.status_line = response2->headers->GetStatusLine(); | |
1129 out.response_info = *response2; | |
1130 out.rv = ReadTransaction(trans2.get(), &out.response_data); | |
1131 EXPECT_EQ(OK, out.rv); | |
1132 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1133 EXPECT_EQ("hello!hello!", out.response_data); | |
1134 | |
1135 helper.VerifyDataConsumed(); | |
1136 } | |
1137 | |
1138 // Similar to ThreeGets above, however this test adds a SETTINGS | |
1139 // frame. The SETTINGS frame is read during the IO loop waiting on | |
1140 // the first transaction completion, and sets a maximum concurrent | |
1141 // stream limit of 1. This means that our IO loop exists after the | |
1142 // second transaction completes, so we can assert on read_index(). | |
1143 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) { | |
1144 // Construct the request. | |
1145 scoped_ptr<SpdyFrame> req( | |
1146 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
1147 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1148 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false)); | |
1149 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1150 | |
1151 scoped_ptr<SpdyFrame> req2( | |
1152 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); | |
1153 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
1154 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); | |
1155 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
1156 | |
1157 scoped_ptr<SpdyFrame> req3( | |
1158 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true)); | |
1159 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5)); | |
1160 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, false)); | |
1161 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(5, true)); | |
1162 | |
1163 SettingsMap settings; | |
1164 const uint32 max_concurrent_streams = 1; | |
1165 settings[SETTINGS_MAX_CONCURRENT_STREAMS] = | |
1166 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); | |
1167 scoped_ptr<SpdyFrame> settings_frame( | |
1168 spdy_util_.ConstructSpdySettings(settings)); | |
1169 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); | |
1170 | |
1171 MockWrite writes[] = { | |
1172 CreateMockWrite(*req), | |
1173 CreateMockWrite(*settings_ack, 2), | |
1174 CreateMockWrite(*req2), | |
1175 CreateMockWrite(*req3), | |
1176 }; | |
1177 | |
1178 MockRead reads[] = { | |
1179 CreateMockRead(*settings_frame, 1), | |
1180 CreateMockRead(*resp), | |
1181 CreateMockRead(*body), | |
1182 CreateMockRead(*fbody), | |
1183 CreateMockRead(*resp2, 8), | |
1184 CreateMockRead(*body2), | |
1185 CreateMockRead(*fbody2), | |
1186 CreateMockRead(*resp3, 13), | |
1187 CreateMockRead(*body3), | |
1188 CreateMockRead(*fbody3), | |
1189 | |
1190 MockRead(ASYNC, 0, 0), // EOF | |
1191 }; | |
1192 | |
1193 OrderedSocketData data(reads, arraysize(reads), | |
1194 writes, arraysize(writes)); | |
1195 OrderedSocketData data_placeholder(NULL, 0, NULL, 0); | |
1196 | |
1197 BoundNetLog log; | |
1198 TransactionHelperResult out; | |
1199 { | |
1200 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
1201 BoundNetLog(), GetParam(), NULL); | |
1202 helper.RunPreTestSetup(); | |
1203 helper.AddData(&data); | |
1204 // We require placeholder data because three get requests are sent out, so | |
1205 // there needs to be three sets of SSL connection data. | |
1206 helper.AddData(&data_placeholder); | |
1207 helper.AddData(&data_placeholder); | |
1208 scoped_ptr<HttpNetworkTransaction> trans1( | |
1209 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1210 scoped_ptr<HttpNetworkTransaction> trans2( | |
1211 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1212 scoped_ptr<HttpNetworkTransaction> trans3( | |
1213 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1214 | |
1215 TestCompletionCallback callback1; | |
1216 TestCompletionCallback callback2; | |
1217 TestCompletionCallback callback3; | |
1218 | |
1219 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
1220 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
1221 HttpRequestInfo httpreq3 = CreateGetRequest(); | |
1222 | |
1223 out.rv = trans1->Start(&httpreq1, callback1.callback(), log); | |
1224 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1225 // Run transaction 1 through quickly to force a read of our SETTINGS | |
1226 // frame. | |
1227 out.rv = callback1.WaitForResult(); | |
1228 ASSERT_EQ(OK, out.rv); | |
1229 | |
1230 out.rv = trans2->Start(&httpreq2, callback2.callback(), log); | |
1231 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1232 out.rv = trans3->Start(&httpreq3, callback3.callback(), log); | |
1233 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1234 out.rv = callback2.WaitForResult(); | |
1235 ASSERT_EQ(OK, out.rv); | |
1236 EXPECT_EQ(7U, data.read_index()); // i.e. the third trans was queued | |
1237 | |
1238 out.rv = callback3.WaitForResult(); | |
1239 ASSERT_EQ(OK, out.rv); | |
1240 | |
1241 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
1242 ASSERT_TRUE(response1 != NULL); | |
1243 EXPECT_TRUE(response1->headers.get() != NULL); | |
1244 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
1245 out.status_line = response1->headers->GetStatusLine(); | |
1246 out.response_info = *response1; | |
1247 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
1248 EXPECT_EQ(OK, out.rv); | |
1249 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1250 EXPECT_EQ("hello!hello!", out.response_data); | |
1251 | |
1252 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
1253 out.status_line = response2->headers->GetStatusLine(); | |
1254 out.response_info = *response2; | |
1255 out.rv = ReadTransaction(trans2.get(), &out.response_data); | |
1256 EXPECT_EQ(OK, out.rv); | |
1257 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1258 EXPECT_EQ("hello!hello!", out.response_data); | |
1259 | |
1260 const HttpResponseInfo* response3 = trans3->GetResponseInfo(); | |
1261 out.status_line = response3->headers->GetStatusLine(); | |
1262 out.response_info = *response3; | |
1263 out.rv = ReadTransaction(trans3.get(), &out.response_data); | |
1264 EXPECT_EQ(OK, out.rv); | |
1265 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1266 EXPECT_EQ("hello!hello!", out.response_data); | |
1267 | |
1268 helper.VerifyDataConsumed(); | |
1269 } | |
1270 EXPECT_EQ(OK, out.rv); | |
1271 } | |
1272 | |
1273 // Similar to ThreeGetsWithMaxConcurrent above, however this test adds | |
1274 // a fourth transaction. The third and fourth transactions have | |
1275 // different data ("hello!" vs "hello!hello!") and because of the | |
1276 // user specified priority, we expect to see them inverted in | |
1277 // the response from the server. | |
1278 TEST_P(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) { | |
1279 // Construct the request. | |
1280 scoped_ptr<SpdyFrame> req( | |
1281 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
1282 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1283 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false)); | |
1284 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1285 | |
1286 scoped_ptr<SpdyFrame> req2( | |
1287 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); | |
1288 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
1289 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); | |
1290 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
1291 | |
1292 scoped_ptr<SpdyFrame> req4( | |
1293 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, HIGHEST, true)); | |
1294 scoped_ptr<SpdyFrame> resp4(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5)); | |
1295 scoped_ptr<SpdyFrame> fbody4(spdy_util_.ConstructSpdyBodyFrame(5, true)); | |
1296 | |
1297 scoped_ptr<SpdyFrame> req3( | |
1298 spdy_util_.ConstructSpdyGet(NULL, 0, false, 7, LOWEST, true)); | |
1299 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 7)); | |
1300 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(7, false)); | |
1301 scoped_ptr<SpdyFrame> fbody3(spdy_util_.ConstructSpdyBodyFrame(7, true)); | |
1302 | |
1303 SettingsMap settings; | |
1304 const uint32 max_concurrent_streams = 1; | |
1305 settings[SETTINGS_MAX_CONCURRENT_STREAMS] = | |
1306 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); | |
1307 scoped_ptr<SpdyFrame> settings_frame( | |
1308 spdy_util_.ConstructSpdySettings(settings)); | |
1309 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); | |
1310 | |
1311 MockWrite writes[] = { CreateMockWrite(*req), | |
1312 CreateMockWrite(*settings_ack, 2), | |
1313 CreateMockWrite(*req2), | |
1314 CreateMockWrite(*req4), | |
1315 CreateMockWrite(*req3), | |
1316 }; | |
1317 MockRead reads[] = { | |
1318 CreateMockRead(*settings_frame, 1), | |
1319 CreateMockRead(*resp), | |
1320 CreateMockRead(*body), | |
1321 CreateMockRead(*fbody), | |
1322 CreateMockRead(*resp2, 8), | |
1323 CreateMockRead(*body2), | |
1324 CreateMockRead(*fbody2), | |
1325 CreateMockRead(*resp4, 14), | |
1326 CreateMockRead(*fbody4), | |
1327 CreateMockRead(*resp3, 17), | |
1328 CreateMockRead(*body3), | |
1329 CreateMockRead(*fbody3), | |
1330 | |
1331 MockRead(ASYNC, 0, 0), // EOF | |
1332 }; | |
1333 | |
1334 OrderedSocketData data(reads, arraysize(reads), | |
1335 writes, arraysize(writes)); | |
1336 OrderedSocketData data_placeholder(NULL, 0, NULL, 0); | |
1337 | |
1338 BoundNetLog log; | |
1339 TransactionHelperResult out; | |
1340 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
1341 BoundNetLog(), GetParam(), NULL); | |
1342 helper.RunPreTestSetup(); | |
1343 helper.AddData(&data); | |
1344 // We require placeholder data because four get requests are sent out, so | |
1345 // there needs to be four sets of SSL connection data. | |
1346 helper.AddData(&data_placeholder); | |
1347 helper.AddData(&data_placeholder); | |
1348 helper.AddData(&data_placeholder); | |
1349 scoped_ptr<HttpNetworkTransaction> trans1( | |
1350 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1351 scoped_ptr<HttpNetworkTransaction> trans2( | |
1352 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1353 scoped_ptr<HttpNetworkTransaction> trans3( | |
1354 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1355 scoped_ptr<HttpNetworkTransaction> trans4( | |
1356 new HttpNetworkTransaction(HIGHEST, helper.session().get())); | |
1357 | |
1358 TestCompletionCallback callback1; | |
1359 TestCompletionCallback callback2; | |
1360 TestCompletionCallback callback3; | |
1361 TestCompletionCallback callback4; | |
1362 | |
1363 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
1364 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
1365 HttpRequestInfo httpreq3 = CreateGetRequest(); | |
1366 HttpRequestInfo httpreq4 = CreateGetRequest(); | |
1367 | |
1368 out.rv = trans1->Start(&httpreq1, callback1.callback(), log); | |
1369 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1370 // Run transaction 1 through quickly to force a read of our SETTINGS frame. | |
1371 out.rv = callback1.WaitForResult(); | |
1372 ASSERT_EQ(OK, out.rv); | |
1373 | |
1374 out.rv = trans2->Start(&httpreq2, callback2.callback(), log); | |
1375 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1376 out.rv = trans3->Start(&httpreq3, callback3.callback(), log); | |
1377 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1378 out.rv = trans4->Start(&httpreq4, callback4.callback(), log); | |
1379 ASSERT_EQ(ERR_IO_PENDING, out.rv); | |
1380 | |
1381 out.rv = callback2.WaitForResult(); | |
1382 ASSERT_EQ(OK, out.rv); | |
1383 EXPECT_EQ(data.read_index(), 7U); // i.e. the third & fourth trans queued | |
1384 | |
1385 out.rv = callback3.WaitForResult(); | |
1386 ASSERT_EQ(OK, out.rv); | |
1387 | |
1388 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
1389 EXPECT_TRUE(response1->headers.get() != NULL); | |
1390 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
1391 out.status_line = response1->headers->GetStatusLine(); | |
1392 out.response_info = *response1; | |
1393 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
1394 EXPECT_EQ(OK, out.rv); | |
1395 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1396 EXPECT_EQ("hello!hello!", out.response_data); | |
1397 | |
1398 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
1399 out.status_line = response2->headers->GetStatusLine(); | |
1400 out.response_info = *response2; | |
1401 out.rv = ReadTransaction(trans2.get(), &out.response_data); | |
1402 EXPECT_EQ(OK, out.rv); | |
1403 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1404 EXPECT_EQ("hello!hello!", out.response_data); | |
1405 | |
1406 // notice: response3 gets two hellos, response4 gets one | |
1407 // hello, so we know dequeuing priority was respected. | |
1408 const HttpResponseInfo* response3 = trans3->GetResponseInfo(); | |
1409 out.status_line = response3->headers->GetStatusLine(); | |
1410 out.response_info = *response3; | |
1411 out.rv = ReadTransaction(trans3.get(), &out.response_data); | |
1412 EXPECT_EQ(OK, out.rv); | |
1413 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1414 EXPECT_EQ("hello!hello!", out.response_data); | |
1415 | |
1416 out.rv = callback4.WaitForResult(); | |
1417 EXPECT_EQ(OK, out.rv); | |
1418 const HttpResponseInfo* response4 = trans4->GetResponseInfo(); | |
1419 out.status_line = response4->headers->GetStatusLine(); | |
1420 out.response_info = *response4; | |
1421 out.rv = ReadTransaction(trans4.get(), &out.response_data); | |
1422 EXPECT_EQ(OK, out.rv); | |
1423 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1424 EXPECT_EQ("hello!", out.response_data); | |
1425 helper.VerifyDataConsumed(); | |
1426 EXPECT_EQ(OK, out.rv); | |
1427 } | |
1428 | |
1429 // Similar to ThreeGetsMaxConcurrrent above, however, this test | |
1430 // deletes a session in the middle of the transaction to insure | |
1431 // that we properly remove pendingcreatestream objects from | |
1432 // the spdy_session | |
1433 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) { | |
1434 // Construct the request. | |
1435 scoped_ptr<SpdyFrame> req( | |
1436 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
1437 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1438 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false)); | |
1439 scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1440 | |
1441 scoped_ptr<SpdyFrame> req2( | |
1442 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); | |
1443 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
1444 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false)); | |
1445 scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
1446 | |
1447 SettingsMap settings; | |
1448 const uint32 max_concurrent_streams = 1; | |
1449 settings[SETTINGS_MAX_CONCURRENT_STREAMS] = | |
1450 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); | |
1451 scoped_ptr<SpdyFrame> settings_frame( | |
1452 spdy_util_.ConstructSpdySettings(settings)); | |
1453 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); | |
1454 | |
1455 MockWrite writes[] = { | |
1456 CreateMockWrite(*req), | |
1457 CreateMockWrite(*settings_ack, 2), | |
1458 CreateMockWrite(*req2), | |
1459 }; | |
1460 MockRead reads[] = { | |
1461 CreateMockRead(*settings_frame, 1), | |
1462 CreateMockRead(*resp), | |
1463 CreateMockRead(*body), | |
1464 CreateMockRead(*fbody), | |
1465 CreateMockRead(*resp2, 8), | |
1466 CreateMockRead(*body2), | |
1467 CreateMockRead(*fbody2), | |
1468 MockRead(ASYNC, 0, 0), // EOF | |
1469 }; | |
1470 | |
1471 OrderedSocketData data(reads, arraysize(reads), | |
1472 writes, arraysize(writes)); | |
1473 OrderedSocketData data_placeholder(NULL, 0, NULL, 0); | |
1474 | |
1475 BoundNetLog log; | |
1476 TransactionHelperResult out; | |
1477 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
1478 BoundNetLog(), GetParam(), NULL); | |
1479 helper.RunPreTestSetup(); | |
1480 helper.AddData(&data); | |
1481 // We require placeholder data because three get requests are sent out, so | |
1482 // there needs to be three sets of SSL connection data. | |
1483 helper.AddData(&data_placeholder); | |
1484 helper.AddData(&data_placeholder); | |
1485 scoped_ptr<HttpNetworkTransaction> trans1( | |
1486 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1487 scoped_ptr<HttpNetworkTransaction> trans2( | |
1488 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1489 scoped_ptr<HttpNetworkTransaction> trans3( | |
1490 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1491 | |
1492 TestCompletionCallback callback1; | |
1493 TestCompletionCallback callback2; | |
1494 TestCompletionCallback callback3; | |
1495 | |
1496 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
1497 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
1498 HttpRequestInfo httpreq3 = CreateGetRequest(); | |
1499 | |
1500 out.rv = trans1->Start(&httpreq1, callback1.callback(), log); | |
1501 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1502 // Run transaction 1 through quickly to force a read of our SETTINGS frame. | |
1503 out.rv = callback1.WaitForResult(); | |
1504 ASSERT_EQ(OK, out.rv); | |
1505 | |
1506 out.rv = trans2->Start(&httpreq2, callback2.callback(), log); | |
1507 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1508 out.rv = trans3->Start(&httpreq3, callback3.callback(), log); | |
1509 delete trans3.release(); | |
1510 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1511 out.rv = callback2.WaitForResult(); | |
1512 ASSERT_EQ(OK, out.rv); | |
1513 | |
1514 EXPECT_EQ(8U, data.read_index()); | |
1515 | |
1516 const HttpResponseInfo* response1 = trans1->GetResponseInfo(); | |
1517 ASSERT_TRUE(response1 != NULL); | |
1518 EXPECT_TRUE(response1->headers.get() != NULL); | |
1519 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
1520 out.status_line = response1->headers->GetStatusLine(); | |
1521 out.response_info = *response1; | |
1522 out.rv = ReadTransaction(trans1.get(), &out.response_data); | |
1523 EXPECT_EQ(OK, out.rv); | |
1524 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1525 EXPECT_EQ("hello!hello!", out.response_data); | |
1526 | |
1527 const HttpResponseInfo* response2 = trans2->GetResponseInfo(); | |
1528 ASSERT_TRUE(response2 != NULL); | |
1529 out.status_line = response2->headers->GetStatusLine(); | |
1530 out.response_info = *response2; | |
1531 out.rv = ReadTransaction(trans2.get(), &out.response_data); | |
1532 EXPECT_EQ(OK, out.rv); | |
1533 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1534 EXPECT_EQ("hello!hello!", out.response_data); | |
1535 helper.VerifyDataConsumed(); | |
1536 EXPECT_EQ(OK, out.rv); | |
1537 } | |
1538 | |
1539 namespace { | |
1540 | |
1541 // The KillerCallback will delete the transaction on error as part of the | |
1542 // callback. | |
1543 class KillerCallback : public TestCompletionCallbackBase { | |
1544 public: | |
1545 explicit KillerCallback(HttpNetworkTransaction* transaction) | |
1546 : transaction_(transaction), | |
1547 callback_(base::Bind(&KillerCallback::OnComplete, | |
1548 base::Unretained(this))) { | |
1549 } | |
1550 | |
1551 ~KillerCallback() override {} | |
1552 | |
1553 const CompletionCallback& callback() const { return callback_; } | |
1554 | |
1555 private: | |
1556 void OnComplete(int result) { | |
1557 if (result < 0) | |
1558 delete transaction_; | |
1559 | |
1560 SetResult(result); | |
1561 } | |
1562 | |
1563 HttpNetworkTransaction* transaction_; | |
1564 CompletionCallback callback_; | |
1565 }; | |
1566 | |
1567 } // namespace | |
1568 | |
1569 // Similar to ThreeGetsMaxConcurrrentDelete above, however, this test | |
1570 // closes the socket while we have a pending transaction waiting for | |
1571 // a pending stream creation. http://crbug.com/52901 | |
1572 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) { | |
1573 // Construct the request. | |
1574 scoped_ptr<SpdyFrame> req( | |
1575 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
1576 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1577 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false)); | |
1578 scoped_ptr<SpdyFrame> fin_body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1579 | |
1580 scoped_ptr<SpdyFrame> req2( | |
1581 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); | |
1582 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
1583 | |
1584 SettingsMap settings; | |
1585 const uint32 max_concurrent_streams = 1; | |
1586 settings[SETTINGS_MAX_CONCURRENT_STREAMS] = | |
1587 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); | |
1588 scoped_ptr<SpdyFrame> settings_frame( | |
1589 spdy_util_.ConstructSpdySettings(settings)); | |
1590 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); | |
1591 | |
1592 MockWrite writes[] = { | |
1593 CreateMockWrite(*req), | |
1594 CreateMockWrite(*settings_ack, 2), | |
1595 CreateMockWrite(*req2), | |
1596 }; | |
1597 MockRead reads[] = { | |
1598 CreateMockRead(*settings_frame, 1), | |
1599 CreateMockRead(*resp), | |
1600 CreateMockRead(*body), | |
1601 CreateMockRead(*fin_body), | |
1602 CreateMockRead(*resp2, 8), | |
1603 MockRead(ASYNC, ERR_CONNECTION_RESET, 0), // Abort! | |
1604 }; | |
1605 | |
1606 OrderedSocketData data(reads, arraysize(reads), | |
1607 writes, arraysize(writes)); | |
1608 OrderedSocketData data_placeholder(NULL, 0, NULL, 0); | |
1609 | |
1610 BoundNetLog log; | |
1611 TransactionHelperResult out; | |
1612 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
1613 BoundNetLog(), GetParam(), NULL); | |
1614 helper.RunPreTestSetup(); | |
1615 helper.AddData(&data); | |
1616 // We require placeholder data because three get requests are sent out, so | |
1617 // there needs to be three sets of SSL connection data. | |
1618 helper.AddData(&data_placeholder); | |
1619 helper.AddData(&data_placeholder); | |
1620 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session().get()); | |
1621 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session().get()); | |
1622 HttpNetworkTransaction* trans3( | |
1623 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
1624 | |
1625 TestCompletionCallback callback1; | |
1626 TestCompletionCallback callback2; | |
1627 KillerCallback callback3(trans3); | |
1628 | |
1629 HttpRequestInfo httpreq1 = CreateGetRequest(); | |
1630 HttpRequestInfo httpreq2 = CreateGetRequest(); | |
1631 HttpRequestInfo httpreq3 = CreateGetRequest(); | |
1632 | |
1633 out.rv = trans1.Start(&httpreq1, callback1.callback(), log); | |
1634 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1635 // Run transaction 1 through quickly to force a read of our SETTINGS frame. | |
1636 out.rv = callback1.WaitForResult(); | |
1637 ASSERT_EQ(OK, out.rv); | |
1638 | |
1639 out.rv = trans2.Start(&httpreq2, callback2.callback(), log); | |
1640 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1641 out.rv = trans3->Start(&httpreq3, callback3.callback(), log); | |
1642 ASSERT_EQ(out.rv, ERR_IO_PENDING); | |
1643 out.rv = callback3.WaitForResult(); | |
1644 ASSERT_EQ(ERR_ABORTED, out.rv); | |
1645 | |
1646 EXPECT_EQ(6U, data.read_index()); | |
1647 | |
1648 const HttpResponseInfo* response1 = trans1.GetResponseInfo(); | |
1649 ASSERT_TRUE(response1 != NULL); | |
1650 EXPECT_TRUE(response1->headers.get() != NULL); | |
1651 EXPECT_TRUE(response1->was_fetched_via_spdy); | |
1652 out.status_line = response1->headers->GetStatusLine(); | |
1653 out.response_info = *response1; | |
1654 out.rv = ReadTransaction(&trans1, &out.response_data); | |
1655 EXPECT_EQ(OK, out.rv); | |
1656 | |
1657 const HttpResponseInfo* response2 = trans2.GetResponseInfo(); | |
1658 ASSERT_TRUE(response2 != NULL); | |
1659 out.status_line = response2->headers->GetStatusLine(); | |
1660 out.response_info = *response2; | |
1661 out.rv = ReadTransaction(&trans2, &out.response_data); | |
1662 EXPECT_EQ(ERR_CONNECTION_RESET, out.rv); | |
1663 | |
1664 helper.VerifyDataConsumed(); | |
1665 } | |
1666 | |
1667 // Test that a simple PUT request works. | |
1668 TEST_P(SpdyNetworkTransactionTest, Put) { | |
1669 // Setup the request | |
1670 HttpRequestInfo request; | |
1671 request.method = "PUT"; | |
1672 request.url = GURL("http://www.google.com/"); | |
1673 | |
1674 scoped_ptr<SpdyHeaderBlock> put_headers( | |
1675 spdy_util_.ConstructPutHeaderBlock("http://www.google.com", 0)); | |
1676 scoped_ptr<SpdyFrame> req( | |
1677 spdy_util_.ConstructSpdySyn(1, *put_headers, LOWEST, false, true)); | |
1678 MockWrite writes[] = { | |
1679 CreateMockWrite(*req), | |
1680 }; | |
1681 | |
1682 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1683 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1684 MockRead reads[] = { | |
1685 CreateMockRead(*resp), | |
1686 CreateMockRead(*body), | |
1687 MockRead(ASYNC, 0, 0) // EOF | |
1688 }; | |
1689 | |
1690 DelayedSocketData data(1, reads, arraysize(reads), | |
1691 writes, arraysize(writes)); | |
1692 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
1693 BoundNetLog(), GetParam(), NULL); | |
1694 helper.RunToCompletion(&data); | |
1695 TransactionHelperResult out = helper.output(); | |
1696 | |
1697 EXPECT_EQ(OK, out.rv); | |
1698 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1699 } | |
1700 | |
1701 // Test that a simple HEAD request works. | |
1702 TEST_P(SpdyNetworkTransactionTest, Head) { | |
1703 // Setup the request | |
1704 HttpRequestInfo request; | |
1705 request.method = "HEAD"; | |
1706 request.url = GURL("http://www.google.com/"); | |
1707 | |
1708 scoped_ptr<SpdyHeaderBlock> head_headers( | |
1709 spdy_util_.ConstructHeadHeaderBlock("http://www.google.com", 0)); | |
1710 scoped_ptr<SpdyFrame> req( | |
1711 spdy_util_.ConstructSpdySyn(1, *head_headers, LOWEST, false, true)); | |
1712 MockWrite writes[] = { | |
1713 CreateMockWrite(*req), | |
1714 }; | |
1715 | |
1716 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
1717 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1718 MockRead reads[] = { | |
1719 CreateMockRead(*resp), | |
1720 CreateMockRead(*body), | |
1721 MockRead(ASYNC, 0, 0) // EOF | |
1722 }; | |
1723 | |
1724 DelayedSocketData data(1, reads, arraysize(reads), | |
1725 writes, arraysize(writes)); | |
1726 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
1727 BoundNetLog(), GetParam(), NULL); | |
1728 helper.RunToCompletion(&data); | |
1729 TransactionHelperResult out = helper.output(); | |
1730 | |
1731 EXPECT_EQ(OK, out.rv); | |
1732 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1733 } | |
1734 | |
1735 // Test that a simple POST works. | |
1736 TEST_P(SpdyNetworkTransactionTest, Post) { | |
1737 scoped_ptr<SpdyFrame> req( | |
1738 spdy_util_.ConstructSpdyPost( | |
1739 kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0)); | |
1740 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1741 MockWrite writes[] = { | |
1742 CreateMockWrite(*req), | |
1743 CreateMockWrite(*body), // POST upload frame | |
1744 }; | |
1745 | |
1746 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
1747 MockRead reads[] = { | |
1748 CreateMockRead(*resp), | |
1749 CreateMockRead(*body), | |
1750 MockRead(ASYNC, 0, 0) // EOF | |
1751 }; | |
1752 | |
1753 DelayedSocketData data(2, reads, arraysize(reads), | |
1754 writes, arraysize(writes)); | |
1755 NormalSpdyTransactionHelper helper(CreatePostRequest(), DEFAULT_PRIORITY, | |
1756 BoundNetLog(), GetParam(), NULL); | |
1757 helper.RunToCompletion(&data); | |
1758 TransactionHelperResult out = helper.output(); | |
1759 EXPECT_EQ(OK, out.rv); | |
1760 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1761 EXPECT_EQ("hello!", out.response_data); | |
1762 } | |
1763 | |
1764 // Test that a POST with a file works. | |
1765 TEST_P(SpdyNetworkTransactionTest, FilePost) { | |
1766 scoped_ptr<SpdyFrame> req( | |
1767 spdy_util_.ConstructSpdyPost( | |
1768 kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0)); | |
1769 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1770 MockWrite writes[] = { | |
1771 CreateMockWrite(*req), | |
1772 CreateMockWrite(*body), // POST upload frame | |
1773 }; | |
1774 | |
1775 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
1776 MockRead reads[] = { | |
1777 CreateMockRead(*resp), | |
1778 CreateMockRead(*body), | |
1779 MockRead(ASYNC, 0, 0) // EOF | |
1780 }; | |
1781 | |
1782 DelayedSocketData data(2, reads, arraysize(reads), | |
1783 writes, arraysize(writes)); | |
1784 NormalSpdyTransactionHelper helper(CreateFilePostRequest(), DEFAULT_PRIORITY, | |
1785 BoundNetLog(), GetParam(), NULL); | |
1786 helper.RunToCompletion(&data); | |
1787 TransactionHelperResult out = helper.output(); | |
1788 EXPECT_EQ(OK, out.rv); | |
1789 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1790 EXPECT_EQ("hello!", out.response_data); | |
1791 } | |
1792 | |
1793 // Test that a POST with a unreadable file fails. | |
1794 TEST_P(SpdyNetworkTransactionTest, UnreadableFilePost) { | |
1795 MockWrite writes[] = { | |
1796 MockWrite(ASYNC, 0, 0) // EOF | |
1797 }; | |
1798 MockRead reads[] = { | |
1799 MockRead(ASYNC, 0, 0) // EOF | |
1800 }; | |
1801 | |
1802 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); | |
1803 NormalSpdyTransactionHelper helper(CreateUnreadableFilePostRequest(), | |
1804 DEFAULT_PRIORITY, | |
1805 BoundNetLog(), GetParam(), NULL); | |
1806 helper.RunPreTestSetup(); | |
1807 helper.AddData(&data); | |
1808 helper.RunDefaultTest(); | |
1809 | |
1810 base::RunLoop().RunUntilIdle(); | |
1811 helper.VerifyDataNotConsumed(); | |
1812 EXPECT_EQ(ERR_ACCESS_DENIED, helper.output().rv); | |
1813 } | |
1814 | |
1815 // Test that a complex POST works. | |
1816 TEST_P(SpdyNetworkTransactionTest, ComplexPost) { | |
1817 scoped_ptr<SpdyFrame> req( | |
1818 spdy_util_.ConstructSpdyPost( | |
1819 kRequestUrl, 1, kUploadDataSize, LOWEST, NULL, 0)); | |
1820 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1821 MockWrite writes[] = { | |
1822 CreateMockWrite(*req), | |
1823 CreateMockWrite(*body), // POST upload frame | |
1824 }; | |
1825 | |
1826 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
1827 MockRead reads[] = { | |
1828 CreateMockRead(*resp), | |
1829 CreateMockRead(*body), | |
1830 MockRead(ASYNC, 0, 0) // EOF | |
1831 }; | |
1832 | |
1833 DelayedSocketData data(2, reads, arraysize(reads), | |
1834 writes, arraysize(writes)); | |
1835 NormalSpdyTransactionHelper helper(CreateComplexPostRequest(), | |
1836 DEFAULT_PRIORITY, | |
1837 BoundNetLog(), GetParam(), NULL); | |
1838 helper.RunToCompletion(&data); | |
1839 TransactionHelperResult out = helper.output(); | |
1840 EXPECT_EQ(OK, out.rv); | |
1841 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1842 EXPECT_EQ("hello!", out.response_data); | |
1843 } | |
1844 | |
1845 // Test that a chunked POST works. | |
1846 TEST_P(SpdyNetworkTransactionTest, ChunkedPost) { | |
1847 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); | |
1848 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1849 MockWrite writes[] = { | |
1850 CreateMockWrite(*req), | |
1851 CreateMockWrite(*body), | |
1852 }; | |
1853 | |
1854 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
1855 MockRead reads[] = { | |
1856 CreateMockRead(*resp), | |
1857 CreateMockRead(*body), | |
1858 MockRead(ASYNC, 0, 0) // EOF | |
1859 }; | |
1860 | |
1861 DelayedSocketData data(2, reads, arraysize(reads), | |
1862 writes, arraysize(writes)); | |
1863 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(), | |
1864 DEFAULT_PRIORITY, | |
1865 BoundNetLog(), GetParam(), NULL); | |
1866 | |
1867 // These chunks get merged into a single frame when being sent. | |
1868 const int kFirstChunkSize = kUploadDataSize/2; | |
1869 upload_chunked_data_stream()->AppendData(kUploadData, kFirstChunkSize, false); | |
1870 upload_chunked_data_stream()->AppendData( | |
1871 kUploadData + kFirstChunkSize, kUploadDataSize - kFirstChunkSize, true); | |
1872 | |
1873 helper.RunToCompletion(&data); | |
1874 TransactionHelperResult out = helper.output(); | |
1875 EXPECT_EQ(OK, out.rv); | |
1876 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1877 EXPECT_EQ(kUploadData, out.response_data); | |
1878 } | |
1879 | |
1880 // Test that a chunked POST works with chunks appended after transaction starts. | |
1881 TEST_P(SpdyNetworkTransactionTest, DelayedChunkedPost) { | |
1882 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); | |
1883 scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, false)); | |
1884 scoped_ptr<SpdyFrame> chunk2(spdy_util_.ConstructSpdyBodyFrame(1, false)); | |
1885 scoped_ptr<SpdyFrame> chunk3(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1886 MockWrite writes[] = { | |
1887 CreateMockWrite(*req), | |
1888 CreateMockWrite(*chunk1), | |
1889 CreateMockWrite(*chunk2), | |
1890 CreateMockWrite(*chunk3), | |
1891 }; | |
1892 | |
1893 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
1894 MockRead reads[] = { | |
1895 CreateMockRead(*resp), | |
1896 CreateMockRead(*chunk1), | |
1897 CreateMockRead(*chunk2), | |
1898 CreateMockRead(*chunk3), | |
1899 MockRead(ASYNC, 0, 0) // EOF | |
1900 }; | |
1901 | |
1902 DelayedSocketData data(4, reads, arraysize(reads), | |
1903 writes, arraysize(writes)); | |
1904 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(), | |
1905 DEFAULT_PRIORITY, | |
1906 BoundNetLog(), GetParam(), NULL); | |
1907 | |
1908 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false); | |
1909 | |
1910 helper.RunPreTestSetup(); | |
1911 helper.AddData(&data); | |
1912 ASSERT_TRUE(helper.StartDefaultTest()); | |
1913 | |
1914 base::RunLoop().RunUntilIdle(); | |
1915 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false); | |
1916 base::RunLoop().RunUntilIdle(); | |
1917 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true); | |
1918 | |
1919 helper.FinishDefaultTest(); | |
1920 helper.VerifyDataConsumed(); | |
1921 | |
1922 std::string expected_response; | |
1923 expected_response += kUploadData; | |
1924 expected_response += kUploadData; | |
1925 expected_response += kUploadData; | |
1926 | |
1927 TransactionHelperResult out = helper.output(); | |
1928 EXPECT_EQ(OK, out.rv); | |
1929 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1930 EXPECT_EQ(expected_response, out.response_data); | |
1931 } | |
1932 | |
1933 // Test that a POST without any post data works. | |
1934 TEST_P(SpdyNetworkTransactionTest, NullPost) { | |
1935 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
1936 // Setup the request | |
1937 HttpRequestInfo request; | |
1938 request.method = "POST"; | |
1939 request.url = GURL(kRequestUrl); | |
1940 // Create an empty UploadData. | |
1941 request.upload_data_stream = NULL; | |
1942 | |
1943 // When request.upload_data_stream is NULL for post, content-length is | |
1944 // expected to be 0. | |
1945 scoped_ptr<SpdyHeaderBlock> req_block( | |
1946 spdy_util_.ConstructPostHeaderBlock(kRequestUrl, 0)); | |
1947 scoped_ptr<SpdyFrame> req( | |
1948 spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true)); | |
1949 | |
1950 MockWrite writes[] = { | |
1951 CreateMockWrite(*req), | |
1952 }; | |
1953 | |
1954 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
1955 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
1956 MockRead reads[] = { | |
1957 CreateMockRead(*resp), | |
1958 CreateMockRead(*body), | |
1959 MockRead(ASYNC, 0, 0) // EOF | |
1960 }; | |
1961 | |
1962 DelayedSocketData data(1, reads, arraysize(reads), | |
1963 writes, arraysize(writes)); | |
1964 | |
1965 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
1966 BoundNetLog(), GetParam(), NULL); | |
1967 helper.RunToCompletion(&data); | |
1968 TransactionHelperResult out = helper.output(); | |
1969 EXPECT_EQ(OK, out.rv); | |
1970 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
1971 EXPECT_EQ("hello!", out.response_data); | |
1972 } | |
1973 | |
1974 // Test that a simple POST works. | |
1975 TEST_P(SpdyNetworkTransactionTest, EmptyPost) { | |
1976 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
1977 // Create an empty UploadDataStream. | |
1978 ScopedVector<UploadElementReader> element_readers; | |
1979 ElementsUploadDataStream stream(element_readers.Pass(), 0); | |
1980 | |
1981 // Setup the request | |
1982 HttpRequestInfo request; | |
1983 request.method = "POST"; | |
1984 request.url = GURL(kRequestUrl); | |
1985 request.upload_data_stream = &stream; | |
1986 | |
1987 const uint64 kContentLength = 0; | |
1988 | |
1989 scoped_ptr<SpdyHeaderBlock> req_block( | |
1990 spdy_util_.ConstructPostHeaderBlock(kRequestUrl, kContentLength)); | |
1991 scoped_ptr<SpdyFrame> req( | |
1992 spdy_util_.ConstructSpdySyn(1, *req_block, LOWEST, false, true)); | |
1993 | |
1994 MockWrite writes[] = { | |
1995 CreateMockWrite(*req), | |
1996 }; | |
1997 | |
1998 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
1999 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2000 MockRead reads[] = { | |
2001 CreateMockRead(*resp), | |
2002 CreateMockRead(*body), | |
2003 MockRead(ASYNC, 0, 0) // EOF | |
2004 }; | |
2005 | |
2006 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); | |
2007 | |
2008 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
2009 BoundNetLog(), GetParam(), NULL); | |
2010 helper.RunToCompletion(&data); | |
2011 TransactionHelperResult out = helper.output(); | |
2012 EXPECT_EQ(OK, out.rv); | |
2013 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
2014 EXPECT_EQ("hello!", out.response_data); | |
2015 } | |
2016 | |
2017 // While we're doing a post, the server sends the reply before upload completes. | |
2018 TEST_P(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) { | |
2019 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); | |
2020 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2021 MockWrite writes[] = { | |
2022 CreateMockWrite(*req, 0), | |
2023 CreateMockWrite(*body, 3), | |
2024 }; | |
2025 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
2026 MockRead reads[] = { | |
2027 CreateMockRead(*resp, 1), | |
2028 CreateMockRead(*body, 2), | |
2029 MockRead(ASYNC, 0, 4) // EOF | |
2030 }; | |
2031 | |
2032 // Write the request headers, and read the complete response | |
2033 // while still waiting for chunked request data. | |
2034 DeterministicSocketData data(reads, arraysize(reads), | |
2035 writes, arraysize(writes)); | |
2036 NormalSpdyTransactionHelper helper(CreateChunkedPostRequest(), | |
2037 DEFAULT_PRIORITY, | |
2038 BoundNetLog(), GetParam(), NULL); | |
2039 helper.SetDeterministic(); | |
2040 helper.RunPreTestSetup(); | |
2041 helper.AddDeterministicData(&data); | |
2042 | |
2043 ASSERT_TRUE(helper.StartDefaultTest()); | |
2044 | |
2045 // Process the request headers, SYN_REPLY, and response body. | |
2046 // The request body is still in flight. | |
2047 data.RunFor(3); | |
2048 | |
2049 const HttpResponseInfo* response = helper.trans()->GetResponseInfo(); | |
2050 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
2051 | |
2052 // Finish sending the request body. | |
2053 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true); | |
2054 data.RunFor(2); | |
2055 | |
2056 std::string response_body; | |
2057 EXPECT_EQ(OK, ReadTransaction(helper.trans(), &response_body)); | |
2058 EXPECT_EQ(kUploadData, response_body); | |
2059 helper.VerifyDataConsumed(); | |
2060 } | |
2061 | |
2062 // The client upon cancellation tries to send a RST_STREAM frame. The mock | |
2063 // socket causes the TCP write to return zero. This test checks that the client | |
2064 // tries to queue up the RST_STREAM frame again. | |
2065 TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) { | |
2066 scoped_ptr<SpdyFrame> req( | |
2067 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2068 scoped_ptr<SpdyFrame> rst( | |
2069 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
2070 MockWrite writes[] = { | |
2071 CreateMockWrite(*req.get(), 0, SYNCHRONOUS), | |
2072 MockWrite(SYNCHRONOUS, 0, 0, 2), | |
2073 CreateMockWrite(*rst.get(), 3, SYNCHRONOUS), | |
2074 }; | |
2075 | |
2076 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2077 MockRead reads[] = { | |
2078 CreateMockRead(*resp.get(), 1, ASYNC), | |
2079 MockRead(ASYNC, 0, 0, 4) // EOF | |
2080 }; | |
2081 | |
2082 DeterministicSocketData data(reads, arraysize(reads), | |
2083 writes, arraysize(writes)); | |
2084 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
2085 BoundNetLog(), GetParam(), NULL); | |
2086 helper.SetDeterministic(); | |
2087 helper.RunPreTestSetup(); | |
2088 helper.AddDeterministicData(&data); | |
2089 HttpNetworkTransaction* trans = helper.trans(); | |
2090 | |
2091 TestCompletionCallback callback; | |
2092 int rv = trans->Start( | |
2093 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
2094 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2095 | |
2096 data.SetStop(2); | |
2097 data.Run(); | |
2098 helper.ResetTrans(); | |
2099 data.SetStop(20); | |
2100 data.Run(); | |
2101 | |
2102 helper.VerifyDataConsumed(); | |
2103 } | |
2104 | |
2105 // Test that the transaction doesn't crash when we don't have a reply. | |
2106 TEST_P(SpdyNetworkTransactionTest, ResponseWithoutSynReply) { | |
2107 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2108 MockRead reads[] = { | |
2109 CreateMockRead(*body), | |
2110 MockRead(ASYNC, 0, 0) // EOF | |
2111 }; | |
2112 | |
2113 DelayedSocketData data(1, reads, arraysize(reads), NULL, 0); | |
2114 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
2115 BoundNetLog(), GetParam(), NULL); | |
2116 helper.RunToCompletion(&data); | |
2117 TransactionHelperResult out = helper.output(); | |
2118 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
2119 } | |
2120 | |
2121 // Test that the transaction doesn't crash when we get two replies on the same | |
2122 // stream ID. See http://crbug.com/45639. | |
2123 TEST_P(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) { | |
2124 scoped_ptr<SpdyFrame> req( | |
2125 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2126 scoped_ptr<SpdyFrame> rst( | |
2127 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); | |
2128 MockWrite writes[] = { | |
2129 CreateMockWrite(*req), | |
2130 CreateMockWrite(*rst), | |
2131 }; | |
2132 | |
2133 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2134 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2135 MockRead reads[] = { | |
2136 CreateMockRead(*resp), | |
2137 CreateMockRead(*resp), | |
2138 CreateMockRead(*body), | |
2139 MockRead(ASYNC, 0, 0) // EOF | |
2140 }; | |
2141 | |
2142 DelayedSocketData data(1, reads, arraysize(reads), | |
2143 writes, arraysize(writes)); | |
2144 | |
2145 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
2146 BoundNetLog(), GetParam(), NULL); | |
2147 helper.RunPreTestSetup(); | |
2148 helper.AddData(&data); | |
2149 | |
2150 HttpNetworkTransaction* trans = helper.trans(); | |
2151 | |
2152 TestCompletionCallback callback; | |
2153 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2154 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2155 rv = callback.WaitForResult(); | |
2156 EXPECT_EQ(OK, rv); | |
2157 | |
2158 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
2159 ASSERT_TRUE(response != NULL); | |
2160 EXPECT_TRUE(response->headers.get() != NULL); | |
2161 EXPECT_TRUE(response->was_fetched_via_spdy); | |
2162 std::string response_data; | |
2163 rv = ReadTransaction(trans, &response_data); | |
2164 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, rv); | |
2165 | |
2166 helper.VerifyDataConsumed(); | |
2167 } | |
2168 | |
2169 TEST_P(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) { | |
2170 // Construct the request. | |
2171 scoped_ptr<SpdyFrame> req( | |
2172 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2173 scoped_ptr<SpdyFrame> rst( | |
2174 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); | |
2175 MockWrite writes[] = { | |
2176 CreateMockWrite(*req), | |
2177 CreateMockWrite(*rst), | |
2178 }; | |
2179 | |
2180 const char* const headers[] = { | |
2181 "transfer-encoding", "chunked" | |
2182 }; | |
2183 scoped_ptr<SpdyFrame> resp( | |
2184 spdy_util_.ConstructSpdyGetSynReply(headers, 1, 1)); | |
2185 scoped_ptr<SpdyFrame> body( | |
2186 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2187 MockRead reads[] = { | |
2188 CreateMockRead(*resp), | |
2189 CreateMockRead(*body), | |
2190 MockRead(ASYNC, 0, 0) // EOF | |
2191 }; | |
2192 | |
2193 DelayedSocketData data(1, reads, arraysize(reads), | |
2194 writes, arraysize(writes)); | |
2195 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
2196 BoundNetLog(), GetParam(), NULL); | |
2197 helper.RunToCompletion(&data); | |
2198 TransactionHelperResult out = helper.output(); | |
2199 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
2200 | |
2201 helper.session()->spdy_session_pool()->CloseAllSessions(); | |
2202 helper.VerifyDataConsumed(); | |
2203 } | |
2204 | |
2205 TEST_P(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) { | |
2206 // Construct the request. | |
2207 scoped_ptr<SpdyFrame> req( | |
2208 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2209 scoped_ptr<SpdyFrame> rst( | |
2210 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR)); | |
2211 MockWrite writes[] = { | |
2212 CreateMockWrite(*req), | |
2213 CreateMockWrite(*rst), | |
2214 }; | |
2215 | |
2216 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2217 const char* const headers[] = { | |
2218 "transfer-encoding", "chunked" | |
2219 }; | |
2220 scoped_ptr<SpdyFrame> push( | |
2221 spdy_util_.ConstructSpdyPush(headers, arraysize(headers) / 2, | |
2222 2, 1, "http://www.google.com/1")); | |
2223 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2224 MockRead reads[] = { | |
2225 CreateMockRead(*resp), | |
2226 CreateMockRead(*push), | |
2227 CreateMockRead(*body), | |
2228 MockRead(ASYNC, 0, 0) // EOF | |
2229 }; | |
2230 | |
2231 DelayedSocketData data(1, reads, arraysize(reads), | |
2232 writes, arraysize(writes)); | |
2233 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
2234 BoundNetLog(), GetParam(), NULL); | |
2235 helper.RunToCompletion(&data); | |
2236 TransactionHelperResult out = helper.output(); | |
2237 EXPECT_EQ(OK, out.rv); | |
2238 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
2239 EXPECT_EQ("hello!", out.response_data); | |
2240 | |
2241 helper.session()->spdy_session_pool()->CloseAllSessions(); | |
2242 helper.VerifyDataConsumed(); | |
2243 } | |
2244 | |
2245 TEST_P(SpdyNetworkTransactionTest, CancelledTransaction) { | |
2246 // Construct the request. | |
2247 scoped_ptr<SpdyFrame> req( | |
2248 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2249 MockWrite writes[] = { | |
2250 CreateMockWrite(*req), | |
2251 }; | |
2252 | |
2253 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2254 MockRead reads[] = { | |
2255 CreateMockRead(*resp), | |
2256 // This following read isn't used by the test, except during the | |
2257 // RunUntilIdle() call at the end since the SpdySession survives the | |
2258 // HttpNetworkTransaction and still tries to continue Read()'ing. Any | |
2259 // MockRead will do here. | |
2260 MockRead(ASYNC, 0, 0) // EOF | |
2261 }; | |
2262 | |
2263 StaticSocketDataProvider data(reads, arraysize(reads), | |
2264 writes, arraysize(writes)); | |
2265 | |
2266 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
2267 BoundNetLog(), GetParam(), NULL); | |
2268 helper.RunPreTestSetup(); | |
2269 helper.AddData(&data); | |
2270 HttpNetworkTransaction* trans = helper.trans(); | |
2271 | |
2272 TestCompletionCallback callback; | |
2273 int rv = trans->Start( | |
2274 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
2275 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2276 helper.ResetTrans(); // Cancel the transaction. | |
2277 | |
2278 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
2279 // MockClientSocketFactory) are still alive. | |
2280 base::RunLoop().RunUntilIdle(); | |
2281 helper.VerifyDataNotConsumed(); | |
2282 } | |
2283 | |
2284 // Verify that the client sends a Rst Frame upon cancelling the stream. | |
2285 TEST_P(SpdyNetworkTransactionTest, CancelledTransactionSendRst) { | |
2286 scoped_ptr<SpdyFrame> req( | |
2287 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2288 scoped_ptr<SpdyFrame> rst( | |
2289 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
2290 MockWrite writes[] = { | |
2291 CreateMockWrite(*req, 0, SYNCHRONOUS), | |
2292 CreateMockWrite(*rst, 2, SYNCHRONOUS), | |
2293 }; | |
2294 | |
2295 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2296 MockRead reads[] = { | |
2297 CreateMockRead(*resp, 1, ASYNC), | |
2298 MockRead(ASYNC, 0, 0, 3) // EOF | |
2299 }; | |
2300 | |
2301 DeterministicSocketData data(reads, arraysize(reads), | |
2302 writes, arraysize(writes)); | |
2303 | |
2304 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
2305 BoundNetLog(), | |
2306 GetParam(), NULL); | |
2307 helper.SetDeterministic(); | |
2308 helper.RunPreTestSetup(); | |
2309 helper.AddDeterministicData(&data); | |
2310 HttpNetworkTransaction* trans = helper.trans(); | |
2311 | |
2312 TestCompletionCallback callback; | |
2313 | |
2314 int rv = trans->Start( | |
2315 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
2316 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2317 | |
2318 data.SetStop(2); | |
2319 data.Run(); | |
2320 helper.ResetTrans(); | |
2321 data.SetStop(20); | |
2322 data.Run(); | |
2323 | |
2324 helper.VerifyDataConsumed(); | |
2325 } | |
2326 | |
2327 // Verify that the client can correctly deal with the user callback attempting | |
2328 // to start another transaction on a session that is closing down. See | |
2329 // http://crbug.com/47455 | |
2330 TEST_P(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) { | |
2331 scoped_ptr<SpdyFrame> req( | |
2332 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2333 MockWrite writes[] = { CreateMockWrite(*req) }; | |
2334 MockWrite writes2[] = { CreateMockWrite(*req) }; | |
2335 | |
2336 // The indicated length of this frame is longer than its actual length. When | |
2337 // the session receives an empty frame after this one, it shuts down the | |
2338 // session, and calls the read callback with the incomplete data. | |
2339 const uint8 kGetBodyFrame2[] = { | |
2340 0x00, 0x00, 0x00, 0x01, | |
2341 0x01, 0x00, 0x00, 0x07, | |
2342 'h', 'e', 'l', 'l', 'o', '!', | |
2343 }; | |
2344 | |
2345 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2346 MockRead reads[] = { | |
2347 CreateMockRead(*resp, 2), | |
2348 MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause | |
2349 MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2), | |
2350 arraysize(kGetBodyFrame2), 4), | |
2351 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause | |
2352 MockRead(ASYNC, 0, 0, 6), // EOF | |
2353 }; | |
2354 MockRead reads2[] = { | |
2355 CreateMockRead(*resp, 2), | |
2356 MockRead(ASYNC, 0, 0, 3), // EOF | |
2357 }; | |
2358 | |
2359 OrderedSocketData data(reads, arraysize(reads), | |
2360 writes, arraysize(writes)); | |
2361 DelayedSocketData data2(1, reads2, arraysize(reads2), | |
2362 writes2, arraysize(writes2)); | |
2363 | |
2364 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
2365 BoundNetLog(), GetParam(), NULL); | |
2366 helper.RunPreTestSetup(); | |
2367 helper.AddData(&data); | |
2368 helper.AddData(&data2); | |
2369 HttpNetworkTransaction* trans = helper.trans(); | |
2370 | |
2371 // Start the transaction with basic parameters. | |
2372 TestCompletionCallback callback; | |
2373 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2374 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2375 rv = callback.WaitForResult(); | |
2376 | |
2377 const int kSize = 3000; | |
2378 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); | |
2379 rv = trans->Read( | |
2380 buf.get(), | |
2381 kSize, | |
2382 base::Bind(&SpdyNetworkTransactionTest::StartTransactionCallback, | |
2383 helper.session())); | |
2384 // This forces an err_IO_pending, which sets the callback. | |
2385 data.CompleteRead(); | |
2386 // This finishes the read. | |
2387 data.CompleteRead(); | |
2388 helper.VerifyDataConsumed(); | |
2389 } | |
2390 | |
2391 // Verify that the client can correctly deal with the user callback deleting the | |
2392 // transaction. Failures will usually be valgrind errors. See | |
2393 // http://crbug.com/46925 | |
2394 TEST_P(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) { | |
2395 scoped_ptr<SpdyFrame> req( | |
2396 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2397 MockWrite writes[] = { CreateMockWrite(*req) }; | |
2398 | |
2399 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2400 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2401 MockRead reads[] = { | |
2402 CreateMockRead(*resp.get(), 2), | |
2403 MockRead(ASYNC, ERR_IO_PENDING, 3), // Force a pause | |
2404 CreateMockRead(*body.get(), 4), | |
2405 MockRead(ASYNC, 0, 0, 5), // EOF | |
2406 }; | |
2407 | |
2408 OrderedSocketData data(reads, arraysize(reads), | |
2409 writes, arraysize(writes)); | |
2410 | |
2411 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
2412 BoundNetLog(), GetParam(), NULL); | |
2413 helper.RunPreTestSetup(); | |
2414 helper.AddData(&data); | |
2415 HttpNetworkTransaction* trans = helper.trans(); | |
2416 | |
2417 // Start the transaction with basic parameters. | |
2418 TestCompletionCallback callback; | |
2419 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
2420 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2421 rv = callback.WaitForResult(); | |
2422 | |
2423 // Setup a user callback which will delete the session, and clear out the | |
2424 // memory holding the stream object. Note that the callback deletes trans. | |
2425 const int kSize = 3000; | |
2426 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSize)); | |
2427 rv = trans->Read( | |
2428 buf.get(), | |
2429 kSize, | |
2430 base::Bind(&SpdyNetworkTransactionTest::DeleteSessionCallback, | |
2431 base::Unretained(&helper))); | |
2432 ASSERT_EQ(ERR_IO_PENDING, rv); | |
2433 data.CompleteRead(); | |
2434 | |
2435 // Finish running rest of tasks. | |
2436 base::RunLoop().RunUntilIdle(); | |
2437 helper.VerifyDataConsumed(); | |
2438 } | |
2439 | |
2440 // Send a spdy request to www.google.com that gets redirected to www.foo.com. | |
2441 TEST_P(SpdyNetworkTransactionTest, RedirectGetRequest) { | |
2442 scoped_ptr<SpdyHeaderBlock> headers( | |
2443 spdy_util_.ConstructGetHeaderBlock("http://www.google.com/")); | |
2444 (*headers)["user-agent"] = ""; | |
2445 (*headers)["accept-encoding"] = "gzip, deflate"; | |
2446 scoped_ptr<SpdyHeaderBlock> headers2( | |
2447 spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php")); | |
2448 (*headers2)["user-agent"] = ""; | |
2449 (*headers2)["accept-encoding"] = "gzip, deflate"; | |
2450 | |
2451 // Setup writes/reads to www.google.com | |
2452 scoped_ptr<SpdyFrame> req( | |
2453 spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true)); | |
2454 scoped_ptr<SpdyFrame> req2( | |
2455 spdy_util_.ConstructSpdySyn(1, *headers2, LOWEST, false, true)); | |
2456 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReplyRedirect(1)); | |
2457 MockWrite writes[] = { | |
2458 CreateMockWrite(*req, 1), | |
2459 }; | |
2460 MockRead reads[] = { | |
2461 CreateMockRead(*resp, 2), | |
2462 MockRead(ASYNC, 0, 0, 3) // EOF | |
2463 }; | |
2464 | |
2465 // Setup writes/reads to www.foo.com | |
2466 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2467 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2468 MockWrite writes2[] = { | |
2469 CreateMockWrite(*req2, 1), | |
2470 }; | |
2471 MockRead reads2[] = { | |
2472 CreateMockRead(*resp2, 2), | |
2473 CreateMockRead(*body2, 3), | |
2474 MockRead(ASYNC, 0, 0, 4) // EOF | |
2475 }; | |
2476 OrderedSocketData data(reads, arraysize(reads), | |
2477 writes, arraysize(writes)); | |
2478 OrderedSocketData data2(reads2, arraysize(reads2), | |
2479 writes2, arraysize(writes2)); | |
2480 | |
2481 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN | |
2482 TestDelegate d; | |
2483 { | |
2484 SpdyURLRequestContext spdy_url_request_context( | |
2485 GetParam().protocol, | |
2486 false /* force_spdy_over_ssl*/, | |
2487 true /* force_spdy_always */); | |
2488 scoped_ptr<URLRequest> r( | |
2489 spdy_url_request_context.CreateRequest(GURL("http://www.google.com/"), | |
2490 DEFAULT_PRIORITY, | |
2491 &d, | |
2492 NULL)); | |
2493 spdy_url_request_context.socket_factory(). | |
2494 AddSocketDataProvider(&data); | |
2495 spdy_url_request_context.socket_factory(). | |
2496 AddSocketDataProvider(&data2); | |
2497 | |
2498 d.set_quit_on_redirect(true); | |
2499 r->Start(); | |
2500 base::RunLoop().Run(); | |
2501 | |
2502 EXPECT_EQ(1, d.received_redirect_count()); | |
2503 | |
2504 r->FollowDeferredRedirect(); | |
2505 base::RunLoop().Run(); | |
2506 EXPECT_EQ(1, d.response_started_count()); | |
2507 EXPECT_FALSE(d.received_data_before_response()); | |
2508 EXPECT_EQ(net::URLRequestStatus::SUCCESS, r->status().status()); | |
2509 std::string contents("hello!"); | |
2510 EXPECT_EQ(contents, d.data_received()); | |
2511 } | |
2512 EXPECT_TRUE(data.at_read_eof()); | |
2513 EXPECT_TRUE(data.at_write_eof()); | |
2514 EXPECT_TRUE(data2.at_read_eof()); | |
2515 EXPECT_TRUE(data2.at_write_eof()); | |
2516 } | |
2517 | |
2518 // Send a spdy request to www.google.com. Get a pushed stream that redirects to | |
2519 // www.foo.com. | |
2520 TEST_P(SpdyNetworkTransactionTest, RedirectServerPush) { | |
2521 scoped_ptr<SpdyHeaderBlock> headers( | |
2522 spdy_util_.ConstructGetHeaderBlock("http://www.google.com/")); | |
2523 (*headers)["user-agent"] = ""; | |
2524 (*headers)["accept-encoding"] = "gzip, deflate"; | |
2525 | |
2526 // Setup writes/reads to www.google.com | |
2527 scoped_ptr<SpdyFrame> req( | |
2528 spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true)); | |
2529 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2530 scoped_ptr<SpdyFrame> rep( | |
2531 spdy_util_.ConstructSpdyPush(NULL, | |
2532 0, | |
2533 2, | |
2534 1, | |
2535 "http://www.google.com/foo.dat", | |
2536 "301 Moved Permanently", | |
2537 "http://www.foo.com/index.php")); | |
2538 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2539 scoped_ptr<SpdyFrame> rst( | |
2540 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL)); | |
2541 MockWrite writes[] = { | |
2542 CreateMockWrite(*req, 1), | |
2543 CreateMockWrite(*rst, 6), | |
2544 }; | |
2545 MockRead reads[] = { | |
2546 CreateMockRead(*resp, 2), | |
2547 CreateMockRead(*rep, 3), | |
2548 CreateMockRead(*body, 4), | |
2549 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause | |
2550 MockRead(ASYNC, 0, 0, 7) // EOF | |
2551 }; | |
2552 | |
2553 // Setup writes/reads to www.foo.com | |
2554 scoped_ptr<SpdyHeaderBlock> headers2( | |
2555 spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php")); | |
2556 (*headers2)["user-agent"] = ""; | |
2557 (*headers2)["accept-encoding"] = "gzip, deflate"; | |
2558 scoped_ptr<SpdyFrame> req2( | |
2559 spdy_util_.ConstructSpdySyn(1, *headers2, LOWEST, false, true)); | |
2560 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2561 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2562 MockWrite writes2[] = { | |
2563 CreateMockWrite(*req2, 1), | |
2564 }; | |
2565 MockRead reads2[] = { | |
2566 CreateMockRead(*resp2, 2), | |
2567 CreateMockRead(*body2, 3), | |
2568 MockRead(ASYNC, 0, 0, 5) // EOF | |
2569 }; | |
2570 OrderedSocketData data(reads, arraysize(reads), | |
2571 writes, arraysize(writes)); | |
2572 OrderedSocketData data2(reads2, arraysize(reads2), | |
2573 writes2, arraysize(writes2)); | |
2574 | |
2575 // TODO(erikchen): Make test support SPDYSSL, SPDYNPN | |
2576 TestDelegate d; | |
2577 TestDelegate d2; | |
2578 SpdyURLRequestContext spdy_url_request_context( | |
2579 GetParam().protocol, | |
2580 false /* force_spdy_over_ssl*/, | |
2581 true /* force_spdy_always */); | |
2582 { | |
2583 scoped_ptr<URLRequest> r( | |
2584 spdy_url_request_context.CreateRequest(GURL("http://www.google.com/"), | |
2585 DEFAULT_PRIORITY, | |
2586 &d, | |
2587 NULL)); | |
2588 spdy_url_request_context.socket_factory(). | |
2589 AddSocketDataProvider(&data); | |
2590 | |
2591 r->Start(); | |
2592 base::RunLoop().Run(); | |
2593 | |
2594 EXPECT_EQ(0, d.received_redirect_count()); | |
2595 std::string contents("hello!"); | |
2596 EXPECT_EQ(contents, d.data_received()); | |
2597 | |
2598 scoped_ptr<URLRequest> r2( | |
2599 spdy_url_request_context.CreateRequest( | |
2600 GURL("http://www.google.com/foo.dat"), | |
2601 DEFAULT_PRIORITY, | |
2602 &d2, | |
2603 NULL)); | |
2604 spdy_url_request_context.socket_factory(). | |
2605 AddSocketDataProvider(&data2); | |
2606 | |
2607 d2.set_quit_on_redirect(true); | |
2608 r2->Start(); | |
2609 base::RunLoop().Run(); | |
2610 EXPECT_EQ(1, d2.received_redirect_count()); | |
2611 | |
2612 r2->FollowDeferredRedirect(); | |
2613 base::RunLoop().Run(); | |
2614 EXPECT_EQ(1, d2.response_started_count()); | |
2615 EXPECT_FALSE(d2.received_data_before_response()); | |
2616 EXPECT_EQ(net::URLRequestStatus::SUCCESS, r2->status().status()); | |
2617 std::string contents2("hello!"); | |
2618 EXPECT_EQ(contents2, d2.data_received()); | |
2619 } | |
2620 data.CompleteRead(); | |
2621 data2.CompleteRead(); | |
2622 EXPECT_TRUE(data.at_read_eof()); | |
2623 EXPECT_TRUE(data.at_write_eof()); | |
2624 EXPECT_TRUE(data2.at_read_eof()); | |
2625 EXPECT_TRUE(data2.at_write_eof()); | |
2626 } | |
2627 | |
2628 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) { | |
2629 scoped_ptr<SpdyFrame> stream1_syn( | |
2630 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2631 scoped_ptr<SpdyFrame> stream1_body( | |
2632 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2633 MockWrite writes[] = { | |
2634 CreateMockWrite(*stream1_syn, 1), | |
2635 }; | |
2636 | |
2637 scoped_ptr<SpdyFrame> | |
2638 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2639 scoped_ptr<SpdyFrame> | |
2640 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
2641 0, | |
2642 2, | |
2643 1, | |
2644 "http://www.google.com/foo.dat")); | |
2645 const char kPushedData[] = "pushed"; | |
2646 scoped_ptr<SpdyFrame> stream2_body( | |
2647 spdy_util_.ConstructSpdyBodyFrame( | |
2648 2, kPushedData, strlen(kPushedData), true)); | |
2649 MockRead reads[] = { | |
2650 CreateMockRead(*stream1_reply, 2), | |
2651 CreateMockRead(*stream2_syn, 3), | |
2652 CreateMockRead(*stream1_body, 4, SYNCHRONOUS), | |
2653 CreateMockRead(*stream2_body, 5), | |
2654 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause | |
2655 }; | |
2656 | |
2657 HttpResponseInfo response; | |
2658 HttpResponseInfo response2; | |
2659 std::string expected_push_result("pushed"); | |
2660 OrderedSocketData data(reads, arraysize(reads), | |
2661 writes, arraysize(writes)); | |
2662 RunServerPushTest(&data, | |
2663 &response, | |
2664 &response2, | |
2665 expected_push_result); | |
2666 | |
2667 // Verify the SYN_REPLY. | |
2668 EXPECT_TRUE(response.headers.get() != NULL); | |
2669 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
2670 | |
2671 // Verify the pushed stream. | |
2672 EXPECT_TRUE(response2.headers.get() != NULL); | |
2673 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
2674 } | |
2675 | |
2676 TEST_P(SpdyNetworkTransactionTest, ServerPushBeforeSynReply) { | |
2677 scoped_ptr<SpdyFrame> stream1_syn( | |
2678 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2679 scoped_ptr<SpdyFrame> stream1_body( | |
2680 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2681 MockWrite writes[] = { | |
2682 CreateMockWrite(*stream1_syn, 1), | |
2683 }; | |
2684 | |
2685 scoped_ptr<SpdyFrame> | |
2686 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2687 scoped_ptr<SpdyFrame> | |
2688 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
2689 0, | |
2690 2, | |
2691 1, | |
2692 "http://www.google.com/foo.dat")); | |
2693 const char kPushedData[] = "pushed"; | |
2694 scoped_ptr<SpdyFrame> stream2_body( | |
2695 spdy_util_.ConstructSpdyBodyFrame( | |
2696 2, kPushedData, strlen(kPushedData), true)); | |
2697 MockRead reads[] = { | |
2698 CreateMockRead(*stream2_syn, 2), | |
2699 CreateMockRead(*stream1_reply, 3), | |
2700 CreateMockRead(*stream1_body, 4, SYNCHRONOUS), | |
2701 CreateMockRead(*stream2_body, 5), | |
2702 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause | |
2703 }; | |
2704 | |
2705 HttpResponseInfo response; | |
2706 HttpResponseInfo response2; | |
2707 std::string expected_push_result("pushed"); | |
2708 OrderedSocketData data(reads, arraysize(reads), | |
2709 writes, arraysize(writes)); | |
2710 RunServerPushTest(&data, | |
2711 &response, | |
2712 &response2, | |
2713 expected_push_result); | |
2714 | |
2715 // Verify the SYN_REPLY. | |
2716 EXPECT_TRUE(response.headers.get() != NULL); | |
2717 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
2718 | |
2719 // Verify the pushed stream. | |
2720 EXPECT_TRUE(response2.headers.get() != NULL); | |
2721 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
2722 } | |
2723 | |
2724 TEST_P(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) { | |
2725 scoped_ptr<SpdyFrame> stream1_syn( | |
2726 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2727 MockWrite writes[] = { CreateMockWrite(*stream1_syn, 1), }; | |
2728 | |
2729 scoped_ptr<SpdyFrame> | |
2730 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2731 scoped_ptr<SpdyFrame> | |
2732 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
2733 0, | |
2734 2, | |
2735 1, | |
2736 "http://www.google.com/foo.dat")); | |
2737 const char kPushedData[] = "pushed"; | |
2738 scoped_ptr<SpdyFrame> stream2_body( | |
2739 spdy_util_.ConstructSpdyBodyFrame( | |
2740 2, kPushedData, strlen(kPushedData), true)); | |
2741 scoped_ptr<SpdyFrame> | |
2742 stream1_body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2743 MockRead reads[] = { | |
2744 CreateMockRead(*stream1_reply, 2), | |
2745 CreateMockRead(*stream2_syn, 3), | |
2746 CreateMockRead(*stream2_body, 4), | |
2747 CreateMockRead(*stream1_body, 5, SYNCHRONOUS), | |
2748 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause | |
2749 }; | |
2750 | |
2751 HttpResponseInfo response; | |
2752 HttpResponseInfo response2; | |
2753 std::string expected_push_result("pushed"); | |
2754 OrderedSocketData data(reads, arraysize(reads), | |
2755 writes, arraysize(writes)); | |
2756 RunServerPushTest(&data, | |
2757 &response, | |
2758 &response2, | |
2759 expected_push_result); | |
2760 | |
2761 // Verify the SYN_REPLY. | |
2762 EXPECT_TRUE(response.headers.get() != NULL); | |
2763 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
2764 | |
2765 // Verify the pushed stream. | |
2766 EXPECT_TRUE(response2.headers.get() != NULL); | |
2767 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
2768 } | |
2769 | |
2770 TEST_P(SpdyNetworkTransactionTest, ServerPushServerAborted) { | |
2771 scoped_ptr<SpdyFrame> stream1_syn( | |
2772 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2773 scoped_ptr<SpdyFrame> stream1_body( | |
2774 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2775 MockWrite writes[] = { | |
2776 CreateMockWrite(*stream1_syn, 1), | |
2777 }; | |
2778 | |
2779 scoped_ptr<SpdyFrame> | |
2780 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2781 scoped_ptr<SpdyFrame> | |
2782 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
2783 0, | |
2784 2, | |
2785 1, | |
2786 "http://www.google.com/foo.dat")); | |
2787 scoped_ptr<SpdyFrame> stream2_rst( | |
2788 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR)); | |
2789 MockRead reads[] = { | |
2790 CreateMockRead(*stream1_reply, 2), | |
2791 CreateMockRead(*stream2_syn, 3), | |
2792 CreateMockRead(*stream2_rst, 4), | |
2793 CreateMockRead(*stream1_body, 5, SYNCHRONOUS), | |
2794 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause | |
2795 }; | |
2796 | |
2797 OrderedSocketData data(reads, arraysize(reads), | |
2798 writes, arraysize(writes)); | |
2799 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
2800 BoundNetLog(), GetParam(), NULL); | |
2801 | |
2802 helper.RunPreTestSetup(); | |
2803 helper.AddData(&data); | |
2804 | |
2805 HttpNetworkTransaction* trans = helper.trans(); | |
2806 | |
2807 // Start the transaction with basic parameters. | |
2808 TestCompletionCallback callback; | |
2809 int rv = trans->Start( | |
2810 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
2811 EXPECT_EQ(ERR_IO_PENDING, rv); | |
2812 rv = callback.WaitForResult(); | |
2813 EXPECT_EQ(OK, rv); | |
2814 | |
2815 // Verify that we consumed all test data. | |
2816 EXPECT_TRUE(data.at_read_eof()) << "Read count: " | |
2817 << data.read_count() | |
2818 << " Read index: " | |
2819 << data.read_index(); | |
2820 EXPECT_TRUE(data.at_write_eof()) << "Write count: " | |
2821 << data.write_count() | |
2822 << " Write index: " | |
2823 << data.write_index(); | |
2824 | |
2825 // Verify the SYN_REPLY. | |
2826 HttpResponseInfo response = *trans->GetResponseInfo(); | |
2827 EXPECT_TRUE(response.headers.get() != NULL); | |
2828 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
2829 } | |
2830 | |
2831 // Verify that we don't leak streams and that we properly send a reset | |
2832 // if the server pushes the same stream twice. | |
2833 TEST_P(SpdyNetworkTransactionTest, ServerPushDuplicate) { | |
2834 scoped_ptr<SpdyFrame> stream1_syn( | |
2835 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2836 scoped_ptr<SpdyFrame> stream1_body( | |
2837 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2838 scoped_ptr<SpdyFrame> stream3_rst( | |
2839 spdy_util_.ConstructSpdyRstStream(4, RST_STREAM_PROTOCOL_ERROR)); | |
2840 MockWrite writes[] = { | |
2841 CreateMockWrite(*stream1_syn, 1), | |
2842 CreateMockWrite(*stream3_rst, 5), | |
2843 }; | |
2844 | |
2845 scoped_ptr<SpdyFrame> | |
2846 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2847 scoped_ptr<SpdyFrame> | |
2848 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
2849 0, | |
2850 2, | |
2851 1, | |
2852 "http://www.google.com/foo.dat")); | |
2853 const char kPushedData[] = "pushed"; | |
2854 scoped_ptr<SpdyFrame> stream2_body( | |
2855 spdy_util_.ConstructSpdyBodyFrame( | |
2856 2, kPushedData, strlen(kPushedData), true)); | |
2857 scoped_ptr<SpdyFrame> | |
2858 stream3_syn(spdy_util_.ConstructSpdyPush(NULL, | |
2859 0, | |
2860 4, | |
2861 1, | |
2862 "http://www.google.com/foo.dat")); | |
2863 MockRead reads[] = { | |
2864 CreateMockRead(*stream1_reply, 2), | |
2865 CreateMockRead(*stream2_syn, 3), | |
2866 CreateMockRead(*stream3_syn, 4), | |
2867 CreateMockRead(*stream1_body, 6, SYNCHRONOUS), | |
2868 CreateMockRead(*stream2_body, 7), | |
2869 MockRead(ASYNC, ERR_IO_PENDING, 8), // Force a pause | |
2870 }; | |
2871 | |
2872 HttpResponseInfo response; | |
2873 HttpResponseInfo response2; | |
2874 std::string expected_push_result("pushed"); | |
2875 OrderedSocketData data(reads, arraysize(reads), | |
2876 writes, arraysize(writes)); | |
2877 RunServerPushTest(&data, | |
2878 &response, | |
2879 &response2, | |
2880 expected_push_result); | |
2881 | |
2882 // Verify the SYN_REPLY. | |
2883 EXPECT_TRUE(response.headers.get() != NULL); | |
2884 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
2885 | |
2886 // Verify the pushed stream. | |
2887 EXPECT_TRUE(response2.headers.get() != NULL); | |
2888 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
2889 } | |
2890 | |
2891 TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) { | |
2892 scoped_ptr<SpdyFrame> stream1_syn( | |
2893 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2894 scoped_ptr<SpdyFrame> stream1_body( | |
2895 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2896 MockWrite writes[] = { | |
2897 CreateMockWrite(*stream1_syn, 1), | |
2898 }; | |
2899 | |
2900 scoped_ptr<SpdyFrame> | |
2901 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2902 scoped_ptr<SpdyFrame> | |
2903 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
2904 0, | |
2905 2, | |
2906 1, | |
2907 "http://www.google.com/foo.dat")); | |
2908 static const char kPushedData[] = "pushed my darling hello my baby"; | |
2909 scoped_ptr<SpdyFrame> stream2_body_base( | |
2910 spdy_util_.ConstructSpdyBodyFrame( | |
2911 2, kPushedData, strlen(kPushedData), true)); | |
2912 const size_t kChunkSize = strlen(kPushedData) / 4; | |
2913 scoped_ptr<SpdyFrame> stream2_body1( | |
2914 new SpdyFrame(stream2_body_base->data(), kChunkSize, false)); | |
2915 scoped_ptr<SpdyFrame> stream2_body2( | |
2916 new SpdyFrame(stream2_body_base->data() + kChunkSize, kChunkSize, false)); | |
2917 scoped_ptr<SpdyFrame> stream2_body3( | |
2918 new SpdyFrame(stream2_body_base->data() + 2 * kChunkSize, | |
2919 kChunkSize, false)); | |
2920 scoped_ptr<SpdyFrame> stream2_body4( | |
2921 new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize, | |
2922 stream2_body_base->size() - 3 * kChunkSize, false)); | |
2923 MockRead reads[] = { | |
2924 CreateMockRead(*stream1_reply, 2), | |
2925 CreateMockRead(*stream2_syn, 3), | |
2926 CreateMockRead(*stream2_body1, 4), | |
2927 CreateMockRead(*stream2_body2, 5), | |
2928 CreateMockRead(*stream2_body3, 6), | |
2929 CreateMockRead(*stream2_body4, 7), | |
2930 CreateMockRead(*stream1_body, 8, SYNCHRONOUS), | |
2931 MockRead(ASYNC, ERR_IO_PENDING, 9), // Force a pause | |
2932 }; | |
2933 | |
2934 HttpResponseInfo response; | |
2935 HttpResponseInfo response2; | |
2936 std::string expected_push_result("pushed my darling hello my baby"); | |
2937 OrderedSocketData data(reads, arraysize(reads), | |
2938 writes, arraysize(writes)); | |
2939 RunServerPushTest(&data, &response, &response2, kPushedData); | |
2940 | |
2941 // Verify the SYN_REPLY. | |
2942 EXPECT_TRUE(response.headers.get() != NULL); | |
2943 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
2944 | |
2945 // Verify the pushed stream. | |
2946 EXPECT_TRUE(response2.headers.get() != NULL); | |
2947 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
2948 } | |
2949 | |
2950 TEST_P(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) { | |
2951 scoped_ptr<SpdyFrame> stream1_syn( | |
2952 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
2953 scoped_ptr<SpdyFrame> stream1_body( | |
2954 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
2955 MockWrite writes[] = { | |
2956 CreateMockWrite(*stream1_syn, 1), | |
2957 }; | |
2958 | |
2959 scoped_ptr<SpdyFrame> | |
2960 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
2961 scoped_ptr<SpdyFrame> | |
2962 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
2963 0, | |
2964 2, | |
2965 1, | |
2966 "http://www.google.com/foo.dat")); | |
2967 static const char kPushedData[] = "pushed my darling hello my baby"; | |
2968 scoped_ptr<SpdyFrame> stream2_body_base( | |
2969 spdy_util_.ConstructSpdyBodyFrame( | |
2970 2, kPushedData, strlen(kPushedData), true)); | |
2971 const size_t kChunkSize = strlen(kPushedData) / 4; | |
2972 scoped_ptr<SpdyFrame> stream2_body1( | |
2973 new SpdyFrame(stream2_body_base->data(), kChunkSize, false)); | |
2974 scoped_ptr<SpdyFrame> stream2_body2( | |
2975 new SpdyFrame(stream2_body_base->data() + kChunkSize, kChunkSize, false)); | |
2976 scoped_ptr<SpdyFrame> stream2_body3( | |
2977 new SpdyFrame(stream2_body_base->data() + 2 * kChunkSize, | |
2978 kChunkSize, false)); | |
2979 scoped_ptr<SpdyFrame> stream2_body4( | |
2980 new SpdyFrame(stream2_body_base->data() + 3 * kChunkSize, | |
2981 stream2_body_base->size() - 3 * kChunkSize, false)); | |
2982 MockRead reads[] = { | |
2983 CreateMockRead(*stream1_reply, 2), | |
2984 CreateMockRead(*stream2_syn, 3), | |
2985 CreateMockRead(*stream2_body1, 4), | |
2986 CreateMockRead(*stream2_body2, 5), | |
2987 MockRead(ASYNC, ERR_IO_PENDING, 6), // Force a pause | |
2988 CreateMockRead(*stream2_body3, 7), | |
2989 CreateMockRead(*stream2_body4, 8), | |
2990 CreateMockRead(*stream1_body.get(), 9, SYNCHRONOUS), | |
2991 MockRead(ASYNC, ERR_IO_PENDING, 10) // Force a pause. | |
2992 }; | |
2993 | |
2994 HttpResponseInfo response; | |
2995 HttpResponseInfo response2; | |
2996 OrderedSocketData data(reads, arraysize(reads), | |
2997 writes, arraysize(writes)); | |
2998 RunServerPushTest(&data, &response, &response2, kPushedData); | |
2999 | |
3000 // Verify the SYN_REPLY. | |
3001 EXPECT_TRUE(response.headers.get() != NULL); | |
3002 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
3003 | |
3004 // Verify the pushed stream. | |
3005 EXPECT_TRUE(response2.headers.get() != NULL); | |
3006 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
3007 } | |
3008 | |
3009 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) { | |
3010 if (spdy_util_.spdy_version() == SPDY4) { | |
3011 // PUSH_PROMISE with stream id 0 is connection-level error. | |
3012 // TODO(baranovich): Test session going away. | |
3013 return; | |
3014 } | |
3015 | |
3016 scoped_ptr<SpdyFrame> stream1_syn( | |
3017 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3018 scoped_ptr<SpdyFrame> stream1_body( | |
3019 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
3020 scoped_ptr<SpdyFrame> stream2_rst( | |
3021 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM)); | |
3022 MockWrite writes[] = { | |
3023 CreateMockWrite(*stream1_syn, 1), | |
3024 CreateMockWrite(*stream2_rst, 4), | |
3025 }; | |
3026 | |
3027 scoped_ptr<SpdyFrame> | |
3028 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3029 scoped_ptr<SpdyFrame> | |
3030 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
3031 0, | |
3032 2, | |
3033 0, | |
3034 "http://www.google.com/foo.dat")); | |
3035 MockRead reads[] = { | |
3036 CreateMockRead(*stream1_reply, 2), | |
3037 CreateMockRead(*stream2_syn, 3), | |
3038 CreateMockRead(*stream1_body, 4), | |
3039 MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause | |
3040 }; | |
3041 | |
3042 OrderedSocketData data(reads, arraysize(reads), | |
3043 writes, arraysize(writes)); | |
3044 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3045 BoundNetLog(), GetParam(), NULL); | |
3046 | |
3047 helper.RunPreTestSetup(); | |
3048 helper.AddData(&data); | |
3049 | |
3050 HttpNetworkTransaction* trans = helper.trans(); | |
3051 | |
3052 // Start the transaction with basic parameters. | |
3053 TestCompletionCallback callback; | |
3054 int rv = trans->Start( | |
3055 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
3056 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3057 rv = callback.WaitForResult(); | |
3058 EXPECT_EQ(OK, rv); | |
3059 | |
3060 // Verify that we consumed all test data. | |
3061 EXPECT_TRUE(data.at_read_eof()) << "Read count: " | |
3062 << data.read_count() | |
3063 << " Read index: " | |
3064 << data.read_index(); | |
3065 EXPECT_TRUE(data.at_write_eof()) << "Write count: " | |
3066 << data.write_count() | |
3067 << " Write index: " | |
3068 << data.write_index(); | |
3069 | |
3070 // Verify the SYN_REPLY. | |
3071 HttpResponseInfo response = *trans->GetResponseInfo(); | |
3072 EXPECT_TRUE(response.headers.get() != NULL); | |
3073 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
3074 } | |
3075 | |
3076 TEST_P(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) { | |
3077 scoped_ptr<SpdyFrame> stream1_syn( | |
3078 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3079 scoped_ptr<SpdyFrame> stream1_body( | |
3080 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
3081 scoped_ptr<SpdyFrame> stream2_rst( | |
3082 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_INVALID_STREAM)); | |
3083 MockWrite writes[] = { | |
3084 CreateMockWrite(*stream1_syn, 1), | |
3085 CreateMockWrite(*stream2_rst, 4), | |
3086 }; | |
3087 | |
3088 scoped_ptr<SpdyFrame> | |
3089 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3090 scoped_ptr<SpdyFrame> | |
3091 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
3092 0, | |
3093 2, | |
3094 9, | |
3095 "http://www.google.com/foo.dat")); | |
3096 MockRead reads[] = { | |
3097 CreateMockRead(*stream1_reply, 2), | |
3098 CreateMockRead(*stream2_syn, 3), | |
3099 CreateMockRead(*stream1_body, 4), | |
3100 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause | |
3101 }; | |
3102 | |
3103 OrderedSocketData data(reads, arraysize(reads), | |
3104 writes, arraysize(writes)); | |
3105 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3106 BoundNetLog(), GetParam(), NULL); | |
3107 | |
3108 helper.RunPreTestSetup(); | |
3109 helper.AddData(&data); | |
3110 | |
3111 HttpNetworkTransaction* trans = helper.trans(); | |
3112 | |
3113 // Start the transaction with basic parameters. | |
3114 TestCompletionCallback callback; | |
3115 int rv = trans->Start( | |
3116 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
3117 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3118 rv = callback.WaitForResult(); | |
3119 EXPECT_EQ(OK, rv); | |
3120 | |
3121 // Verify that we consumed all test data. | |
3122 EXPECT_TRUE(data.at_read_eof()) << "Read count: " | |
3123 << data.read_count() | |
3124 << " Read index: " | |
3125 << data.read_index(); | |
3126 EXPECT_TRUE(data.at_write_eof()) << "Write count: " | |
3127 << data.write_count() | |
3128 << " Write index: " | |
3129 << data.write_index(); | |
3130 | |
3131 // Verify the SYN_REPLY. | |
3132 HttpResponseInfo response = *trans->GetResponseInfo(); | |
3133 EXPECT_TRUE(response.headers.get() != NULL); | |
3134 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
3135 } | |
3136 | |
3137 TEST_P(SpdyNetworkTransactionTest, ServerPushNoURL) { | |
3138 scoped_ptr<SpdyFrame> stream1_syn( | |
3139 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3140 scoped_ptr<SpdyFrame> stream1_body( | |
3141 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
3142 scoped_ptr<SpdyFrame> stream2_rst( | |
3143 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_PROTOCOL_ERROR)); | |
3144 MockWrite writes[] = { | |
3145 CreateMockWrite(*stream1_syn, 1), | |
3146 CreateMockWrite(*stream2_rst, 4), | |
3147 }; | |
3148 | |
3149 scoped_ptr<SpdyFrame> | |
3150 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3151 scoped_ptr<SpdyHeaderBlock> incomplete_headers(new SpdyHeaderBlock()); | |
3152 (*incomplete_headers)["hello"] = "bye"; | |
3153 (*incomplete_headers)[spdy_util_.GetStatusKey()] = "200 OK"; | |
3154 (*incomplete_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1"; | |
3155 scoped_ptr<SpdyFrame> stream2_syn(spdy_util_.ConstructInitialSpdyPushFrame( | |
3156 incomplete_headers.Pass(), 2, 1)); | |
3157 MockRead reads[] = { | |
3158 CreateMockRead(*stream1_reply, 2), | |
3159 CreateMockRead(*stream2_syn, 3), | |
3160 CreateMockRead(*stream1_body, 4), | |
3161 MockRead(ASYNC, ERR_IO_PENDING, 5) // Force a pause | |
3162 }; | |
3163 | |
3164 OrderedSocketData data(reads, arraysize(reads), | |
3165 writes, arraysize(writes)); | |
3166 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3167 BoundNetLog(), GetParam(), NULL); | |
3168 | |
3169 helper.RunPreTestSetup(); | |
3170 helper.AddData(&data); | |
3171 | |
3172 HttpNetworkTransaction* trans = helper.trans(); | |
3173 | |
3174 // Start the transaction with basic parameters. | |
3175 TestCompletionCallback callback; | |
3176 int rv = trans->Start( | |
3177 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
3178 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3179 rv = callback.WaitForResult(); | |
3180 EXPECT_EQ(OK, rv); | |
3181 // Verify that we consumed all test data. | |
3182 EXPECT_TRUE(data.at_read_eof()) << "Read count: " | |
3183 << data.read_count() | |
3184 << " Read index: " | |
3185 << data.read_index(); | |
3186 EXPECT_TRUE(data.at_write_eof()) << "Write count: " | |
3187 << data.write_count() | |
3188 << " Write index: " | |
3189 << data.write_index(); | |
3190 | |
3191 // Verify the SYN_REPLY. | |
3192 HttpResponseInfo response = *trans->GetResponseInfo(); | |
3193 EXPECT_TRUE(response.headers.get() != NULL); | |
3194 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
3195 } | |
3196 | |
3197 // Verify that various SynReply headers parse correctly through the | |
3198 // HTTP layer. | |
3199 TEST_P(SpdyNetworkTransactionTest, SynReplyHeaders) { | |
3200 struct SynReplyHeadersTests { | |
3201 int num_headers; | |
3202 const char* extra_headers[5]; | |
3203 SpdyHeaderBlock expected_headers; | |
3204 } test_cases[] = { | |
3205 // This uses a multi-valued cookie header. | |
3206 { 2, | |
3207 { "cookie", "val1", | |
3208 "cookie", "val2", // will get appended separated by NULL | |
3209 NULL | |
3210 }, | |
3211 }, | |
3212 // This is the minimalist set of headers. | |
3213 { 0, | |
3214 { NULL }, | |
3215 }, | |
3216 // Headers with a comma separated list. | |
3217 { 1, | |
3218 { "cookie", "val1,val2", | |
3219 NULL | |
3220 }, | |
3221 } | |
3222 }; | |
3223 | |
3224 test_cases[0].expected_headers["cookie"] = "val1"; | |
3225 test_cases[0].expected_headers["cookie"] += '\0'; | |
3226 test_cases[0].expected_headers["cookie"] += "val2"; | |
3227 test_cases[0].expected_headers["hello"] = "bye"; | |
3228 test_cases[0].expected_headers["status"] = "200"; | |
3229 | |
3230 test_cases[1].expected_headers["hello"] = "bye"; | |
3231 test_cases[1].expected_headers["status"] = "200"; | |
3232 | |
3233 test_cases[2].expected_headers["cookie"] = "val1,val2"; | |
3234 test_cases[2].expected_headers["hello"] = "bye"; | |
3235 test_cases[2].expected_headers["status"] = "200"; | |
3236 | |
3237 if (spdy_util_.spdy_version() < SPDY4) { | |
3238 // SPDY4/HTTP2 eliminates use of the :version header. | |
3239 test_cases[0].expected_headers["version"] = "HTTP/1.1"; | |
3240 test_cases[1].expected_headers["version"] = "HTTP/1.1"; | |
3241 test_cases[2].expected_headers["version"] = "HTTP/1.1"; | |
3242 } | |
3243 | |
3244 for (size_t i = 0; i < arraysize(test_cases); ++i) { | |
3245 scoped_ptr<SpdyFrame> req( | |
3246 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3247 MockWrite writes[] = { CreateMockWrite(*req) }; | |
3248 | |
3249 scoped_ptr<SpdyFrame> resp( | |
3250 spdy_util_.ConstructSpdyGetSynReply(test_cases[i].extra_headers, | |
3251 test_cases[i].num_headers, | |
3252 1)); | |
3253 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
3254 MockRead reads[] = { | |
3255 CreateMockRead(*resp), | |
3256 CreateMockRead(*body), | |
3257 MockRead(ASYNC, 0, 0) // EOF | |
3258 }; | |
3259 | |
3260 DelayedSocketData data(1, reads, arraysize(reads), | |
3261 writes, arraysize(writes)); | |
3262 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3263 BoundNetLog(), GetParam(), NULL); | |
3264 helper.RunToCompletion(&data); | |
3265 TransactionHelperResult out = helper.output(); | |
3266 | |
3267 EXPECT_EQ(OK, out.rv); | |
3268 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
3269 EXPECT_EQ("hello!", out.response_data); | |
3270 | |
3271 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers; | |
3272 EXPECT_TRUE(headers.get() != NULL); | |
3273 void* iter = NULL; | |
3274 std::string name, value; | |
3275 SpdyHeaderBlock header_block; | |
3276 while (headers->EnumerateHeaderLines(&iter, &name, &value)) { | |
3277 if (header_block[name].empty()) { | |
3278 header_block[name] = value; | |
3279 } else { | |
3280 header_block[name] += '\0'; | |
3281 header_block[name] += value; | |
3282 } | |
3283 } | |
3284 EXPECT_EQ(test_cases[i].expected_headers, header_block); | |
3285 } | |
3286 } | |
3287 | |
3288 // Verify that various SynReply headers parse vary fields correctly | |
3289 // through the HTTP layer, and the response matches the request. | |
3290 TEST_P(SpdyNetworkTransactionTest, SynReplyHeadersVary) { | |
3291 // Modify the following data to change/add test cases: | |
3292 struct SynReplyTests { | |
3293 bool vary_matches; | |
3294 int num_headers[2]; | |
3295 const char* extra_headers[2][16]; | |
3296 } test_cases[] = { | |
3297 // Test the case of a multi-valued cookie. When the value is delimited | |
3298 // with NUL characters, it needs to be unfolded into multiple headers. | |
3299 { | |
3300 true, | |
3301 { 1, 4 }, | |
3302 { { "cookie", "val1,val2", | |
3303 NULL | |
3304 }, | |
3305 { "vary", "cookie", | |
3306 spdy_util_.GetStatusKey(), "200", | |
3307 spdy_util_.GetPathKey(), "/index.php", | |
3308 spdy_util_.GetVersionKey(), "HTTP/1.1", | |
3309 NULL | |
3310 } | |
3311 } | |
3312 }, { // Multiple vary fields. | |
3313 true, | |
3314 { 2, 5 }, | |
3315 { { "friend", "barney", | |
3316 "enemy", "snaggletooth", | |
3317 NULL | |
3318 }, | |
3319 { "vary", "friend", | |
3320 "vary", "enemy", | |
3321 spdy_util_.GetStatusKey(), "200", | |
3322 spdy_util_.GetPathKey(), "/index.php", | |
3323 spdy_util_.GetVersionKey(), "HTTP/1.1", | |
3324 NULL | |
3325 } | |
3326 } | |
3327 }, { // Test a '*' vary field. | |
3328 false, | |
3329 { 1, 4 }, | |
3330 { { "cookie", "val1,val2", | |
3331 NULL | |
3332 }, | |
3333 { "vary", "*", | |
3334 spdy_util_.GetStatusKey(), "200", | |
3335 spdy_util_.GetPathKey(), "/index.php", | |
3336 spdy_util_.GetVersionKey(), "HTTP/1.1", | |
3337 NULL | |
3338 } | |
3339 } | |
3340 }, { // Multiple comma-separated vary fields. | |
3341 true, | |
3342 { 2, 4 }, | |
3343 { { "friend", "barney", | |
3344 "enemy", "snaggletooth", | |
3345 NULL | |
3346 }, | |
3347 { "vary", "friend,enemy", | |
3348 spdy_util_.GetStatusKey(), "200", | |
3349 spdy_util_.GetPathKey(), "/index.php", | |
3350 spdy_util_.GetVersionKey(), "HTTP/1.1", | |
3351 NULL | |
3352 } | |
3353 } | |
3354 } | |
3355 }; | |
3356 | |
3357 for (size_t i = 0; i < arraysize(test_cases); ++i) { | |
3358 // Construct the request. | |
3359 scoped_ptr<SpdyFrame> frame_req( | |
3360 spdy_util_.ConstructSpdyGet(test_cases[i].extra_headers[0], | |
3361 test_cases[i].num_headers[0], | |
3362 false, 1, LOWEST, true)); | |
3363 | |
3364 MockWrite writes[] = { | |
3365 CreateMockWrite(*frame_req), | |
3366 }; | |
3367 | |
3368 // Construct the reply. | |
3369 SpdyHeaderBlock reply_headers; | |
3370 AppendToHeaderBlock(test_cases[i].extra_headers[1], | |
3371 test_cases[i].num_headers[1], | |
3372 &reply_headers); | |
3373 scoped_ptr<SpdyFrame> frame_reply( | |
3374 spdy_util_.ConstructSpdyReply(1, reply_headers)); | |
3375 | |
3376 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
3377 MockRead reads[] = { | |
3378 CreateMockRead(*frame_reply), | |
3379 CreateMockRead(*body), | |
3380 MockRead(ASYNC, 0, 0) // EOF | |
3381 }; | |
3382 | |
3383 // Attach the headers to the request. | |
3384 int header_count = test_cases[i].num_headers[0]; | |
3385 | |
3386 HttpRequestInfo request = CreateGetRequest(); | |
3387 for (int ct = 0; ct < header_count; ct++) { | |
3388 const char* header_key = test_cases[i].extra_headers[0][ct * 2]; | |
3389 const char* header_value = test_cases[i].extra_headers[0][ct * 2 + 1]; | |
3390 request.extra_headers.SetHeader(header_key, header_value); | |
3391 } | |
3392 | |
3393 DelayedSocketData data(1, reads, arraysize(reads), | |
3394 writes, arraysize(writes)); | |
3395 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
3396 BoundNetLog(), GetParam(), NULL); | |
3397 helper.RunToCompletion(&data); | |
3398 TransactionHelperResult out = helper.output(); | |
3399 | |
3400 EXPECT_EQ(OK, out.rv) << i; | |
3401 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line) << i; | |
3402 EXPECT_EQ("hello!", out.response_data) << i; | |
3403 | |
3404 // Test the response information. | |
3405 EXPECT_TRUE(out.response_info.response_time > | |
3406 out.response_info.request_time) << i; | |
3407 base::TimeDelta test_delay = out.response_info.response_time - | |
3408 out.response_info.request_time; | |
3409 base::TimeDelta min_expected_delay; | |
3410 min_expected_delay.FromMilliseconds(10); | |
3411 EXPECT_GT(test_delay.InMillisecondsF(), | |
3412 min_expected_delay.InMillisecondsF()) << i; | |
3413 EXPECT_EQ(out.response_info.vary_data.is_valid(), | |
3414 test_cases[i].vary_matches) << i; | |
3415 | |
3416 // Check the headers. | |
3417 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers; | |
3418 ASSERT_TRUE(headers.get() != NULL) << i; | |
3419 void* iter = NULL; | |
3420 std::string name, value, lines; | |
3421 while (headers->EnumerateHeaderLines(&iter, &name, &value)) { | |
3422 lines.append(name); | |
3423 lines.append(": "); | |
3424 lines.append(value); | |
3425 lines.append("\n"); | |
3426 } | |
3427 | |
3428 // Construct the expected header reply string. | |
3429 std::string expected_reply = | |
3430 spdy_util_.ConstructSpdyReplyString(reply_headers); | |
3431 EXPECT_EQ(expected_reply, lines) << i; | |
3432 } | |
3433 } | |
3434 | |
3435 // Verify that we don't crash on invalid SynReply responses. | |
3436 TEST_P(SpdyNetworkTransactionTest, InvalidSynReply) { | |
3437 struct InvalidSynReplyTests { | |
3438 int num_headers; | |
3439 const char* headers[10]; | |
3440 } test_cases[] = { | |
3441 // SYN_REPLY missing status header | |
3442 { 4, | |
3443 { "cookie", "val1", | |
3444 "cookie", "val2", | |
3445 spdy_util_.GetPathKey(), "/index.php", | |
3446 spdy_util_.GetVersionKey(), "HTTP/1.1", | |
3447 NULL | |
3448 }, | |
3449 }, | |
3450 // SYN_REPLY missing version header | |
3451 { 2, | |
3452 { "status", "200", | |
3453 spdy_util_.GetPathKey(), "/index.php", | |
3454 NULL | |
3455 }, | |
3456 }, | |
3457 // SYN_REPLY with no headers | |
3458 { 0, { NULL }, }, | |
3459 }; | |
3460 | |
3461 for (size_t i = 0; i < arraysize(test_cases); ++i) { | |
3462 scoped_ptr<SpdyFrame> req( | |
3463 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3464 scoped_ptr<SpdyFrame> rst( | |
3465 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); | |
3466 MockWrite writes[] = { | |
3467 CreateMockWrite(*req), | |
3468 CreateMockWrite(*rst), | |
3469 }; | |
3470 | |
3471 // Construct the reply. | |
3472 SpdyHeaderBlock reply_headers; | |
3473 AppendToHeaderBlock( | |
3474 test_cases[i].headers, test_cases[i].num_headers, &reply_headers); | |
3475 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyReply(1, reply_headers)); | |
3476 MockRead reads[] = { | |
3477 CreateMockRead(*resp), | |
3478 MockRead(ASYNC, 0, 0) // EOF | |
3479 }; | |
3480 | |
3481 DelayedSocketData data(1, reads, arraysize(reads), | |
3482 writes, arraysize(writes)); | |
3483 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3484 BoundNetLog(), GetParam(), NULL); | |
3485 helper.RunToCompletion(&data); | |
3486 TransactionHelperResult out = helper.output(); | |
3487 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
3488 } | |
3489 } | |
3490 | |
3491 // Verify that we don't crash on some corrupt frames. | |
3492 // TODO(jgraettinger): SPDY4 and up treats a header decompression failure as a | |
3493 // connection error. I'd like to backport this behavior to SPDY3 as well. | |
3494 TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionError) { | |
3495 if (spdy_util_.spdy_version() >= SPDY4) { | |
3496 return; | |
3497 } | |
3498 // This is the length field that's too short. | |
3499 scoped_ptr<SpdyFrame> syn_reply_wrong_length( | |
3500 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3501 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
3502 size_t right_size = | |
3503 (spdy_util_.spdy_version() < SPDY4) ? | |
3504 syn_reply_wrong_length->size() - framer.GetControlFrameHeaderSize() : | |
3505 syn_reply_wrong_length->size(); | |
3506 size_t wrong_size = right_size - 4; | |
3507 test::SetFrameLength(syn_reply_wrong_length.get(), | |
3508 wrong_size, | |
3509 spdy_util_.spdy_version()); | |
3510 | |
3511 struct SynReplyTests { | |
3512 const SpdyFrame* syn_reply; | |
3513 } test_cases[] = { | |
3514 { syn_reply_wrong_length.get(), }, | |
3515 }; | |
3516 | |
3517 for (size_t i = 0; i < arraysize(test_cases); ++i) { | |
3518 scoped_ptr<SpdyFrame> req( | |
3519 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3520 scoped_ptr<SpdyFrame> rst( | |
3521 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); | |
3522 MockWrite writes[] = { | |
3523 CreateMockWrite(*req), | |
3524 CreateMockWrite(*rst), | |
3525 }; | |
3526 | |
3527 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
3528 MockRead reads[] = { | |
3529 MockRead(ASYNC, test_cases[i].syn_reply->data(), wrong_size), | |
3530 CreateMockRead(*body), | |
3531 MockRead(ASYNC, 0, 0) // EOF | |
3532 }; | |
3533 | |
3534 DelayedSocketData data(1, reads, arraysize(reads), | |
3535 writes, arraysize(writes)); | |
3536 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3537 BoundNetLog(), GetParam(), NULL); | |
3538 helper.RunToCompletion(&data); | |
3539 TransactionHelperResult out = helper.output(); | |
3540 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
3541 } | |
3542 } | |
3543 | |
3544 // SPDY4 treats a header decompression failure as a connection-level error. | |
3545 TEST_P(SpdyNetworkTransactionTest, CorruptFrameSessionErrorSpdy4) { | |
3546 if (spdy_util_.spdy_version() < SPDY4) { | |
3547 return; | |
3548 } | |
3549 // This is the length field that's too short. | |
3550 scoped_ptr<SpdyFrame> syn_reply_wrong_length( | |
3551 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3552 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
3553 size_t right_size = | |
3554 syn_reply_wrong_length->size() - framer.GetControlFrameHeaderSize(); | |
3555 size_t wrong_size = right_size - 4; | |
3556 test::SetFrameLength(syn_reply_wrong_length.get(), | |
3557 wrong_size, | |
3558 spdy_util_.spdy_version()); | |
3559 | |
3560 scoped_ptr<SpdyFrame> req( | |
3561 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3562 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway( | |
3563 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE).")); | |
3564 MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)}; | |
3565 | |
3566 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
3567 MockRead reads[] = { | |
3568 MockRead(ASYNC, syn_reply_wrong_length->data(), | |
3569 syn_reply_wrong_length->size() - 4), | |
3570 }; | |
3571 | |
3572 DelayedSocketData data(1, reads, arraysize(reads), | |
3573 writes, arraysize(writes)); | |
3574 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3575 BoundNetLog(), GetParam(), NULL); | |
3576 helper.RunToCompletion(&data); | |
3577 TransactionHelperResult out = helper.output(); | |
3578 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv); | |
3579 } | |
3580 | |
3581 TEST_P(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) { | |
3582 if (GetParam().protocol < kProtoSPDY4MinimumVersion) { | |
3583 // Decompression failures are a stream error in SPDY3 and above. | |
3584 return; | |
3585 } | |
3586 scoped_ptr<SpdyFrame> req( | |
3587 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3588 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway( | |
3589 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE).")); | |
3590 MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)}; | |
3591 | |
3592 // Read HEADERS with corrupted payload. | |
3593 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3594 memset(resp->data() + 12, 0xff, resp->size() - 12); | |
3595 MockRead reads[] = {CreateMockRead(*resp)}; | |
3596 | |
3597 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); | |
3598 NormalSpdyTransactionHelper helper( | |
3599 CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); | |
3600 helper.RunToCompletion(&data); | |
3601 TransactionHelperResult out = helper.output(); | |
3602 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv); | |
3603 } | |
3604 | |
3605 TEST_P(SpdyNetworkTransactionTest, GoAwayOnFrameSizeError) { | |
3606 scoped_ptr<SpdyFrame> req( | |
3607 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3608 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway( | |
3609 0, GOAWAY_PROTOCOL_ERROR, "Framer error: 1 (INVALID_CONTROL_FRAME).")); | |
3610 MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*goaway)}; | |
3611 | |
3612 // Read WINDOW_UPDATE with incorrectly-sized payload. | |
3613 // TODO(jgraettinger): SpdyFramer signals this as an INVALID_CONTROL_FRAME, | |
3614 // which is mapped to a protocol error, and not a frame size error. | |
3615 scoped_ptr<SpdyFrame> bad_window_update( | |
3616 spdy_util_.ConstructSpdyWindowUpdate(1, 1)); | |
3617 test::SetFrameLength(bad_window_update.get(), | |
3618 bad_window_update->size() - 1, | |
3619 spdy_util_.spdy_version()); | |
3620 MockRead reads[] = {CreateMockRead(*bad_window_update)}; | |
3621 | |
3622 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); | |
3623 NormalSpdyTransactionHelper helper( | |
3624 CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); | |
3625 helper.RunToCompletion(&data); | |
3626 TransactionHelperResult out = helper.output(); | |
3627 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
3628 } | |
3629 | |
3630 // Test that we shutdown correctly on write errors. | |
3631 TEST_P(SpdyNetworkTransactionTest, WriteError) { | |
3632 scoped_ptr<SpdyFrame> req( | |
3633 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3634 MockWrite writes[] = { | |
3635 // We'll write 10 bytes successfully | |
3636 MockWrite(ASYNC, req->data(), 10, 0), | |
3637 // Followed by ERROR! | |
3638 MockWrite(ASYNC, ERR_FAILED, 1), | |
3639 // Session drains and attempts to write a GOAWAY: Another ERROR! | |
3640 MockWrite(ASYNC, ERR_FAILED, 2), | |
3641 }; | |
3642 | |
3643 MockRead reads[] = { | |
3644 MockRead(ASYNC, 0, 3) // EOF | |
3645 }; | |
3646 | |
3647 DeterministicSocketData data(reads, arraysize(reads), | |
3648 writes, arraysize(writes)); | |
3649 | |
3650 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3651 BoundNetLog(), GetParam(), NULL); | |
3652 helper.SetDeterministic(); | |
3653 helper.RunPreTestSetup(); | |
3654 helper.AddDeterministicData(&data); | |
3655 EXPECT_TRUE(helper.StartDefaultTest()); | |
3656 data.RunFor(2); | |
3657 helper.FinishDefaultTest(); | |
3658 EXPECT_TRUE(data.at_write_eof()); | |
3659 EXPECT_TRUE(!data.at_read_eof()); | |
3660 TransactionHelperResult out = helper.output(); | |
3661 EXPECT_EQ(ERR_FAILED, out.rv); | |
3662 } | |
3663 | |
3664 // Test that partial writes work. | |
3665 TEST_P(SpdyNetworkTransactionTest, PartialWrite) { | |
3666 // Chop the SYN_STREAM frame into 5 chunks. | |
3667 scoped_ptr<SpdyFrame> req( | |
3668 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3669 const int kChunks = 5; | |
3670 scoped_ptr<MockWrite[]> writes(ChopWriteFrame(*req.get(), kChunks)); | |
3671 | |
3672 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3673 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
3674 MockRead reads[] = { | |
3675 CreateMockRead(*resp), | |
3676 CreateMockRead(*body), | |
3677 MockRead(ASYNC, 0, 0) // EOF | |
3678 }; | |
3679 | |
3680 DelayedSocketData data(kChunks, reads, arraysize(reads), | |
3681 writes.get(), kChunks); | |
3682 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3683 BoundNetLog(), GetParam(), NULL); | |
3684 helper.RunToCompletion(&data); | |
3685 TransactionHelperResult out = helper.output(); | |
3686 EXPECT_EQ(OK, out.rv); | |
3687 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
3688 EXPECT_EQ("hello!", out.response_data); | |
3689 } | |
3690 | |
3691 // In this test, we enable compression, but get a uncompressed SynReply from | |
3692 // the server. Verify that teardown is all clean. | |
3693 TEST_P(SpdyNetworkTransactionTest, DecompressFailureOnSynReply) { | |
3694 if (spdy_util_.spdy_version() >= SPDY4) { | |
3695 // HPACK doesn't use deflate compression. | |
3696 return; | |
3697 } | |
3698 scoped_ptr<SpdyFrame> compressed( | |
3699 spdy_util_.ConstructSpdyGet(NULL, 0, true, 1, LOWEST, true)); | |
3700 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway( | |
3701 0, GOAWAY_COMPRESSION_ERROR, "Framer error: 5 (DECOMPRESS_FAILURE).")); | |
3702 MockWrite writes[] = {CreateMockWrite(*compressed), CreateMockWrite(*goaway)}; | |
3703 | |
3704 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3705 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
3706 MockRead reads[] = { | |
3707 CreateMockRead(*resp), | |
3708 }; | |
3709 | |
3710 DelayedSocketData data(1, reads, arraysize(reads), | |
3711 writes, arraysize(writes)); | |
3712 SpdySessionDependencies* session_deps = | |
3713 CreateSpdySessionDependencies(GetParam()); | |
3714 session_deps->enable_compression = true; | |
3715 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3716 BoundNetLog(), GetParam(), session_deps); | |
3717 helper.RunToCompletion(&data); | |
3718 TransactionHelperResult out = helper.output(); | |
3719 EXPECT_EQ(ERR_SPDY_COMPRESSION_ERROR, out.rv); | |
3720 data.Reset(); | |
3721 } | |
3722 | |
3723 // Test that the NetLog contains good data for a simple GET request. | |
3724 TEST_P(SpdyNetworkTransactionTest, NetLog) { | |
3725 static const char* const kExtraHeaders[] = { | |
3726 "user-agent", "Chrome", | |
3727 }; | |
3728 scoped_ptr<SpdyFrame> req( | |
3729 spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, false, 1, LOWEST, true)); | |
3730 MockWrite writes[] = { CreateMockWrite(*req) }; | |
3731 | |
3732 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3733 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
3734 MockRead reads[] = { | |
3735 CreateMockRead(*resp), | |
3736 CreateMockRead(*body), | |
3737 MockRead(ASYNC, 0, 0) // EOF | |
3738 }; | |
3739 | |
3740 CapturingBoundNetLog log; | |
3741 | |
3742 DelayedSocketData data(1, reads, arraysize(reads), | |
3743 writes, arraysize(writes)); | |
3744 NormalSpdyTransactionHelper helper(CreateGetRequestWithUserAgent(), | |
3745 DEFAULT_PRIORITY, | |
3746 log.bound(), GetParam(), NULL); | |
3747 helper.RunToCompletion(&data); | |
3748 TransactionHelperResult out = helper.output(); | |
3749 EXPECT_EQ(OK, out.rv); | |
3750 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
3751 EXPECT_EQ("hello!", out.response_data); | |
3752 | |
3753 // Check that the NetLog was filled reasonably. | |
3754 // This test is intentionally non-specific about the exact ordering of the | |
3755 // log; instead we just check to make sure that certain events exist, and that | |
3756 // they are in the right order. | |
3757 net::CapturingNetLog::CapturedEntryList entries; | |
3758 log.GetEntries(&entries); | |
3759 | |
3760 EXPECT_LT(0u, entries.size()); | |
3761 int pos = 0; | |
3762 pos = net::ExpectLogContainsSomewhere(entries, 0, | |
3763 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, | |
3764 net::NetLog::PHASE_BEGIN); | |
3765 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
3766 net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST, | |
3767 net::NetLog::PHASE_END); | |
3768 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
3769 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, | |
3770 net::NetLog::PHASE_BEGIN); | |
3771 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
3772 net::NetLog::TYPE_HTTP_TRANSACTION_READ_HEADERS, | |
3773 net::NetLog::PHASE_END); | |
3774 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
3775 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, | |
3776 net::NetLog::PHASE_BEGIN); | |
3777 pos = net::ExpectLogContainsSomewhere(entries, pos + 1, | |
3778 net::NetLog::TYPE_HTTP_TRANSACTION_READ_BODY, | |
3779 net::NetLog::PHASE_END); | |
3780 | |
3781 // Check that we logged all the headers correctly | |
3782 pos = net::ExpectLogContainsSomewhere( | |
3783 entries, 0, | |
3784 net::NetLog::TYPE_SPDY_SESSION_SYN_STREAM, | |
3785 net::NetLog::PHASE_NONE); | |
3786 | |
3787 base::ListValue* header_list; | |
3788 ASSERT_TRUE(entries[pos].params.get()); | |
3789 ASSERT_TRUE(entries[pos].params->GetList("headers", &header_list)); | |
3790 | |
3791 std::vector<std::string> expected; | |
3792 expected.push_back(std::string(spdy_util_.GetHostKey()) + ": www.google.com"); | |
3793 expected.push_back(std::string(spdy_util_.GetPathKey()) + ": /"); | |
3794 expected.push_back(std::string(spdy_util_.GetSchemeKey()) + ": http"); | |
3795 expected.push_back(std::string(spdy_util_.GetMethodKey()) + ": GET"); | |
3796 expected.push_back("user-agent: Chrome"); | |
3797 if (spdy_util_.spdy_version() < SPDY4) { | |
3798 // SPDY4/HTTP2 eliminates use of the :version header. | |
3799 expected.push_back(std::string(spdy_util_.GetVersionKey()) + ": HTTP/1.1"); | |
3800 } | |
3801 EXPECT_EQ(expected.size(), header_list->GetSize()); | |
3802 for (std::vector<std::string>::const_iterator it = expected.begin(); | |
3803 it != expected.end(); | |
3804 ++it) { | |
3805 base::StringValue header(*it); | |
3806 EXPECT_NE(header_list->end(), header_list->Find(header)) << | |
3807 "Header not found: " << *it; | |
3808 } | |
3809 } | |
3810 | |
3811 // Since we buffer the IO from the stream to the renderer, this test verifies | |
3812 // that when we read out the maximum amount of data (e.g. we received 50 bytes | |
3813 // on the network, but issued a Read for only 5 of those bytes) that the data | |
3814 // flow still works correctly. | |
3815 TEST_P(SpdyNetworkTransactionTest, BufferFull) { | |
3816 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
3817 | |
3818 scoped_ptr<SpdyFrame> req( | |
3819 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3820 MockWrite writes[] = { CreateMockWrite(*req) }; | |
3821 | |
3822 // 2 data frames in a single read. | |
3823 scoped_ptr<SpdyFrame> data_frame_1( | |
3824 framer.CreateDataFrame(1, "goodby", 6, DATA_FLAG_NONE)); | |
3825 scoped_ptr<SpdyFrame> data_frame_2( | |
3826 framer.CreateDataFrame(1, "e worl", 6, DATA_FLAG_NONE)); | |
3827 const SpdyFrame* data_frames[2] = { | |
3828 data_frame_1.get(), | |
3829 data_frame_2.get(), | |
3830 }; | |
3831 char combined_data_frames[100]; | |
3832 int combined_data_frames_len = | |
3833 CombineFrames(data_frames, arraysize(data_frames), | |
3834 combined_data_frames, arraysize(combined_data_frames)); | |
3835 scoped_ptr<SpdyFrame> last_frame( | |
3836 framer.CreateDataFrame(1, "d", 1, DATA_FLAG_FIN)); | |
3837 | |
3838 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3839 MockRead reads[] = { | |
3840 CreateMockRead(*resp), | |
3841 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause | |
3842 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), | |
3843 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause | |
3844 CreateMockRead(*last_frame), | |
3845 MockRead(ASYNC, 0, 0) // EOF | |
3846 }; | |
3847 | |
3848 DelayedSocketData data(1, reads, arraysize(reads), | |
3849 writes, arraysize(writes)); | |
3850 | |
3851 TestCompletionCallback callback; | |
3852 | |
3853 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3854 BoundNetLog(), GetParam(), NULL); | |
3855 helper.RunPreTestSetup(); | |
3856 helper.AddData(&data); | |
3857 HttpNetworkTransaction* trans = helper.trans(); | |
3858 int rv = trans->Start( | |
3859 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
3860 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3861 | |
3862 TransactionHelperResult out = helper.output(); | |
3863 out.rv = callback.WaitForResult(); | |
3864 EXPECT_EQ(out.rv, OK); | |
3865 | |
3866 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3867 EXPECT_TRUE(response->headers.get() != NULL); | |
3868 EXPECT_TRUE(response->was_fetched_via_spdy); | |
3869 out.status_line = response->headers->GetStatusLine(); | |
3870 out.response_info = *response; // Make a copy so we can verify. | |
3871 | |
3872 // Read Data | |
3873 TestCompletionCallback read_callback; | |
3874 | |
3875 std::string content; | |
3876 do { | |
3877 // Read small chunks at a time. | |
3878 const int kSmallReadSize = 3; | |
3879 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
3880 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); | |
3881 if (rv == net::ERR_IO_PENDING) { | |
3882 data.CompleteRead(); | |
3883 rv = read_callback.WaitForResult(); | |
3884 } | |
3885 if (rv > 0) { | |
3886 content.append(buf->data(), rv); | |
3887 } else if (rv < 0) { | |
3888 NOTREACHED(); | |
3889 } | |
3890 } while (rv > 0); | |
3891 | |
3892 out.response_data.swap(content); | |
3893 | |
3894 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
3895 // MockClientSocketFactory) are still alive. | |
3896 base::RunLoop().RunUntilIdle(); | |
3897 | |
3898 // Verify that we consumed all test data. | |
3899 helper.VerifyDataConsumed(); | |
3900 | |
3901 EXPECT_EQ(OK, out.rv); | |
3902 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
3903 EXPECT_EQ("goodbye world", out.response_data); | |
3904 } | |
3905 | |
3906 // Verify that basic buffering works; when multiple data frames arrive | |
3907 // at the same time, ensure that we don't notify a read completion for | |
3908 // each data frame individually. | |
3909 TEST_P(SpdyNetworkTransactionTest, Buffering) { | |
3910 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
3911 | |
3912 scoped_ptr<SpdyFrame> req( | |
3913 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
3914 MockWrite writes[] = { CreateMockWrite(*req) }; | |
3915 | |
3916 // 4 data frames in a single read. | |
3917 scoped_ptr<SpdyFrame> data_frame( | |
3918 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); | |
3919 scoped_ptr<SpdyFrame> data_frame_fin( | |
3920 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN)); | |
3921 const SpdyFrame* data_frames[4] = { | |
3922 data_frame.get(), | |
3923 data_frame.get(), | |
3924 data_frame.get(), | |
3925 data_frame_fin.get() | |
3926 }; | |
3927 char combined_data_frames[100]; | |
3928 int combined_data_frames_len = | |
3929 CombineFrames(data_frames, arraysize(data_frames), | |
3930 combined_data_frames, arraysize(combined_data_frames)); | |
3931 | |
3932 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
3933 MockRead reads[] = { | |
3934 CreateMockRead(*resp), | |
3935 MockRead(ASYNC, ERR_IO_PENDING), // Force a pause | |
3936 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), | |
3937 MockRead(ASYNC, 0, 0) // EOF | |
3938 }; | |
3939 | |
3940 DelayedSocketData data(1, reads, arraysize(reads), | |
3941 writes, arraysize(writes)); | |
3942 | |
3943 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
3944 BoundNetLog(), GetParam(), NULL); | |
3945 helper.RunPreTestSetup(); | |
3946 helper.AddData(&data); | |
3947 HttpNetworkTransaction* trans = helper.trans(); | |
3948 | |
3949 TestCompletionCallback callback; | |
3950 int rv = trans->Start( | |
3951 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
3952 EXPECT_EQ(ERR_IO_PENDING, rv); | |
3953 | |
3954 TransactionHelperResult out = helper.output(); | |
3955 out.rv = callback.WaitForResult(); | |
3956 EXPECT_EQ(out.rv, OK); | |
3957 | |
3958 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
3959 EXPECT_TRUE(response->headers.get() != NULL); | |
3960 EXPECT_TRUE(response->was_fetched_via_spdy); | |
3961 out.status_line = response->headers->GetStatusLine(); | |
3962 out.response_info = *response; // Make a copy so we can verify. | |
3963 | |
3964 // Read Data | |
3965 TestCompletionCallback read_callback; | |
3966 | |
3967 std::string content; | |
3968 int reads_completed = 0; | |
3969 do { | |
3970 // Read small chunks at a time. | |
3971 const int kSmallReadSize = 14; | |
3972 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
3973 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); | |
3974 if (rv == net::ERR_IO_PENDING) { | |
3975 data.CompleteRead(); | |
3976 rv = read_callback.WaitForResult(); | |
3977 } | |
3978 if (rv > 0) { | |
3979 EXPECT_EQ(kSmallReadSize, rv); | |
3980 content.append(buf->data(), rv); | |
3981 } else if (rv < 0) { | |
3982 FAIL() << "Unexpected read error: " << rv; | |
3983 } | |
3984 reads_completed++; | |
3985 } while (rv > 0); | |
3986 | |
3987 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes. | |
3988 | |
3989 out.response_data.swap(content); | |
3990 | |
3991 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
3992 // MockClientSocketFactory) are still alive. | |
3993 base::RunLoop().RunUntilIdle(); | |
3994 | |
3995 // Verify that we consumed all test data. | |
3996 helper.VerifyDataConsumed(); | |
3997 | |
3998 EXPECT_EQ(OK, out.rv); | |
3999 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4000 EXPECT_EQ("messagemessagemessagemessage", out.response_data); | |
4001 } | |
4002 | |
4003 // Verify the case where we buffer data but read it after it has been buffered. | |
4004 TEST_P(SpdyNetworkTransactionTest, BufferedAll) { | |
4005 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
4006 | |
4007 scoped_ptr<SpdyFrame> req( | |
4008 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4009 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4010 | |
4011 // 5 data frames in a single read. | |
4012 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4013 scoped_ptr<SpdyFrame> data_frame( | |
4014 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); | |
4015 scoped_ptr<SpdyFrame> data_frame_fin( | |
4016 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_FIN)); | |
4017 const SpdyFrame* frames[5] = {reply.get(), data_frame.get(), data_frame.get(), | |
4018 data_frame.get(), data_frame_fin.get()}; | |
4019 char combined_frames[200]; | |
4020 int combined_frames_len = | |
4021 CombineFrames(frames, arraysize(frames), | |
4022 combined_frames, arraysize(combined_frames)); | |
4023 | |
4024 MockRead reads[] = { | |
4025 MockRead(ASYNC, combined_frames, combined_frames_len), | |
4026 MockRead(ASYNC, 0, 0) // EOF | |
4027 }; | |
4028 | |
4029 DelayedSocketData data(1, reads, arraysize(reads), | |
4030 writes, arraysize(writes)); | |
4031 | |
4032 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4033 BoundNetLog(), GetParam(), NULL); | |
4034 helper.RunPreTestSetup(); | |
4035 helper.AddData(&data); | |
4036 HttpNetworkTransaction* trans = helper.trans(); | |
4037 | |
4038 TestCompletionCallback callback; | |
4039 int rv = trans->Start( | |
4040 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4041 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4042 | |
4043 TransactionHelperResult out = helper.output(); | |
4044 out.rv = callback.WaitForResult(); | |
4045 EXPECT_EQ(out.rv, OK); | |
4046 | |
4047 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4048 EXPECT_TRUE(response->headers.get() != NULL); | |
4049 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4050 out.status_line = response->headers->GetStatusLine(); | |
4051 out.response_info = *response; // Make a copy so we can verify. | |
4052 | |
4053 // Read Data | |
4054 TestCompletionCallback read_callback; | |
4055 | |
4056 std::string content; | |
4057 int reads_completed = 0; | |
4058 do { | |
4059 // Read small chunks at a time. | |
4060 const int kSmallReadSize = 14; | |
4061 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
4062 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); | |
4063 if (rv > 0) { | |
4064 EXPECT_EQ(kSmallReadSize, rv); | |
4065 content.append(buf->data(), rv); | |
4066 } else if (rv < 0) { | |
4067 FAIL() << "Unexpected read error: " << rv; | |
4068 } | |
4069 reads_completed++; | |
4070 } while (rv > 0); | |
4071 | |
4072 EXPECT_EQ(3, reads_completed); | |
4073 | |
4074 out.response_data.swap(content); | |
4075 | |
4076 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
4077 // MockClientSocketFactory) are still alive. | |
4078 base::RunLoop().RunUntilIdle(); | |
4079 | |
4080 // Verify that we consumed all test data. | |
4081 helper.VerifyDataConsumed(); | |
4082 | |
4083 EXPECT_EQ(OK, out.rv); | |
4084 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4085 EXPECT_EQ("messagemessagemessagemessage", out.response_data); | |
4086 } | |
4087 | |
4088 // Verify the case where we buffer data and close the connection. | |
4089 TEST_P(SpdyNetworkTransactionTest, BufferedClosed) { | |
4090 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
4091 | |
4092 scoped_ptr<SpdyFrame> req( | |
4093 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4094 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4095 | |
4096 // All data frames in a single read. | |
4097 // NOTE: We don't FIN the stream. | |
4098 scoped_ptr<SpdyFrame> data_frame( | |
4099 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); | |
4100 const SpdyFrame* data_frames[4] = { | |
4101 data_frame.get(), | |
4102 data_frame.get(), | |
4103 data_frame.get(), | |
4104 data_frame.get() | |
4105 }; | |
4106 char combined_data_frames[100]; | |
4107 int combined_data_frames_len = | |
4108 CombineFrames(data_frames, arraysize(data_frames), | |
4109 combined_data_frames, arraysize(combined_data_frames)); | |
4110 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4111 MockRead reads[] = { | |
4112 CreateMockRead(*resp), | |
4113 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait | |
4114 MockRead(ASYNC, combined_data_frames, combined_data_frames_len), | |
4115 MockRead(ASYNC, 0, 0) // EOF | |
4116 }; | |
4117 | |
4118 DelayedSocketData data(1, reads, arraysize(reads), | |
4119 writes, arraysize(writes)); | |
4120 | |
4121 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4122 BoundNetLog(), GetParam(), NULL); | |
4123 helper.RunPreTestSetup(); | |
4124 helper.AddData(&data); | |
4125 HttpNetworkTransaction* trans = helper.trans(); | |
4126 | |
4127 TestCompletionCallback callback; | |
4128 | |
4129 int rv = trans->Start( | |
4130 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4131 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4132 | |
4133 TransactionHelperResult out = helper.output(); | |
4134 out.rv = callback.WaitForResult(); | |
4135 EXPECT_EQ(out.rv, OK); | |
4136 | |
4137 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4138 EXPECT_TRUE(response->headers.get() != NULL); | |
4139 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4140 out.status_line = response->headers->GetStatusLine(); | |
4141 out.response_info = *response; // Make a copy so we can verify. | |
4142 | |
4143 // Read Data | |
4144 TestCompletionCallback read_callback; | |
4145 | |
4146 std::string content; | |
4147 int reads_completed = 0; | |
4148 do { | |
4149 // Read small chunks at a time. | |
4150 const int kSmallReadSize = 14; | |
4151 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kSmallReadSize)); | |
4152 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback()); | |
4153 if (rv == net::ERR_IO_PENDING) { | |
4154 data.CompleteRead(); | |
4155 rv = read_callback.WaitForResult(); | |
4156 } | |
4157 if (rv > 0) { | |
4158 content.append(buf->data(), rv); | |
4159 } else if (rv < 0) { | |
4160 // This test intentionally closes the connection, and will get an error. | |
4161 EXPECT_EQ(ERR_CONNECTION_CLOSED, rv); | |
4162 break; | |
4163 } | |
4164 reads_completed++; | |
4165 } while (rv > 0); | |
4166 | |
4167 EXPECT_EQ(0, reads_completed); | |
4168 | |
4169 out.response_data.swap(content); | |
4170 | |
4171 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the | |
4172 // MockClientSocketFactory) are still alive. | |
4173 base::RunLoop().RunUntilIdle(); | |
4174 | |
4175 // Verify that we consumed all test data. | |
4176 helper.VerifyDataConsumed(); | |
4177 } | |
4178 | |
4179 // Verify the case where we buffer data and cancel the transaction. | |
4180 TEST_P(SpdyNetworkTransactionTest, BufferedCancelled) { | |
4181 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); | |
4182 | |
4183 scoped_ptr<SpdyFrame> req( | |
4184 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4185 scoped_ptr<SpdyFrame> rst( | |
4186 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL)); | |
4187 MockWrite writes[] = {CreateMockWrite(*req), CreateMockWrite(*rst)}; | |
4188 | |
4189 // NOTE: We don't FIN the stream. | |
4190 scoped_ptr<SpdyFrame> data_frame( | |
4191 framer.CreateDataFrame(1, "message", 7, DATA_FLAG_NONE)); | |
4192 | |
4193 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4194 MockRead reads[] = { | |
4195 CreateMockRead(*resp), | |
4196 MockRead(ASYNC, ERR_IO_PENDING), // Force a wait | |
4197 CreateMockRead(*data_frame), | |
4198 MockRead(ASYNC, 0, 0) // EOF | |
4199 }; | |
4200 | |
4201 DelayedSocketData data(1, reads, arraysize(reads), | |
4202 writes, arraysize(writes)); | |
4203 | |
4204 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4205 BoundNetLog(), GetParam(), NULL); | |
4206 helper.RunPreTestSetup(); | |
4207 helper.AddData(&data); | |
4208 HttpNetworkTransaction* trans = helper.trans(); | |
4209 TestCompletionCallback callback; | |
4210 | |
4211 int rv = trans->Start( | |
4212 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4213 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4214 | |
4215 TransactionHelperResult out = helper.output(); | |
4216 out.rv = callback.WaitForResult(); | |
4217 EXPECT_EQ(out.rv, OK); | |
4218 | |
4219 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4220 EXPECT_TRUE(response->headers.get() != NULL); | |
4221 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4222 out.status_line = response->headers->GetStatusLine(); | |
4223 out.response_info = *response; // Make a copy so we can verify. | |
4224 | |
4225 // Read Data | |
4226 TestCompletionCallback read_callback; | |
4227 | |
4228 const int kReadSize = 256; | |
4229 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kReadSize)); | |
4230 rv = trans->Read(buf.get(), kReadSize, read_callback.callback()); | |
4231 ASSERT_EQ(net::ERR_IO_PENDING, rv) << "Unexpected read: " << rv; | |
4232 | |
4233 // Complete the read now, which causes buffering to start. | |
4234 data.CompleteRead(); | |
4235 // Destroy the transaction, causing the stream to get cancelled | |
4236 // and orphaning the buffered IO task. | |
4237 helper.ResetTrans(); | |
4238 | |
4239 // Flush the MessageLoop; this will cause the buffered IO task | |
4240 // to run for the final time. | |
4241 base::RunLoop().RunUntilIdle(); | |
4242 | |
4243 // Verify that we consumed all test data. | |
4244 helper.VerifyDataConsumed(); | |
4245 } | |
4246 | |
4247 // Test that if the server requests persistence of settings, that we save | |
4248 // the settings in the HttpServerProperties. | |
4249 TEST_P(SpdyNetworkTransactionTest, SettingsSaved) { | |
4250 if (spdy_util_.spdy_version() >= SPDY4) { | |
4251 // SPDY4 doesn't support settings persistence. | |
4252 return; | |
4253 } | |
4254 static const SpdyHeaderInfo kSynReplyInfo = { | |
4255 SYN_REPLY, // Syn Reply | |
4256 1, // Stream ID | |
4257 0, // Associated Stream ID | |
4258 ConvertRequestPriorityToSpdyPriority( | |
4259 LOWEST, spdy_util_.spdy_version()), | |
4260 kSpdyCredentialSlotUnused, | |
4261 CONTROL_FLAG_NONE, // Control Flags | |
4262 false, // Compressed | |
4263 RST_STREAM_INVALID, // Status | |
4264 NULL, // Data | |
4265 0, // Data Length | |
4266 DATA_FLAG_NONE // Data Flags | |
4267 }; | |
4268 | |
4269 BoundNetLog net_log; | |
4270 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4271 net_log, GetParam(), NULL); | |
4272 helper.RunPreTestSetup(); | |
4273 | |
4274 // Verify that no settings exist initially. | |
4275 HostPortPair host_port_pair("www.google.com", helper.port()); | |
4276 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); | |
4277 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4278 host_port_pair).empty()); | |
4279 | |
4280 // Construct the request. | |
4281 scoped_ptr<SpdyFrame> req( | |
4282 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4283 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4284 | |
4285 // Construct the reply. | |
4286 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock()); | |
4287 (*reply_headers)[spdy_util_.GetStatusKey()] = "200"; | |
4288 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1"; | |
4289 scoped_ptr<SpdyFrame> reply( | |
4290 spdy_util_.ConstructSpdyFrame(kSynReplyInfo, reply_headers.Pass())); | |
4291 | |
4292 const SpdySettingsIds kSampleId1 = SETTINGS_UPLOAD_BANDWIDTH; | |
4293 unsigned int kSampleValue1 = 0x0a0a0a0a; | |
4294 const SpdySettingsIds kSampleId2 = SETTINGS_DOWNLOAD_BANDWIDTH; | |
4295 unsigned int kSampleValue2 = 0x0b0b0b0b; | |
4296 const SpdySettingsIds kSampleId3 = SETTINGS_ROUND_TRIP_TIME; | |
4297 unsigned int kSampleValue3 = 0x0c0c0c0c; | |
4298 scoped_ptr<SpdyFrame> settings_frame; | |
4299 { | |
4300 // Construct the SETTINGS frame. | |
4301 SettingsMap settings; | |
4302 // First add a persisted setting. | |
4303 settings[kSampleId1] = | |
4304 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue1); | |
4305 // Next add a non-persisted setting. | |
4306 settings[kSampleId2] = | |
4307 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kSampleValue2); | |
4308 // Next add another persisted setting. | |
4309 settings[kSampleId3] = | |
4310 SettingsFlagsAndValue(SETTINGS_FLAG_PLEASE_PERSIST, kSampleValue3); | |
4311 settings_frame.reset(spdy_util_.ConstructSpdySettings(settings)); | |
4312 } | |
4313 | |
4314 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
4315 MockRead reads[] = { | |
4316 CreateMockRead(*reply), | |
4317 CreateMockRead(*body), | |
4318 CreateMockRead(*settings_frame), | |
4319 MockRead(ASYNC, 0, 0) // EOF | |
4320 }; | |
4321 | |
4322 DelayedSocketData data(1, reads, arraysize(reads), | |
4323 writes, arraysize(writes)); | |
4324 helper.AddData(&data); | |
4325 helper.RunDefaultTest(); | |
4326 helper.VerifyDataConsumed(); | |
4327 TransactionHelperResult out = helper.output(); | |
4328 EXPECT_EQ(OK, out.rv); | |
4329 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4330 EXPECT_EQ("hello!", out.response_data); | |
4331 | |
4332 { | |
4333 // Verify we had two persisted settings. | |
4334 const SettingsMap& settings_map = | |
4335 spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4336 host_port_pair); | |
4337 ASSERT_EQ(2u, settings_map.size()); | |
4338 | |
4339 // Verify the first persisted setting. | |
4340 SettingsMap::const_iterator it1 = settings_map.find(kSampleId1); | |
4341 EXPECT_TRUE(it1 != settings_map.end()); | |
4342 SettingsFlagsAndValue flags_and_value1 = it1->second; | |
4343 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first); | |
4344 EXPECT_EQ(kSampleValue1, flags_and_value1.second); | |
4345 | |
4346 // Verify the second persisted setting. | |
4347 SettingsMap::const_iterator it3 = settings_map.find(kSampleId3); | |
4348 EXPECT_TRUE(it3 != settings_map.end()); | |
4349 SettingsFlagsAndValue flags_and_value3 = it3->second; | |
4350 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value3.first); | |
4351 EXPECT_EQ(kSampleValue3, flags_and_value3.second); | |
4352 } | |
4353 } | |
4354 | |
4355 // Test that when there are settings saved that they are sent back to the | |
4356 // server upon session establishment. | |
4357 TEST_P(SpdyNetworkTransactionTest, SettingsPlayback) { | |
4358 if (spdy_util_.spdy_version() >= SPDY4) { | |
4359 // SPDY4 doesn't support settings persistence. | |
4360 return; | |
4361 } | |
4362 static const SpdyHeaderInfo kSynReplyInfo = { | |
4363 SYN_REPLY, // Syn Reply | |
4364 1, // Stream ID | |
4365 0, // Associated Stream ID | |
4366 ConvertRequestPriorityToSpdyPriority( | |
4367 LOWEST, spdy_util_.spdy_version()), | |
4368 kSpdyCredentialSlotUnused, | |
4369 CONTROL_FLAG_NONE, // Control Flags | |
4370 false, // Compressed | |
4371 RST_STREAM_INVALID, // Status | |
4372 NULL, // Data | |
4373 0, // Data Length | |
4374 DATA_FLAG_NONE // Data Flags | |
4375 }; | |
4376 | |
4377 BoundNetLog net_log; | |
4378 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4379 net_log, GetParam(), NULL); | |
4380 helper.RunPreTestSetup(); | |
4381 | |
4382 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); | |
4383 | |
4384 SpdySessionPoolPeer pool_peer(spdy_session_pool); | |
4385 pool_peer.SetEnableSendingInitialData(true); | |
4386 | |
4387 // Verify that no settings exist initially. | |
4388 HostPortPair host_port_pair("www.google.com", helper.port()); | |
4389 EXPECT_TRUE(spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4390 host_port_pair).empty()); | |
4391 | |
4392 const SpdySettingsIds kSampleId1 = SETTINGS_MAX_CONCURRENT_STREAMS; | |
4393 unsigned int kSampleValue1 = 0x0a0a0a0a; | |
4394 const SpdySettingsIds kSampleId2 = SETTINGS_INITIAL_WINDOW_SIZE; | |
4395 unsigned int kSampleValue2 = 0x0c0c0c0c; | |
4396 | |
4397 // First add a persisted setting. | |
4398 spdy_session_pool->http_server_properties()->SetSpdySetting( | |
4399 host_port_pair, | |
4400 kSampleId1, | |
4401 SETTINGS_FLAG_PLEASE_PERSIST, | |
4402 kSampleValue1); | |
4403 | |
4404 // Next add another persisted setting. | |
4405 spdy_session_pool->http_server_properties()->SetSpdySetting( | |
4406 host_port_pair, | |
4407 kSampleId2, | |
4408 SETTINGS_FLAG_PLEASE_PERSIST, | |
4409 kSampleValue2); | |
4410 | |
4411 EXPECT_EQ(2u, spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4412 host_port_pair).size()); | |
4413 | |
4414 // Construct the initial SETTINGS frame. | |
4415 SettingsMap initial_settings; | |
4416 initial_settings[SETTINGS_MAX_CONCURRENT_STREAMS] = | |
4417 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, kMaxConcurrentPushedStreams); | |
4418 scoped_ptr<SpdyFrame> initial_settings_frame( | |
4419 spdy_util_.ConstructSpdySettings(initial_settings)); | |
4420 | |
4421 // Construct the initial window update. | |
4422 scoped_ptr<SpdyFrame> initial_window_update( | |
4423 spdy_util_.ConstructSpdyWindowUpdate( | |
4424 kSessionFlowControlStreamId, | |
4425 kDefaultInitialRecvWindowSize - | |
4426 SpdySession::GetInitialWindowSize(GetParam().protocol))); | |
4427 | |
4428 // Construct the persisted SETTINGS frame. | |
4429 const SettingsMap& settings = | |
4430 spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4431 host_port_pair); | |
4432 scoped_ptr<SpdyFrame> settings_frame( | |
4433 spdy_util_.ConstructSpdySettings(settings)); | |
4434 | |
4435 // Construct the request. | |
4436 scoped_ptr<SpdyFrame> req( | |
4437 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4438 | |
4439 std::vector<MockWrite> writes; | |
4440 if ((GetParam().protocol >= kProtoSPDY4MinimumVersion) && | |
4441 (GetParam().protocol <= kProtoSPDY4MaximumVersion)) { | |
4442 writes.push_back( | |
4443 MockWrite(ASYNC, | |
4444 kHttp2ConnectionHeaderPrefix, | |
4445 kHttp2ConnectionHeaderPrefixSize)); | |
4446 } | |
4447 writes.push_back(CreateMockWrite(*initial_settings_frame)); | |
4448 if (GetParam().protocol >= kProtoSPDY31) { | |
4449 writes.push_back(CreateMockWrite(*initial_window_update)); | |
4450 } | |
4451 writes.push_back(CreateMockWrite(*settings_frame)); | |
4452 writes.push_back(CreateMockWrite(*req)); | |
4453 | |
4454 // Construct the reply. | |
4455 scoped_ptr<SpdyHeaderBlock> reply_headers(new SpdyHeaderBlock()); | |
4456 (*reply_headers)[spdy_util_.GetStatusKey()] = "200"; | |
4457 (*reply_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1"; | |
4458 scoped_ptr<SpdyFrame> reply( | |
4459 spdy_util_.ConstructSpdyFrame(kSynReplyInfo, reply_headers.Pass())); | |
4460 | |
4461 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
4462 MockRead reads[] = { | |
4463 CreateMockRead(*reply), | |
4464 CreateMockRead(*body), | |
4465 MockRead(ASYNC, 0, 0) // EOF | |
4466 }; | |
4467 | |
4468 DelayedSocketData data(2, reads, arraysize(reads), | |
4469 vector_as_array(&writes), writes.size()); | |
4470 helper.AddData(&data); | |
4471 helper.RunDefaultTest(); | |
4472 helper.VerifyDataConsumed(); | |
4473 TransactionHelperResult out = helper.output(); | |
4474 EXPECT_EQ(OK, out.rv); | |
4475 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4476 EXPECT_EQ("hello!", out.response_data); | |
4477 | |
4478 { | |
4479 // Verify we had two persisted settings. | |
4480 const SettingsMap& settings_map = | |
4481 spdy_session_pool->http_server_properties()->GetSpdySettings( | |
4482 host_port_pair); | |
4483 ASSERT_EQ(2u, settings_map.size()); | |
4484 | |
4485 // Verify the first persisted setting. | |
4486 SettingsMap::const_iterator it1 = settings_map.find(kSampleId1); | |
4487 EXPECT_TRUE(it1 != settings_map.end()); | |
4488 SettingsFlagsAndValue flags_and_value1 = it1->second; | |
4489 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value1.first); | |
4490 EXPECT_EQ(kSampleValue1, flags_and_value1.second); | |
4491 | |
4492 // Verify the second persisted setting. | |
4493 SettingsMap::const_iterator it2 = settings_map.find(kSampleId2); | |
4494 EXPECT_TRUE(it2 != settings_map.end()); | |
4495 SettingsFlagsAndValue flags_and_value2 = it2->second; | |
4496 EXPECT_EQ(SETTINGS_FLAG_PERSISTED, flags_and_value2.first); | |
4497 EXPECT_EQ(kSampleValue2, flags_and_value2.second); | |
4498 } | |
4499 } | |
4500 | |
4501 TEST_P(SpdyNetworkTransactionTest, GoAwayWithActiveStream) { | |
4502 scoped_ptr<SpdyFrame> req( | |
4503 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4504 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4505 | |
4506 scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway()); | |
4507 MockRead reads[] = { | |
4508 CreateMockRead(*go_away), | |
4509 }; | |
4510 | |
4511 DelayedSocketData data(1, reads, arraysize(reads), | |
4512 writes, arraysize(writes)); | |
4513 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4514 BoundNetLog(), GetParam(), NULL); | |
4515 helper.AddData(&data); | |
4516 helper.RunToCompletion(&data); | |
4517 TransactionHelperResult out = helper.output(); | |
4518 EXPECT_EQ(ERR_ABORTED, out.rv); | |
4519 } | |
4520 | |
4521 TEST_P(SpdyNetworkTransactionTest, CloseWithActiveStream) { | |
4522 scoped_ptr<SpdyFrame> req( | |
4523 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4524 MockWrite writes[] = { CreateMockWrite(*req) }; | |
4525 | |
4526 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4527 MockRead reads[] = { | |
4528 CreateMockRead(*resp), | |
4529 MockRead(SYNCHRONOUS, 0, 0) // EOF | |
4530 }; | |
4531 | |
4532 DelayedSocketData data(1, reads, arraysize(reads), | |
4533 writes, arraysize(writes)); | |
4534 BoundNetLog log; | |
4535 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4536 log, GetParam(), NULL); | |
4537 helper.RunPreTestSetup(); | |
4538 helper.AddData(&data); | |
4539 HttpNetworkTransaction* trans = helper.trans(); | |
4540 | |
4541 TestCompletionCallback callback; | |
4542 TransactionHelperResult out; | |
4543 out.rv = trans->Start(&CreateGetRequest(), callback.callback(), log); | |
4544 | |
4545 EXPECT_EQ(out.rv, ERR_IO_PENDING); | |
4546 out.rv = callback.WaitForResult(); | |
4547 EXPECT_EQ(out.rv, OK); | |
4548 | |
4549 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4550 EXPECT_TRUE(response->headers.get() != NULL); | |
4551 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4552 out.rv = ReadTransaction(trans, &out.response_data); | |
4553 EXPECT_EQ(ERR_CONNECTION_CLOSED, out.rv); | |
4554 | |
4555 // Verify that we consumed all test data. | |
4556 helper.VerifyDataConsumed(); | |
4557 } | |
4558 | |
4559 // HTTP_1_1_REQUIRED results in ERR_HTTP_1_1_REQUIRED. | |
4560 TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredError) { | |
4561 // HTTP_1_1_REQUIRED is only supported by SPDY4. | |
4562 if (spdy_util_.spdy_version() < SPDY4) | |
4563 return; | |
4564 | |
4565 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4566 BoundNetLog(), GetParam(), nullptr); | |
4567 | |
4568 scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway( | |
4569 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please.")); | |
4570 MockRead reads[] = { | |
4571 CreateMockRead(*go_away), | |
4572 }; | |
4573 DelayedSocketData data(0, reads, arraysize(reads), nullptr, 0); | |
4574 | |
4575 helper.RunToCompletion(&data); | |
4576 TransactionHelperResult out = helper.output(); | |
4577 EXPECT_EQ(ERR_HTTP_1_1_REQUIRED, out.rv); | |
4578 } | |
4579 | |
4580 // Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual | |
4581 // protocol negotiation happens, instead this test forces protocols for both | |
4582 // sockets. | |
4583 TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredRetry) { | |
4584 // HTTP_1_1_REQUIRED is only supported by SPDY4. | |
4585 if (spdy_util_.spdy_version() < SPDY4) | |
4586 return; | |
4587 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is | |
4588 // only spoken over SSL. | |
4589 if (GetParam().ssl_type != SPDYSSL) | |
4590 return; | |
4591 | |
4592 HttpRequestInfo request; | |
4593 request.method = "GET"; | |
4594 request.url = GURL("https://www.google.com/"); | |
4595 scoped_ptr<SpdySessionDependencies> session_deps( | |
4596 CreateSpdySessionDependencies(GetParam())); | |
4597 // Do not force SPDY so that second socket can negotiate HTTP/1.1. | |
4598 session_deps->force_spdy_over_ssl = false; | |
4599 session_deps->force_spdy_always = false; | |
4600 session_deps->next_protos = SpdyNextProtos(); | |
4601 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), | |
4602 GetParam(), session_deps.release()); | |
4603 | |
4604 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED. | |
4605 const char* url = "https://www.google.com/"; | |
4606 scoped_ptr<SpdyHeaderBlock> headers(spdy_util_.ConstructGetHeaderBlock(url)); | |
4607 scoped_ptr<SpdyFrame> req( | |
4608 spdy_util_.ConstructSpdySyn(1, *headers, LOWEST, false, true)); | |
4609 MockWrite writes0[] = {CreateMockWrite(*req)}; | |
4610 scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway( | |
4611 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please.")); | |
4612 MockRead reads0[] = {CreateMockRead(*go_away)}; | |
4613 DelayedSocketData data0(1, reads0, arraysize(reads0), writes0, | |
4614 arraysize(writes0)); | |
4615 | |
4616 scoped_ptr<SSLSocketDataProvider> ssl_provider0( | |
4617 new SSLSocketDataProvider(ASYNC, OK)); | |
4618 // Expect HTTP/2 protocols too in SSLConfig. | |
4619 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11); | |
4620 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY31); | |
4621 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_14); | |
4622 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_15); | |
4623 // Force SPDY. | |
4624 ssl_provider0->SetNextProto(GetParam().protocol); | |
4625 helper.AddDataWithSSLSocketDataProvider(&data0, ssl_provider0.Pass()); | |
4626 | |
4627 // Second socket: falling back to HTTP/1.1. | |
4628 MockWrite writes1[] = {MockWrite( | |
4629 "GET / HTTP/1.1\r\n" | |
4630 "Host: www.google.com\r\n" | |
4631 "Connection: keep-alive\r\n\r\n")}; | |
4632 MockRead reads1[] = {MockRead( | |
4633 "HTTP/1.1 200 OK\r\n" | |
4634 "Content-Length: 5\r\n\r\n" | |
4635 "hello")}; | |
4636 DelayedSocketData data1(1, reads1, arraysize(reads1), writes1, | |
4637 arraysize(writes1)); | |
4638 | |
4639 scoped_ptr<SSLSocketDataProvider> ssl_provider1( | |
4640 new SSLSocketDataProvider(ASYNC, OK)); | |
4641 // Expect only HTTP/1.1 protocol in SSLConfig. | |
4642 ssl_provider1->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11); | |
4643 // Force HTTP/1.1. | |
4644 ssl_provider1->SetNextProto(kProtoHTTP11); | |
4645 helper.AddDataWithSSLSocketDataProvider(&data1, ssl_provider1.Pass()); | |
4646 | |
4647 base::WeakPtr<HttpServerProperties> http_server_properties = | |
4648 helper.session()->spdy_session_pool()->http_server_properties(); | |
4649 const HostPortPair host_port_pair = HostPortPair::FromURL(GURL(url)); | |
4650 EXPECT_FALSE(http_server_properties->RequiresHTTP11(host_port_pair)); | |
4651 | |
4652 helper.RunPreTestSetup(); | |
4653 helper.StartDefaultTest(); | |
4654 helper.FinishDefaultTestWithoutVerification(); | |
4655 helper.VerifyDataConsumed(); | |
4656 EXPECT_TRUE(http_server_properties->RequiresHTTP11(host_port_pair)); | |
4657 | |
4658 const HttpResponseInfo* response = helper.trans()->GetResponseInfo(); | |
4659 ASSERT_TRUE(response != nullptr); | |
4660 ASSERT_TRUE(response->headers.get() != nullptr); | |
4661 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
4662 EXPECT_FALSE(response->was_fetched_via_spdy); | |
4663 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1, response->connection_info); | |
4664 EXPECT_TRUE(response->was_npn_negotiated); | |
4665 EXPECT_TRUE(request.url.SchemeIs("https")); | |
4666 EXPECT_EQ("127.0.0.1", response->socket_address.host()); | |
4667 EXPECT_EQ(443, response->socket_address.port()); | |
4668 std::string response_data; | |
4669 ASSERT_EQ(OK, ReadTransaction(helper.trans(), &response_data)); | |
4670 EXPECT_EQ("hello", response_data); | |
4671 } | |
4672 | |
4673 // Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the | |
4674 // proxy. Note that no actual protocol negotiation happens, instead this test | |
4675 // forces protocols for both sockets. | |
4676 TEST_P(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) { | |
4677 // HTTP_1_1_REQUIRED is only supported by SPDY4. | |
4678 if (spdy_util_.spdy_version() < SPDY4) | |
4679 return; | |
4680 // HTTP_1_1_REQUIRED implementation relies on the assumption that HTTP/2 is | |
4681 // only spoken over SSL. | |
4682 if (GetParam().ssl_type != SPDYSSL) | |
4683 return; | |
4684 | |
4685 HttpRequestInfo request; | |
4686 request.method = "GET"; | |
4687 request.url = GURL("https://www.google.com/"); | |
4688 scoped_ptr<SpdySessionDependencies> session_deps( | |
4689 CreateSpdySessionDependencies( | |
4690 GetParam(), | |
4691 ProxyService::CreateFixedFromPacResult("HTTPS myproxy:70"))); | |
4692 // Do not force SPDY so that second socket can negotiate HTTP/1.1. | |
4693 session_deps->force_spdy_over_ssl = false; | |
4694 session_deps->force_spdy_always = false; | |
4695 session_deps->next_protos = SpdyNextProtos(); | |
4696 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, BoundNetLog(), | |
4697 GetParam(), session_deps.release()); | |
4698 | |
4699 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED. | |
4700 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyConnect( | |
4701 nullptr, 0, 1, LOWEST, HostPortPair("www.google.com", 443))); | |
4702 MockWrite writes0[] = {CreateMockWrite(*req)}; | |
4703 scoped_ptr<SpdyFrame> go_away(spdy_util_.ConstructSpdyGoAway( | |
4704 0, GOAWAY_HTTP_1_1_REQUIRED, "Try again using HTTP/1.1 please.")); | |
4705 MockRead reads0[] = {CreateMockRead(*go_away)}; | |
4706 DelayedSocketData data0(1, reads0, arraysize(reads0), writes0, | |
4707 arraysize(writes0)); | |
4708 | |
4709 scoped_ptr<SSLSocketDataProvider> ssl_provider0( | |
4710 new SSLSocketDataProvider(ASYNC, OK)); | |
4711 // Expect HTTP/2 protocols too in SSLConfig. | |
4712 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11); | |
4713 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY31); | |
4714 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_14); | |
4715 ssl_provider0->next_protos_expected_in_ssl_config.push_back(kProtoSPDY4_15); | |
4716 // Force SPDY. | |
4717 ssl_provider0->SetNextProto(GetParam().protocol); | |
4718 helper.AddDataWithSSLSocketDataProvider(&data0, ssl_provider0.Pass()); | |
4719 | |
4720 // Second socket: retry using HTTP/1.1. | |
4721 MockWrite writes1[] = { | |
4722 MockWrite(ASYNC, 1, | |
4723 "CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4724 "Host: www.google.com\r\n" | |
4725 "Proxy-Connection: keep-alive\r\n\r\n"), | |
4726 MockWrite(ASYNC, 3, | |
4727 "GET / HTTP/1.1\r\n" | |
4728 "Host: www.google.com\r\n" | |
4729 "Connection: keep-alive\r\n\r\n"), | |
4730 }; | |
4731 | |
4732 MockRead reads1[] = { | |
4733 MockRead(ASYNC, 2, "HTTP/1.1 200 OK\r\n\r\n"), | |
4734 MockRead(ASYNC, 4, | |
4735 "HTTP/1.1 200 OK\r\n" | |
4736 "Content-Length: 5\r\n\r\n" | |
4737 "hello"), | |
4738 }; | |
4739 DelayedSocketData data1(1, reads1, arraysize(reads1), writes1, | |
4740 arraysize(writes1)); | |
4741 | |
4742 scoped_ptr<SSLSocketDataProvider> ssl_provider1( | |
4743 new SSLSocketDataProvider(ASYNC, OK)); | |
4744 // Expect only HTTP/1.1 protocol in SSLConfig. | |
4745 ssl_provider1->next_protos_expected_in_ssl_config.push_back(kProtoHTTP11); | |
4746 // Force HTTP/1.1. | |
4747 ssl_provider1->SetNextProto(kProtoHTTP11); | |
4748 helper.AddDataWithSSLSocketDataProvider(&data1, ssl_provider1.Pass()); | |
4749 | |
4750 // A third socket is needed for the tunnelled connection. | |
4751 scoped_ptr<SSLSocketDataProvider> ssl_provider2( | |
4752 new SSLSocketDataProvider(ASYNC, OK)); | |
4753 helper.session_deps()->socket_factory->AddSSLSocketDataProvider( | |
4754 ssl_provider2.get()); | |
4755 | |
4756 base::WeakPtr<HttpServerProperties> http_server_properties = | |
4757 helper.session()->spdy_session_pool()->http_server_properties(); | |
4758 const HostPortPair proxy_host_port_pair = HostPortPair("myproxy", 70); | |
4759 EXPECT_FALSE(http_server_properties->RequiresHTTP11(proxy_host_port_pair)); | |
4760 | |
4761 helper.RunPreTestSetup(); | |
4762 helper.StartDefaultTest(); | |
4763 helper.FinishDefaultTestWithoutVerification(); | |
4764 helper.VerifyDataConsumed(); | |
4765 EXPECT_TRUE(http_server_properties->RequiresHTTP11(proxy_host_port_pair)); | |
4766 | |
4767 const HttpResponseInfo* response = helper.trans()->GetResponseInfo(); | |
4768 ASSERT_TRUE(response != nullptr); | |
4769 ASSERT_TRUE(response->headers.get() != nullptr); | |
4770 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
4771 EXPECT_FALSE(response->was_fetched_via_spdy); | |
4772 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1, response->connection_info); | |
4773 EXPECT_FALSE(response->was_npn_negotiated); | |
4774 EXPECT_TRUE(request.url.SchemeIs("https")); | |
4775 EXPECT_EQ("127.0.0.1", response->socket_address.host()); | |
4776 EXPECT_EQ(70, response->socket_address.port()); | |
4777 std::string response_data; | |
4778 ASSERT_EQ(OK, ReadTransaction(helper.trans(), &response_data)); | |
4779 EXPECT_EQ("hello", response_data); | |
4780 } | |
4781 | |
4782 // Test to make sure we can correctly connect through a proxy. | |
4783 TEST_P(SpdyNetworkTransactionTest, ProxyConnect) { | |
4784 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4785 BoundNetLog(), GetParam(), NULL); | |
4786 helper.session_deps().reset(CreateSpdySessionDependencies( | |
4787 GetParam(), | |
4788 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70"))); | |
4789 helper.SetSession(make_scoped_refptr( | |
4790 SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get()))); | |
4791 helper.RunPreTestSetup(); | |
4792 HttpNetworkTransaction* trans = helper.trans(); | |
4793 | |
4794 const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4795 "Host: www.google.com\r\n" | |
4796 "Proxy-Connection: keep-alive\r\n\r\n"}; | |
4797 const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n" | |
4798 "Host: www.google.com\r\n" | |
4799 "Proxy-Connection: keep-alive\r\n\r\n"}; | |
4800 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"}; | |
4801 scoped_ptr<SpdyFrame> req( | |
4802 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4803 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4804 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
4805 | |
4806 MockWrite writes_SPDYNPN[] = { | |
4807 MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0), | |
4808 CreateMockWrite(*req, 2), | |
4809 }; | |
4810 MockRead reads_SPDYNPN[] = { | |
4811 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), | |
4812 CreateMockRead(*resp, 3), | |
4813 CreateMockRead(*body.get(), 4), | |
4814 MockRead(ASYNC, 0, 0, 5), | |
4815 }; | |
4816 | |
4817 MockWrite writes_SPDYSSL[] = { | |
4818 MockWrite(SYNCHRONOUS, kConnect80, arraysize(kConnect80) - 1, 0), | |
4819 CreateMockWrite(*req, 2), | |
4820 }; | |
4821 MockRead reads_SPDYSSL[] = { | |
4822 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), | |
4823 CreateMockRead(*resp, 3), | |
4824 CreateMockRead(*body.get(), 4), | |
4825 MockRead(ASYNC, 0, 0, 5), | |
4826 }; | |
4827 | |
4828 MockWrite writes_SPDYNOSSL[] = { | |
4829 CreateMockWrite(*req, 0), | |
4830 }; | |
4831 | |
4832 MockRead reads_SPDYNOSSL[] = { | |
4833 CreateMockRead(*resp, 1), | |
4834 CreateMockRead(*body.get(), 2), | |
4835 MockRead(ASYNC, 0, 0, 3), | |
4836 }; | |
4837 | |
4838 scoped_ptr<OrderedSocketData> data; | |
4839 switch (GetParam().ssl_type) { | |
4840 case SPDYNOSSL: | |
4841 data.reset(new OrderedSocketData(reads_SPDYNOSSL, | |
4842 arraysize(reads_SPDYNOSSL), | |
4843 writes_SPDYNOSSL, | |
4844 arraysize(writes_SPDYNOSSL))); | |
4845 break; | |
4846 case SPDYSSL: | |
4847 data.reset(new OrderedSocketData(reads_SPDYSSL, | |
4848 arraysize(reads_SPDYSSL), | |
4849 writes_SPDYSSL, | |
4850 arraysize(writes_SPDYSSL))); | |
4851 break; | |
4852 case SPDYNPN: | |
4853 data.reset(new OrderedSocketData(reads_SPDYNPN, | |
4854 arraysize(reads_SPDYNPN), | |
4855 writes_SPDYNPN, | |
4856 arraysize(writes_SPDYNPN))); | |
4857 break; | |
4858 default: | |
4859 NOTREACHED(); | |
4860 } | |
4861 | |
4862 helper.AddData(data.get()); | |
4863 TestCompletionCallback callback; | |
4864 | |
4865 int rv = trans->Start( | |
4866 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4867 EXPECT_EQ(ERR_IO_PENDING, rv); | |
4868 | |
4869 rv = callback.WaitForResult(); | |
4870 EXPECT_EQ(0, rv); | |
4871 | |
4872 // Verify the SYN_REPLY. | |
4873 HttpResponseInfo response = *trans->GetResponseInfo(); | |
4874 EXPECT_TRUE(response.headers.get() != NULL); | |
4875 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
4876 | |
4877 std::string response_data; | |
4878 ASSERT_EQ(OK, ReadTransaction(trans, &response_data)); | |
4879 EXPECT_EQ("hello!", response_data); | |
4880 helper.VerifyDataConsumed(); | |
4881 } | |
4882 | |
4883 // Test to make sure we can correctly connect through a proxy to www.google.com, | |
4884 // if there already exists a direct spdy connection to www.google.com. See | |
4885 // http://crbug.com/49874 | |
4886 TEST_P(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) { | |
4887 // When setting up the first transaction, we store the SpdySessionPool so that | |
4888 // we can use the same pool in the second transaction. | |
4889 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
4890 BoundNetLog(), GetParam(), NULL); | |
4891 | |
4892 // Use a proxy service which returns a proxy fallback list from DIRECT to | |
4893 // myproxy:70. For this test there will be no fallback, so it is equivalent | |
4894 // to simply DIRECT. The reason for appending the second proxy is to verify | |
4895 // that the session pool key used does is just "DIRECT". | |
4896 helper.session_deps().reset(CreateSpdySessionDependencies( | |
4897 GetParam(), | |
4898 ProxyService::CreateFixedFromPacResult("DIRECT; PROXY myproxy:70"))); | |
4899 helper.SetSession(make_scoped_refptr( | |
4900 SpdySessionDependencies::SpdyCreateSession(helper.session_deps().get()))); | |
4901 | |
4902 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool(); | |
4903 helper.RunPreTestSetup(); | |
4904 | |
4905 // Construct and send a simple GET request. | |
4906 scoped_ptr<SpdyFrame> req( | |
4907 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
4908 MockWrite writes[] = { | |
4909 CreateMockWrite(*req, 1), | |
4910 }; | |
4911 | |
4912 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4913 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
4914 MockRead reads[] = { | |
4915 CreateMockRead(*resp, 2), | |
4916 CreateMockRead(*body, 3), | |
4917 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause | |
4918 MockRead(ASYNC, 0, 5) // EOF | |
4919 }; | |
4920 OrderedSocketData data(reads, arraysize(reads), | |
4921 writes, arraysize(writes)); | |
4922 helper.AddData(&data); | |
4923 HttpNetworkTransaction* trans = helper.trans(); | |
4924 | |
4925 TestCompletionCallback callback; | |
4926 TransactionHelperResult out; | |
4927 out.rv = trans->Start( | |
4928 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
4929 | |
4930 EXPECT_EQ(out.rv, ERR_IO_PENDING); | |
4931 out.rv = callback.WaitForResult(); | |
4932 EXPECT_EQ(out.rv, OK); | |
4933 | |
4934 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
4935 EXPECT_TRUE(response->headers.get() != NULL); | |
4936 EXPECT_TRUE(response->was_fetched_via_spdy); | |
4937 out.rv = ReadTransaction(trans, &out.response_data); | |
4938 EXPECT_EQ(OK, out.rv); | |
4939 out.status_line = response->headers->GetStatusLine(); | |
4940 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
4941 EXPECT_EQ("hello!", out.response_data); | |
4942 | |
4943 // Check that the SpdySession is still in the SpdySessionPool. | |
4944 HostPortPair host_port_pair("www.google.com", helper.port()); | |
4945 SpdySessionKey session_pool_key_direct( | |
4946 host_port_pair, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); | |
4947 EXPECT_TRUE(HasSpdySession(spdy_session_pool, session_pool_key_direct)); | |
4948 SpdySessionKey session_pool_key_proxy( | |
4949 host_port_pair, | |
4950 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP), | |
4951 PRIVACY_MODE_DISABLED); | |
4952 EXPECT_FALSE(HasSpdySession(spdy_session_pool, session_pool_key_proxy)); | |
4953 | |
4954 // Set up data for the proxy connection. | |
4955 const char kConnect443[] = {"CONNECT www.google.com:443 HTTP/1.1\r\n" | |
4956 "Host: www.google.com\r\n" | |
4957 "Proxy-Connection: keep-alive\r\n\r\n"}; | |
4958 const char kConnect80[] = {"CONNECT www.google.com:80 HTTP/1.1\r\n" | |
4959 "Host: www.google.com\r\n" | |
4960 "Proxy-Connection: keep-alive\r\n\r\n"}; | |
4961 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"}; | |
4962 scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyGet( | |
4963 "http://www.google.com/foo.dat", false, 1, LOWEST)); | |
4964 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
4965 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
4966 | |
4967 MockWrite writes_SPDYNPN[] = { | |
4968 MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0), | |
4969 CreateMockWrite(*req2, 2), | |
4970 }; | |
4971 MockRead reads_SPDYNPN[] = { | |
4972 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), | |
4973 CreateMockRead(*resp2, 3), | |
4974 CreateMockRead(*body2, 4), | |
4975 MockRead(ASYNC, 0, 5) // EOF | |
4976 }; | |
4977 | |
4978 MockWrite writes_SPDYNOSSL[] = { | |
4979 CreateMockWrite(*req2, 0), | |
4980 }; | |
4981 MockRead reads_SPDYNOSSL[] = { | |
4982 CreateMockRead(*resp2, 1), | |
4983 CreateMockRead(*body2, 2), | |
4984 MockRead(ASYNC, 0, 3) // EOF | |
4985 }; | |
4986 | |
4987 MockWrite writes_SPDYSSL[] = { | |
4988 MockWrite(SYNCHRONOUS, kConnect80, arraysize(kConnect80) - 1, 0), | |
4989 CreateMockWrite(*req2, 2), | |
4990 }; | |
4991 MockRead reads_SPDYSSL[] = { | |
4992 MockRead(SYNCHRONOUS, kHTTP200, arraysize(kHTTP200) - 1, 1), | |
4993 CreateMockRead(*resp2, 3), | |
4994 CreateMockRead(*body2, 4), | |
4995 MockRead(ASYNC, 0, 0, 5), | |
4996 }; | |
4997 | |
4998 scoped_ptr<OrderedSocketData> data_proxy; | |
4999 switch (GetParam().ssl_type) { | |
5000 case SPDYNPN: | |
5001 data_proxy.reset(new OrderedSocketData(reads_SPDYNPN, | |
5002 arraysize(reads_SPDYNPN), | |
5003 writes_SPDYNPN, | |
5004 arraysize(writes_SPDYNPN))); | |
5005 break; | |
5006 case SPDYNOSSL: | |
5007 data_proxy.reset(new OrderedSocketData(reads_SPDYNOSSL, | |
5008 arraysize(reads_SPDYNOSSL), | |
5009 writes_SPDYNOSSL, | |
5010 arraysize(writes_SPDYNOSSL))); | |
5011 break; | |
5012 case SPDYSSL: | |
5013 data_proxy.reset(new OrderedSocketData(reads_SPDYSSL, | |
5014 arraysize(reads_SPDYSSL), | |
5015 writes_SPDYSSL, | |
5016 arraysize(writes_SPDYSSL))); | |
5017 break; | |
5018 default: | |
5019 NOTREACHED(); | |
5020 } | |
5021 | |
5022 // Create another request to www.google.com, but this time through a proxy. | |
5023 HttpRequestInfo request_proxy; | |
5024 request_proxy.method = "GET"; | |
5025 request_proxy.url = GURL("http://www.google.com/foo.dat"); | |
5026 request_proxy.load_flags = 0; | |
5027 scoped_ptr<SpdySessionDependencies> ssd_proxy( | |
5028 CreateSpdySessionDependencies(GetParam())); | |
5029 // Ensure that this transaction uses the same SpdySessionPool. | |
5030 scoped_refptr<HttpNetworkSession> session_proxy( | |
5031 SpdySessionDependencies::SpdyCreateSession(ssd_proxy.get())); | |
5032 NormalSpdyTransactionHelper helper_proxy(request_proxy, DEFAULT_PRIORITY, | |
5033 BoundNetLog(), GetParam(), NULL); | |
5034 HttpNetworkSessionPeer session_peer(session_proxy); | |
5035 scoped_ptr<net::ProxyService> proxy_service( | |
5036 ProxyService::CreateFixedFromPacResult("PROXY myproxy:70")); | |
5037 session_peer.SetProxyService(proxy_service.get()); | |
5038 helper_proxy.session_deps().swap(ssd_proxy); | |
5039 helper_proxy.SetSession(session_proxy); | |
5040 helper_proxy.RunPreTestSetup(); | |
5041 helper_proxy.AddData(data_proxy.get()); | |
5042 | |
5043 HttpNetworkTransaction* trans_proxy = helper_proxy.trans(); | |
5044 TestCompletionCallback callback_proxy; | |
5045 int rv = trans_proxy->Start( | |
5046 &request_proxy, callback_proxy.callback(), BoundNetLog()); | |
5047 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5048 rv = callback_proxy.WaitForResult(); | |
5049 EXPECT_EQ(0, rv); | |
5050 | |
5051 HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo(); | |
5052 EXPECT_TRUE(response_proxy.headers.get() != NULL); | |
5053 EXPECT_EQ("HTTP/1.1 200 OK", response_proxy.headers->GetStatusLine()); | |
5054 | |
5055 std::string response_data; | |
5056 ASSERT_EQ(OK, ReadTransaction(trans_proxy, &response_data)); | |
5057 EXPECT_EQ("hello!", response_data); | |
5058 | |
5059 data.CompleteRead(); | |
5060 helper_proxy.VerifyDataConsumed(); | |
5061 } | |
5062 | |
5063 // When we get a TCP-level RST, we need to retry a HttpNetworkTransaction | |
5064 // on a new connection, if the connection was previously known to be good. | |
5065 // This can happen when a server reboots without saying goodbye, or when | |
5066 // we're behind a NAT that masked the RST. | |
5067 TEST_P(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) { | |
5068 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5069 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
5070 MockRead reads[] = { | |
5071 CreateMockRead(*resp), | |
5072 CreateMockRead(*body), | |
5073 MockRead(ASYNC, ERR_IO_PENDING), | |
5074 MockRead(ASYNC, ERR_CONNECTION_RESET), | |
5075 }; | |
5076 | |
5077 MockRead reads2[] = { | |
5078 CreateMockRead(*resp), | |
5079 CreateMockRead(*body), | |
5080 MockRead(ASYNC, 0, 0) // EOF | |
5081 }; | |
5082 | |
5083 // This test has a couple of variants. | |
5084 enum { | |
5085 // Induce the RST while waiting for our transaction to send. | |
5086 VARIANT_RST_DURING_SEND_COMPLETION, | |
5087 // Induce the RST while waiting for our transaction to read. | |
5088 // In this case, the send completed - everything copied into the SNDBUF. | |
5089 VARIANT_RST_DURING_READ_COMPLETION | |
5090 }; | |
5091 | |
5092 for (int variant = VARIANT_RST_DURING_SEND_COMPLETION; | |
5093 variant <= VARIANT_RST_DURING_READ_COMPLETION; | |
5094 ++variant) { | |
5095 DelayedSocketData data1(1, reads, arraysize(reads), NULL, 0); | |
5096 | |
5097 DelayedSocketData data2(1, reads2, arraysize(reads2), NULL, 0); | |
5098 | |
5099 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
5100 BoundNetLog(), GetParam(), NULL); | |
5101 helper.AddData(&data1); | |
5102 helper.AddData(&data2); | |
5103 helper.RunPreTestSetup(); | |
5104 | |
5105 for (int i = 0; i < 2; ++i) { | |
5106 scoped_ptr<HttpNetworkTransaction> trans( | |
5107 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
5108 | |
5109 TestCompletionCallback callback; | |
5110 int rv = trans->Start( | |
5111 &helper.request(), callback.callback(), BoundNetLog()); | |
5112 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5113 // On the second transaction, we trigger the RST. | |
5114 if (i == 1) { | |
5115 if (variant == VARIANT_RST_DURING_READ_COMPLETION) { | |
5116 // Writes to the socket complete asynchronously on SPDY by running | |
5117 // through the message loop. Complete the write here. | |
5118 base::RunLoop().RunUntilIdle(); | |
5119 } | |
5120 | |
5121 // Now schedule the ERR_CONNECTION_RESET. | |
5122 EXPECT_EQ(3u, data1.read_index()); | |
5123 data1.CompleteRead(); | |
5124 EXPECT_EQ(4u, data1.read_index()); | |
5125 } | |
5126 rv = callback.WaitForResult(); | |
5127 EXPECT_EQ(OK, rv); | |
5128 | |
5129 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
5130 ASSERT_TRUE(response != NULL); | |
5131 EXPECT_TRUE(response->headers.get() != NULL); | |
5132 EXPECT_TRUE(response->was_fetched_via_spdy); | |
5133 std::string response_data; | |
5134 rv = ReadTransaction(trans.get(), &response_data); | |
5135 EXPECT_EQ(OK, rv); | |
5136 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
5137 EXPECT_EQ("hello!", response_data); | |
5138 } | |
5139 | |
5140 helper.VerifyDataConsumed(); | |
5141 } | |
5142 } | |
5143 | |
5144 // Test that turning SPDY on and off works properly. | |
5145 TEST_P(SpdyNetworkTransactionTest, SpdyOnOffToggle) { | |
5146 HttpStreamFactory::set_spdy_enabled(true); | |
5147 scoped_ptr<SpdyFrame> req( | |
5148 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
5149 MockWrite spdy_writes[] = { CreateMockWrite(*req) }; | |
5150 | |
5151 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5152 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
5153 MockRead spdy_reads[] = { | |
5154 CreateMockRead(*resp), | |
5155 CreateMockRead(*body), | |
5156 MockRead(ASYNC, 0, 0) // EOF | |
5157 }; | |
5158 | |
5159 DelayedSocketData data(1, spdy_reads, arraysize(spdy_reads), | |
5160 spdy_writes, arraysize(spdy_writes)); | |
5161 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
5162 BoundNetLog(), GetParam(), NULL); | |
5163 helper.RunToCompletion(&data); | |
5164 TransactionHelperResult out = helper.output(); | |
5165 EXPECT_EQ(OK, out.rv); | |
5166 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
5167 EXPECT_EQ("hello!", out.response_data); | |
5168 | |
5169 net::HttpStreamFactory::set_spdy_enabled(false); | |
5170 MockRead http_reads[] = { | |
5171 MockRead("HTTP/1.1 200 OK\r\n\r\n"), | |
5172 MockRead("hello from http"), | |
5173 MockRead(SYNCHRONOUS, OK), | |
5174 }; | |
5175 DelayedSocketData data2(1, http_reads, arraysize(http_reads), NULL, 0); | |
5176 NormalSpdyTransactionHelper helper2(CreateGetRequest(), DEFAULT_PRIORITY, | |
5177 BoundNetLog(), GetParam(), NULL); | |
5178 helper2.SetSpdyDisabled(); | |
5179 helper2.RunToCompletion(&data2); | |
5180 TransactionHelperResult out2 = helper2.output(); | |
5181 EXPECT_EQ(OK, out2.rv); | |
5182 EXPECT_EQ("HTTP/1.1 200 OK", out2.status_line); | |
5183 EXPECT_EQ("hello from http", out2.response_data); | |
5184 | |
5185 net::HttpStreamFactory::set_spdy_enabled(true); | |
5186 } | |
5187 | |
5188 // Tests that Basic authentication works over SPDY | |
5189 TEST_P(SpdyNetworkTransactionTest, SpdyBasicAuth) { | |
5190 net::HttpStreamFactory::set_spdy_enabled(true); | |
5191 | |
5192 // The first request will be a bare GET, the second request will be a | |
5193 // GET with an Authorization header. | |
5194 scoped_ptr<SpdyFrame> req_get( | |
5195 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
5196 const char* const kExtraAuthorizationHeaders[] = { | |
5197 "authorization", "Basic Zm9vOmJhcg==" | |
5198 }; | |
5199 scoped_ptr<SpdyFrame> req_get_authorization( | |
5200 spdy_util_.ConstructSpdyGet(kExtraAuthorizationHeaders, | |
5201 arraysize(kExtraAuthorizationHeaders) / 2, | |
5202 false, 3, LOWEST, true)); | |
5203 MockWrite spdy_writes[] = { | |
5204 CreateMockWrite(*req_get, 1), | |
5205 CreateMockWrite(*req_get_authorization, 4), | |
5206 }; | |
5207 | |
5208 // The first response is a 401 authentication challenge, and the second | |
5209 // response will be a 200 response since the second request includes a valid | |
5210 // Authorization header. | |
5211 const char* const kExtraAuthenticationHeaders[] = { | |
5212 "www-authenticate", | |
5213 "Basic realm=\"MyRealm\"" | |
5214 }; | |
5215 scoped_ptr<SpdyFrame> resp_authentication( | |
5216 spdy_util_.ConstructSpdySynReplyError( | |
5217 "401 Authentication Required", | |
5218 kExtraAuthenticationHeaders, | |
5219 arraysize(kExtraAuthenticationHeaders) / 2, | |
5220 1)); | |
5221 scoped_ptr<SpdyFrame> body_authentication( | |
5222 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
5223 scoped_ptr<SpdyFrame> resp_data( | |
5224 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
5225 scoped_ptr<SpdyFrame> body_data(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
5226 MockRead spdy_reads[] = { | |
5227 CreateMockRead(*resp_authentication, 2), | |
5228 CreateMockRead(*body_authentication, 3), | |
5229 CreateMockRead(*resp_data, 5), | |
5230 CreateMockRead(*body_data, 6), | |
5231 MockRead(ASYNC, 0, 7), | |
5232 }; | |
5233 | |
5234 OrderedSocketData data(spdy_reads, arraysize(spdy_reads), | |
5235 spdy_writes, arraysize(spdy_writes)); | |
5236 HttpRequestInfo request(CreateGetRequest()); | |
5237 BoundNetLog net_log; | |
5238 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
5239 net_log, GetParam(), NULL); | |
5240 | |
5241 helper.RunPreTestSetup(); | |
5242 helper.AddData(&data); | |
5243 HttpNetworkTransaction* trans = helper.trans(); | |
5244 TestCompletionCallback callback; | |
5245 const int rv_start = trans->Start(&request, callback.callback(), net_log); | |
5246 EXPECT_EQ(ERR_IO_PENDING, rv_start); | |
5247 const int rv_start_complete = callback.WaitForResult(); | |
5248 EXPECT_EQ(OK, rv_start_complete); | |
5249 | |
5250 // Make sure the response has an auth challenge. | |
5251 const HttpResponseInfo* const response_start = trans->GetResponseInfo(); | |
5252 ASSERT_TRUE(response_start != NULL); | |
5253 ASSERT_TRUE(response_start->headers.get() != NULL); | |
5254 EXPECT_EQ(401, response_start->headers->response_code()); | |
5255 EXPECT_TRUE(response_start->was_fetched_via_spdy); | |
5256 AuthChallengeInfo* auth_challenge = response_start->auth_challenge.get(); | |
5257 ASSERT_TRUE(auth_challenge != NULL); | |
5258 EXPECT_FALSE(auth_challenge->is_proxy); | |
5259 EXPECT_EQ("basic", auth_challenge->scheme); | |
5260 EXPECT_EQ("MyRealm", auth_challenge->realm); | |
5261 | |
5262 // Restart with a username/password. | |
5263 AuthCredentials credentials(base::ASCIIToUTF16("foo"), | |
5264 base::ASCIIToUTF16("bar")); | |
5265 TestCompletionCallback callback_restart; | |
5266 const int rv_restart = trans->RestartWithAuth( | |
5267 credentials, callback_restart.callback()); | |
5268 EXPECT_EQ(ERR_IO_PENDING, rv_restart); | |
5269 const int rv_restart_complete = callback_restart.WaitForResult(); | |
5270 EXPECT_EQ(OK, rv_restart_complete); | |
5271 // TODO(cbentzel): This is actually the same response object as before, but | |
5272 // data has changed. | |
5273 const HttpResponseInfo* const response_restart = trans->GetResponseInfo(); | |
5274 ASSERT_TRUE(response_restart != NULL); | |
5275 ASSERT_TRUE(response_restart->headers.get() != NULL); | |
5276 EXPECT_EQ(200, response_restart->headers->response_code()); | |
5277 EXPECT_TRUE(response_restart->auth_challenge.get() == NULL); | |
5278 } | |
5279 | |
5280 TEST_P(SpdyNetworkTransactionTest, ServerPushWithHeaders) { | |
5281 scoped_ptr<SpdyFrame> stream1_syn( | |
5282 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
5283 scoped_ptr<SpdyFrame> stream1_body( | |
5284 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
5285 MockWrite writes[] = { | |
5286 CreateMockWrite(*stream1_syn, 1), | |
5287 }; | |
5288 | |
5289 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock()); | |
5290 spdy_util_.AddUrlToHeaderBlock( | |
5291 "http://www.google.com/foo.dat", initial_headers.get()); | |
5292 scoped_ptr<SpdyFrame> stream2_syn( | |
5293 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1)); | |
5294 | |
5295 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock()); | |
5296 (*late_headers)["hello"] = "bye"; | |
5297 (*late_headers)[spdy_util_.GetStatusKey()] = "200"; | |
5298 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1"; | |
5299 scoped_ptr<SpdyFrame> stream2_headers( | |
5300 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(), | |
5301 false, | |
5302 2, | |
5303 LOWEST, | |
5304 HEADERS, | |
5305 CONTROL_FLAG_NONE, | |
5306 0)); | |
5307 | |
5308 scoped_ptr<SpdyFrame> | |
5309 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5310 const char kPushedData[] = "pushed"; | |
5311 scoped_ptr<SpdyFrame> stream2_body( | |
5312 spdy_util_.ConstructSpdyBodyFrame( | |
5313 2, kPushedData, strlen(kPushedData), true)); | |
5314 MockRead reads[] = { | |
5315 CreateMockRead(*stream1_reply, 2), | |
5316 CreateMockRead(*stream2_syn, 3), | |
5317 CreateMockRead(*stream2_headers, 4), | |
5318 CreateMockRead(*stream1_body, 5, SYNCHRONOUS), | |
5319 CreateMockRead(*stream2_body, 5), | |
5320 MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause | |
5321 }; | |
5322 | |
5323 HttpResponseInfo response; | |
5324 HttpResponseInfo response2; | |
5325 std::string expected_push_result("pushed"); | |
5326 OrderedSocketData data(reads, arraysize(reads), | |
5327 writes, arraysize(writes)); | |
5328 RunServerPushTest(&data, | |
5329 &response, | |
5330 &response2, | |
5331 expected_push_result); | |
5332 | |
5333 // Verify the SYN_REPLY. | |
5334 EXPECT_TRUE(response.headers.get() != NULL); | |
5335 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
5336 | |
5337 // Verify the pushed stream. | |
5338 EXPECT_TRUE(response2.headers.get() != NULL); | |
5339 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
5340 } | |
5341 | |
5342 TEST_P(SpdyNetworkTransactionTest, ServerPushClaimBeforeHeaders) { | |
5343 // We push a stream and attempt to claim it before the headers come down. | |
5344 scoped_ptr<SpdyFrame> stream1_syn( | |
5345 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
5346 scoped_ptr<SpdyFrame> stream1_body( | |
5347 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
5348 MockWrite writes[] = { | |
5349 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS), | |
5350 }; | |
5351 | |
5352 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock()); | |
5353 spdy_util_.AddUrlToHeaderBlock( | |
5354 "http://www.google.com/foo.dat", initial_headers.get()); | |
5355 scoped_ptr<SpdyFrame> stream2_syn( | |
5356 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1)); | |
5357 | |
5358 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock()); | |
5359 (*late_headers)["hello"] = "bye"; | |
5360 (*late_headers)[spdy_util_.GetStatusKey()] = "200"; | |
5361 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1"; | |
5362 scoped_ptr<SpdyFrame> stream2_headers( | |
5363 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(), | |
5364 false, | |
5365 2, | |
5366 LOWEST, | |
5367 HEADERS, | |
5368 CONTROL_FLAG_NONE, | |
5369 0)); | |
5370 | |
5371 scoped_ptr<SpdyFrame> | |
5372 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5373 const char kPushedData[] = "pushed"; | |
5374 scoped_ptr<SpdyFrame> stream2_body( | |
5375 spdy_util_.ConstructSpdyBodyFrame( | |
5376 2, kPushedData, strlen(kPushedData), true)); | |
5377 MockRead reads[] = { | |
5378 CreateMockRead(*stream1_reply, 1), | |
5379 CreateMockRead(*stream2_syn, 2), | |
5380 CreateMockRead(*stream1_body, 3), | |
5381 CreateMockRead(*stream2_headers, 4), | |
5382 CreateMockRead(*stream2_body, 5), | |
5383 MockRead(ASYNC, 0, 6), // EOF | |
5384 }; | |
5385 | |
5386 HttpResponseInfo response; | |
5387 HttpResponseInfo response2; | |
5388 std::string expected_push_result("pushed"); | |
5389 DeterministicSocketData data(reads, arraysize(reads), | |
5390 writes, arraysize(writes)); | |
5391 | |
5392 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
5393 BoundNetLog(), GetParam(), NULL); | |
5394 helper.SetDeterministic(); | |
5395 helper.AddDeterministicData(&data); | |
5396 helper.RunPreTestSetup(); | |
5397 | |
5398 HttpNetworkTransaction* trans = helper.trans(); | |
5399 | |
5400 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM, | |
5401 // and the body of the primary stream, but before we've received the HEADERS | |
5402 // for the pushed stream. | |
5403 data.SetStop(3); | |
5404 | |
5405 // Start the transaction. | |
5406 TestCompletionCallback callback; | |
5407 int rv = trans->Start( | |
5408 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
5409 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5410 data.Run(); | |
5411 rv = callback.WaitForResult(); | |
5412 EXPECT_EQ(0, rv); | |
5413 | |
5414 // Request the pushed path. At this point, we've received the push, but the | |
5415 // headers are not yet complete. | |
5416 scoped_ptr<HttpNetworkTransaction> trans2( | |
5417 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
5418 rv = trans2->Start( | |
5419 &CreateGetPushRequest(), callback.callback(), BoundNetLog()); | |
5420 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5421 data.RunFor(3); | |
5422 base::RunLoop().RunUntilIdle(); | |
5423 | |
5424 // Read the server push body. | |
5425 std::string result2; | |
5426 ReadResult(trans2.get(), &data, &result2); | |
5427 // Read the response body. | |
5428 std::string result; | |
5429 ReadResult(trans, &data, &result); | |
5430 | |
5431 // Verify that the received push data is same as the expected push data. | |
5432 EXPECT_EQ(result2.compare(expected_push_result), 0) | |
5433 << "Received data: " | |
5434 << result2 | |
5435 << "||||| Expected data: " | |
5436 << expected_push_result; | |
5437 | |
5438 // Verify the SYN_REPLY. | |
5439 // Copy the response info, because trans goes away. | |
5440 response = *trans->GetResponseInfo(); | |
5441 response2 = *trans2->GetResponseInfo(); | |
5442 | |
5443 VerifyStreamsClosed(helper); | |
5444 | |
5445 // Verify the SYN_REPLY. | |
5446 EXPECT_TRUE(response.headers.get() != NULL); | |
5447 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
5448 | |
5449 // Verify the pushed stream. | |
5450 EXPECT_TRUE(response2.headers.get() != NULL); | |
5451 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
5452 | |
5453 // Read the final EOF (which will close the session) | |
5454 data.RunFor(1); | |
5455 | |
5456 // Verify that we consumed all test data. | |
5457 EXPECT_TRUE(data.at_read_eof()); | |
5458 EXPECT_TRUE(data.at_write_eof()); | |
5459 } | |
5460 | |
5461 // TODO(baranovich): HTTP 2 does not allow multiple HEADERS frames | |
5462 TEST_P(SpdyNetworkTransactionTest, ServerPushWithTwoHeaderFrames) { | |
5463 // We push a stream and attempt to claim it before the headers come down. | |
5464 scoped_ptr<SpdyFrame> stream1_syn( | |
5465 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
5466 scoped_ptr<SpdyFrame> stream1_body( | |
5467 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
5468 MockWrite writes[] = { | |
5469 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS), | |
5470 }; | |
5471 | |
5472 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock()); | |
5473 if (spdy_util_.spdy_version() < SPDY4) { | |
5474 // In SPDY4 PUSH_PROMISE headers won't show up in the response headers. | |
5475 (*initial_headers)["alpha"] = "beta"; | |
5476 } | |
5477 spdy_util_.AddUrlToHeaderBlock( | |
5478 "http://www.google.com/foo.dat", initial_headers.get()); | |
5479 scoped_ptr<SpdyFrame> stream2_syn( | |
5480 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1)); | |
5481 | |
5482 scoped_ptr<SpdyHeaderBlock> middle_headers(new SpdyHeaderBlock()); | |
5483 (*middle_headers)["hello"] = "bye"; | |
5484 scoped_ptr<SpdyFrame> stream2_headers1( | |
5485 spdy_util_.ConstructSpdyControlFrame(middle_headers.Pass(), | |
5486 false, | |
5487 2, | |
5488 LOWEST, | |
5489 HEADERS, | |
5490 CONTROL_FLAG_NONE, | |
5491 0)); | |
5492 | |
5493 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock()); | |
5494 (*late_headers)[spdy_util_.GetStatusKey()] = "200"; | |
5495 if (spdy_util_.spdy_version() < SPDY4) { | |
5496 // SPDY4/HTTP2 eliminates use of the :version header. | |
5497 (*late_headers)[spdy_util_.GetVersionKey()] = "HTTP/1.1"; | |
5498 } | |
5499 scoped_ptr<SpdyFrame> stream2_headers2( | |
5500 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(), | |
5501 false, | |
5502 2, | |
5503 LOWEST, | |
5504 HEADERS, | |
5505 CONTROL_FLAG_NONE, | |
5506 0)); | |
5507 | |
5508 scoped_ptr<SpdyFrame> | |
5509 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5510 const char kPushedData[] = "pushed"; | |
5511 scoped_ptr<SpdyFrame> stream2_body( | |
5512 spdy_util_.ConstructSpdyBodyFrame( | |
5513 2, kPushedData, strlen(kPushedData), true)); | |
5514 MockRead reads[] = { | |
5515 CreateMockRead(*stream1_reply, 1), | |
5516 CreateMockRead(*stream2_syn, 2), | |
5517 CreateMockRead(*stream1_body, 3), | |
5518 CreateMockRead(*stream2_headers1, 4), | |
5519 CreateMockRead(*stream2_headers2, 5), | |
5520 CreateMockRead(*stream2_body, 6), | |
5521 MockRead(ASYNC, 0, 7), // EOF | |
5522 }; | |
5523 | |
5524 HttpResponseInfo response; | |
5525 HttpResponseInfo response2; | |
5526 std::string expected_push_result("pushed"); | |
5527 DeterministicSocketData data(reads, arraysize(reads), | |
5528 writes, arraysize(writes)); | |
5529 | |
5530 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
5531 BoundNetLog(), GetParam(), NULL); | |
5532 helper.SetDeterministic(); | |
5533 helper.AddDeterministicData(&data); | |
5534 helper.RunPreTestSetup(); | |
5535 | |
5536 HttpNetworkTransaction* trans = helper.trans(); | |
5537 | |
5538 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM, | |
5539 // the first HEADERS frame, and the body of the primary stream, but before | |
5540 // we've received the final HEADERS for the pushed stream. | |
5541 data.SetStop(4); | |
5542 | |
5543 // Start the transaction. | |
5544 TestCompletionCallback callback; | |
5545 int rv = trans->Start( | |
5546 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
5547 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5548 data.Run(); | |
5549 rv = callback.WaitForResult(); | |
5550 EXPECT_EQ(0, rv); | |
5551 | |
5552 // Request the pushed path. At this point, we've received the push, but the | |
5553 // headers are not yet complete. | |
5554 scoped_ptr<HttpNetworkTransaction> trans2( | |
5555 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
5556 rv = trans2->Start( | |
5557 &CreateGetPushRequest(), callback.callback(), BoundNetLog()); | |
5558 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5559 data.RunFor(3); | |
5560 base::RunLoop().RunUntilIdle(); | |
5561 | |
5562 // Read the server push body. | |
5563 std::string result2; | |
5564 ReadResult(trans2.get(), &data, &result2); | |
5565 // Read the response body. | |
5566 std::string result; | |
5567 ReadResult(trans, &data, &result); | |
5568 | |
5569 // Verify that the received push data is same as the expected push data. | |
5570 EXPECT_EQ(expected_push_result, result2); | |
5571 | |
5572 // Verify the SYN_REPLY. | |
5573 // Copy the response info, because trans goes away. | |
5574 response = *trans->GetResponseInfo(); | |
5575 response2 = *trans2->GetResponseInfo(); | |
5576 | |
5577 VerifyStreamsClosed(helper); | |
5578 | |
5579 // Verify the SYN_REPLY. | |
5580 EXPECT_TRUE(response.headers.get() != NULL); | |
5581 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
5582 | |
5583 // Verify the pushed stream. | |
5584 EXPECT_TRUE(response2.headers.get() != NULL); | |
5585 EXPECT_EQ("HTTP/1.1 200 OK", response2.headers->GetStatusLine()); | |
5586 | |
5587 // Verify we got all the headers from all header blocks. | |
5588 if (spdy_util_.spdy_version() < SPDY4) | |
5589 EXPECT_TRUE(response2.headers->HasHeaderValue("alpha", "beta")); | |
5590 EXPECT_TRUE(response2.headers->HasHeaderValue("hello", "bye")); | |
5591 EXPECT_TRUE(response2.headers->HasHeaderValue("status", "200")); | |
5592 | |
5593 // Read the final EOF (which will close the session) | |
5594 data.RunFor(1); | |
5595 | |
5596 // Verify that we consumed all test data. | |
5597 EXPECT_TRUE(data.at_read_eof()); | |
5598 EXPECT_TRUE(data.at_write_eof()); | |
5599 } | |
5600 | |
5601 TEST_P(SpdyNetworkTransactionTest, ServerPushWithNoStatusHeaderFrames) { | |
5602 // We push a stream and attempt to claim it before the headers come down. | |
5603 scoped_ptr<SpdyFrame> stream1_syn( | |
5604 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
5605 scoped_ptr<SpdyFrame> stream1_body( | |
5606 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
5607 MockWrite writes[] = { | |
5608 CreateMockWrite(*stream1_syn, 0, SYNCHRONOUS), | |
5609 }; | |
5610 | |
5611 scoped_ptr<SpdyHeaderBlock> initial_headers(new SpdyHeaderBlock()); | |
5612 spdy_util_.AddUrlToHeaderBlock( | |
5613 "http://www.google.com/foo.dat", initial_headers.get()); | |
5614 scoped_ptr<SpdyFrame> stream2_syn( | |
5615 spdy_util_.ConstructInitialSpdyPushFrame(initial_headers.Pass(), 2, 1)); | |
5616 | |
5617 scoped_ptr<SpdyHeaderBlock> middle_headers(new SpdyHeaderBlock()); | |
5618 (*middle_headers)["hello"] = "bye"; | |
5619 scoped_ptr<SpdyFrame> stream2_headers1( | |
5620 spdy_util_.ConstructSpdyControlFrame(middle_headers.Pass(), | |
5621 false, | |
5622 2, | |
5623 LOWEST, | |
5624 HEADERS, | |
5625 CONTROL_FLAG_NONE, | |
5626 0)); | |
5627 | |
5628 scoped_ptr<SpdyFrame> | |
5629 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5630 const char kPushedData[] = "pushed"; | |
5631 scoped_ptr<SpdyFrame> stream2_body( | |
5632 spdy_util_.ConstructSpdyBodyFrame( | |
5633 2, kPushedData, strlen(kPushedData), true)); | |
5634 MockRead reads[] = { | |
5635 CreateMockRead(*stream1_reply, 1), | |
5636 CreateMockRead(*stream2_syn, 2), | |
5637 CreateMockRead(*stream1_body, 3), | |
5638 CreateMockRead(*stream2_headers1, 4), | |
5639 CreateMockRead(*stream2_body, 5), | |
5640 MockRead(ASYNC, 0, 6), // EOF | |
5641 }; | |
5642 | |
5643 DeterministicSocketData data(reads, arraysize(reads), | |
5644 writes, arraysize(writes)); | |
5645 | |
5646 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
5647 BoundNetLog(), GetParam(), NULL); | |
5648 helper.SetDeterministic(); | |
5649 helper.AddDeterministicData(&data); | |
5650 helper.RunPreTestSetup(); | |
5651 | |
5652 HttpNetworkTransaction* trans = helper.trans(); | |
5653 | |
5654 // Run until we've received the primary SYN_STREAM, the pushed SYN_STREAM, | |
5655 // the first HEADERS frame, and the body of the primary stream, but before | |
5656 // we've received the final HEADERS for the pushed stream. | |
5657 data.SetStop(4); | |
5658 | |
5659 // Start the transaction. | |
5660 TestCompletionCallback callback; | |
5661 int rv = trans->Start( | |
5662 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
5663 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5664 data.Run(); | |
5665 rv = callback.WaitForResult(); | |
5666 EXPECT_EQ(0, rv); | |
5667 | |
5668 // Request the pushed path. At this point, we've received the push, but the | |
5669 // headers are not yet complete. | |
5670 scoped_ptr<HttpNetworkTransaction> trans2( | |
5671 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session().get())); | |
5672 rv = trans2->Start( | |
5673 &CreateGetPushRequest(), callback.callback(), BoundNetLog()); | |
5674 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5675 data.RunFor(2); | |
5676 base::RunLoop().RunUntilIdle(); | |
5677 | |
5678 // Read the server push body. | |
5679 std::string result2; | |
5680 ReadResult(trans2.get(), &data, &result2); | |
5681 // Read the response body. | |
5682 std::string result; | |
5683 ReadResult(trans, &data, &result); | |
5684 EXPECT_EQ("hello!", result); | |
5685 | |
5686 // Verify that we haven't received any push data. | |
5687 EXPECT_EQ("", result2); | |
5688 | |
5689 // Verify the SYN_REPLY. | |
5690 // Copy the response info, because trans goes away. | |
5691 HttpResponseInfo response = *trans->GetResponseInfo(); | |
5692 ASSERT_TRUE(trans2->GetResponseInfo() == NULL); | |
5693 | |
5694 VerifyStreamsClosed(helper); | |
5695 | |
5696 // Verify the SYN_REPLY. | |
5697 EXPECT_TRUE(response.headers.get() != NULL); | |
5698 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
5699 | |
5700 // Read the final EOF (which will close the session). | |
5701 data.RunFor(1); | |
5702 | |
5703 // Verify that we consumed all test data. | |
5704 EXPECT_TRUE(data.at_read_eof()); | |
5705 EXPECT_TRUE(data.at_write_eof()); | |
5706 } | |
5707 | |
5708 TEST_P(SpdyNetworkTransactionTest, SynReplyWithHeaders) { | |
5709 scoped_ptr<SpdyFrame> req( | |
5710 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
5711 scoped_ptr<SpdyFrame> rst( | |
5712 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); | |
5713 MockWrite writes[] = { | |
5714 CreateMockWrite(*req), CreateMockWrite(*rst), | |
5715 }; | |
5716 | |
5717 scoped_ptr<SpdyFrame> stream1_reply( | |
5718 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5719 | |
5720 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock()); | |
5721 (*late_headers)["hello"] = "bye"; | |
5722 scoped_ptr<SpdyFrame> stream1_headers( | |
5723 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(), | |
5724 false, | |
5725 1, | |
5726 LOWEST, | |
5727 HEADERS, | |
5728 CONTROL_FLAG_NONE, | |
5729 0)); | |
5730 scoped_ptr<SpdyFrame> stream1_body( | |
5731 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
5732 MockRead reads[] = { | |
5733 CreateMockRead(*stream1_reply), | |
5734 CreateMockRead(*stream1_headers), | |
5735 CreateMockRead(*stream1_body), | |
5736 MockRead(ASYNC, 0, 0) // EOF | |
5737 }; | |
5738 | |
5739 DelayedSocketData data(1, reads, arraysize(reads), | |
5740 writes, arraysize(writes)); | |
5741 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
5742 BoundNetLog(), GetParam(), NULL); | |
5743 helper.RunToCompletion(&data); | |
5744 TransactionHelperResult out = helper.output(); | |
5745 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
5746 } | |
5747 | |
5748 TEST_P(SpdyNetworkTransactionTest, SynReplyWithLateHeaders) { | |
5749 scoped_ptr<SpdyFrame> req( | |
5750 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
5751 scoped_ptr<SpdyFrame> rst( | |
5752 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR)); | |
5753 MockWrite writes[] = { | |
5754 CreateMockWrite(*req), | |
5755 CreateMockWrite(*rst), | |
5756 }; | |
5757 | |
5758 scoped_ptr<SpdyFrame> stream1_reply( | |
5759 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5760 | |
5761 scoped_ptr<SpdyHeaderBlock> late_headers(new SpdyHeaderBlock()); | |
5762 (*late_headers)["hello"] = "bye"; | |
5763 scoped_ptr<SpdyFrame> stream1_headers( | |
5764 spdy_util_.ConstructSpdyControlFrame(late_headers.Pass(), | |
5765 false, | |
5766 1, | |
5767 LOWEST, | |
5768 HEADERS, | |
5769 CONTROL_FLAG_NONE, | |
5770 0)); | |
5771 scoped_ptr<SpdyFrame> stream1_body( | |
5772 spdy_util_.ConstructSpdyBodyFrame(1, false)); | |
5773 scoped_ptr<SpdyFrame> stream1_body2( | |
5774 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
5775 MockRead reads[] = { | |
5776 CreateMockRead(*stream1_reply), | |
5777 CreateMockRead(*stream1_body), | |
5778 CreateMockRead(*stream1_headers), | |
5779 CreateMockRead(*stream1_body2), | |
5780 MockRead(ASYNC, 0, 0) // EOF | |
5781 }; | |
5782 | |
5783 DelayedSocketData data(1, reads, arraysize(reads), | |
5784 writes, arraysize(writes)); | |
5785 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
5786 BoundNetLog(), GetParam(), NULL); | |
5787 helper.RunToCompletion(&data); | |
5788 TransactionHelperResult out = helper.output(); | |
5789 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
5790 } | |
5791 | |
5792 TEST_P(SpdyNetworkTransactionTest, ServerPushCrossOriginCorrectness) { | |
5793 // In this test we want to verify that we can't accidentally push content | |
5794 // which can't be pushed by this content server. | |
5795 // This test assumes that: | |
5796 // - if we're requesting http://www.foo.com/barbaz | |
5797 // - the browser has made a connection to "www.foo.com". | |
5798 | |
5799 // A list of the URL to fetch, followed by the URL being pushed. | |
5800 static const char* const kTestCases[] = { | |
5801 "http://www.google.com/foo.html", | |
5802 "http://www.google.com:81/foo.js", // Bad port | |
5803 | |
5804 "http://www.google.com/foo.html", | |
5805 "https://www.google.com/foo.js", // Bad protocol | |
5806 | |
5807 "http://www.google.com/foo.html", | |
5808 "ftp://www.google.com/foo.js", // Invalid Protocol | |
5809 | |
5810 "http://www.google.com/foo.html", | |
5811 "http://blat.www.google.com/foo.js", // Cross subdomain | |
5812 | |
5813 "http://www.google.com/foo.html", | |
5814 "http://www.foo.com/foo.js", // Cross domain | |
5815 }; | |
5816 | |
5817 for (size_t index = 0; index < arraysize(kTestCases); index += 2) { | |
5818 const char* url_to_fetch = kTestCases[index]; | |
5819 const char* url_to_push = kTestCases[index + 1]; | |
5820 | |
5821 scoped_ptr<SpdyFrame> stream1_syn( | |
5822 spdy_util_.ConstructSpdyGet(url_to_fetch, false, 1, LOWEST)); | |
5823 scoped_ptr<SpdyFrame> stream1_body( | |
5824 spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
5825 scoped_ptr<SpdyFrame> push_rst( | |
5826 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM)); | |
5827 MockWrite writes[] = { | |
5828 CreateMockWrite(*stream1_syn, 1), | |
5829 CreateMockWrite(*push_rst, 4), | |
5830 }; | |
5831 | |
5832 scoped_ptr<SpdyFrame> | |
5833 stream1_reply(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5834 scoped_ptr<SpdyFrame> | |
5835 stream2_syn(spdy_util_.ConstructSpdyPush(NULL, | |
5836 0, | |
5837 2, | |
5838 1, | |
5839 url_to_push)); | |
5840 const char kPushedData[] = "pushed"; | |
5841 scoped_ptr<SpdyFrame> stream2_body( | |
5842 spdy_util_.ConstructSpdyBodyFrame( | |
5843 2, kPushedData, strlen(kPushedData), true)); | |
5844 scoped_ptr<SpdyFrame> rst( | |
5845 spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_CANCEL)); | |
5846 | |
5847 MockRead reads[] = { | |
5848 CreateMockRead(*stream1_reply, 2), | |
5849 CreateMockRead(*stream2_syn, 3), | |
5850 CreateMockRead(*stream1_body, 5, SYNCHRONOUS), | |
5851 CreateMockRead(*stream2_body, 6), | |
5852 MockRead(ASYNC, ERR_IO_PENDING, 7), // Force a pause | |
5853 }; | |
5854 | |
5855 HttpResponseInfo response; | |
5856 OrderedSocketData data(reads, arraysize(reads), | |
5857 writes, arraysize(writes)); | |
5858 | |
5859 HttpRequestInfo request; | |
5860 request.method = "GET"; | |
5861 request.url = GURL(url_to_fetch); | |
5862 request.load_flags = 0; | |
5863 | |
5864 // Enable cross-origin push. Since we are not using a proxy, this should | |
5865 // not actually enable cross-origin SPDY push. | |
5866 scoped_ptr<SpdySessionDependencies> session_deps( | |
5867 CreateSpdySessionDependencies(GetParam())); | |
5868 session_deps->trusted_spdy_proxy = "123.45.67.89:8080"; | |
5869 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
5870 BoundNetLog(), GetParam(), | |
5871 session_deps.release()); | |
5872 helper.RunPreTestSetup(); | |
5873 helper.AddData(&data); | |
5874 | |
5875 HttpNetworkTransaction* trans = helper.trans(); | |
5876 | |
5877 // Start the transaction with basic parameters. | |
5878 TestCompletionCallback callback; | |
5879 | |
5880 int rv = trans->Start(&request, callback.callback(), BoundNetLog()); | |
5881 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5882 rv = callback.WaitForResult(); | |
5883 | |
5884 // Read the response body. | |
5885 std::string result; | |
5886 ReadResult(trans, &data, &result); | |
5887 | |
5888 // Verify that we consumed all test data. | |
5889 EXPECT_TRUE(data.at_read_eof()); | |
5890 EXPECT_TRUE(data.at_write_eof()); | |
5891 | |
5892 // Verify the SYN_REPLY. | |
5893 // Copy the response info, because trans goes away. | |
5894 response = *trans->GetResponseInfo(); | |
5895 | |
5896 VerifyStreamsClosed(helper); | |
5897 | |
5898 // Verify the SYN_REPLY. | |
5899 EXPECT_TRUE(response.headers.get() != NULL); | |
5900 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
5901 } | |
5902 } | |
5903 | |
5904 TEST_P(SpdyNetworkTransactionTest, RetryAfterRefused) { | |
5905 // Construct the request. | |
5906 scoped_ptr<SpdyFrame> req( | |
5907 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
5908 scoped_ptr<SpdyFrame> req2( | |
5909 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true)); | |
5910 MockWrite writes[] = { | |
5911 CreateMockWrite(*req, 1), | |
5912 CreateMockWrite(*req2, 3), | |
5913 }; | |
5914 | |
5915 scoped_ptr<SpdyFrame> refused( | |
5916 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_REFUSED_STREAM)); | |
5917 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
5918 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
5919 MockRead reads[] = { | |
5920 CreateMockRead(*refused, 2), | |
5921 CreateMockRead(*resp, 4), | |
5922 CreateMockRead(*body, 5), | |
5923 MockRead(ASYNC, 0, 6) // EOF | |
5924 }; | |
5925 | |
5926 OrderedSocketData data(reads, arraysize(reads), | |
5927 writes, arraysize(writes)); | |
5928 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
5929 BoundNetLog(), GetParam(), NULL); | |
5930 | |
5931 helper.RunPreTestSetup(); | |
5932 helper.AddData(&data); | |
5933 | |
5934 HttpNetworkTransaction* trans = helper.trans(); | |
5935 | |
5936 // Start the transaction with basic parameters. | |
5937 TestCompletionCallback callback; | |
5938 int rv = trans->Start( | |
5939 &CreateGetRequest(), callback.callback(), BoundNetLog()); | |
5940 EXPECT_EQ(ERR_IO_PENDING, rv); | |
5941 rv = callback.WaitForResult(); | |
5942 EXPECT_EQ(OK, rv); | |
5943 | |
5944 // Verify that we consumed all test data. | |
5945 EXPECT_TRUE(data.at_read_eof()) << "Read count: " | |
5946 << data.read_count() | |
5947 << " Read index: " | |
5948 << data.read_index(); | |
5949 EXPECT_TRUE(data.at_write_eof()) << "Write count: " | |
5950 << data.write_count() | |
5951 << " Write index: " | |
5952 << data.write_index(); | |
5953 | |
5954 // Verify the SYN_REPLY. | |
5955 HttpResponseInfo response = *trans->GetResponseInfo(); | |
5956 EXPECT_TRUE(response.headers.get() != NULL); | |
5957 EXPECT_EQ("HTTP/1.1 200 OK", response.headers->GetStatusLine()); | |
5958 } | |
5959 | |
5960 TEST_P(SpdyNetworkTransactionTest, OutOfOrderSynStream) { | |
5961 // This first request will start to establish the SpdySession. | |
5962 // Then we will start the second (MEDIUM priority) and then third | |
5963 // (HIGHEST priority) request in such a way that the third will actually | |
5964 // start before the second, causing the second to be numbered differently | |
5965 // than the order they were created. | |
5966 scoped_ptr<SpdyFrame> req1( | |
5967 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
5968 scoped_ptr<SpdyFrame> req2( | |
5969 spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, HIGHEST, true)); | |
5970 scoped_ptr<SpdyFrame> req3( | |
5971 spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, MEDIUM, true)); | |
5972 MockWrite writes[] = { | |
5973 CreateMockWrite(*req1, 0), | |
5974 CreateMockWrite(*req2, 3), | |
5975 CreateMockWrite(*req3, 4), | |
5976 }; | |
5977 | |
5978 scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
5979 scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
5980 scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3)); | |
5981 scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true)); | |
5982 scoped_ptr<SpdyFrame> resp3(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5)); | |
5983 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(5, true)); | |
5984 MockRead reads[] = { | |
5985 CreateMockRead(*resp1, 1), | |
5986 CreateMockRead(*body1, 2), | |
5987 CreateMockRead(*resp2, 5), | |
5988 CreateMockRead(*body2, 6), | |
5989 CreateMockRead(*resp3, 7), | |
5990 CreateMockRead(*body3, 8), | |
5991 MockRead(ASYNC, 0, 9) // EOF | |
5992 }; | |
5993 | |
5994 DeterministicSocketData data(reads, arraysize(reads), | |
5995 writes, arraysize(writes)); | |
5996 NormalSpdyTransactionHelper helper(CreateGetRequest(), LOWEST, | |
5997 BoundNetLog(), GetParam(), NULL); | |
5998 helper.SetDeterministic(); | |
5999 helper.RunPreTestSetup(); | |
6000 helper.AddDeterministicData(&data); | |
6001 | |
6002 // Start the first transaction to set up the SpdySession | |
6003 HttpNetworkTransaction* trans = helper.trans(); | |
6004 TestCompletionCallback callback; | |
6005 HttpRequestInfo info1 = CreateGetRequest(); | |
6006 int rv = trans->Start(&info1, callback.callback(), BoundNetLog()); | |
6007 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6008 | |
6009 // Run the message loop, but do not allow the write to complete. | |
6010 // This leaves the SpdySession with a write pending, which prevents | |
6011 // SpdySession from attempting subsequent writes until this write completes. | |
6012 base::RunLoop().RunUntilIdle(); | |
6013 | |
6014 // Now, start both new transactions | |
6015 HttpRequestInfo info2 = CreateGetRequest(); | |
6016 TestCompletionCallback callback2; | |
6017 scoped_ptr<HttpNetworkTransaction> trans2( | |
6018 new HttpNetworkTransaction(MEDIUM, helper.session().get())); | |
6019 rv = trans2->Start(&info2, callback2.callback(), BoundNetLog()); | |
6020 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6021 base::RunLoop().RunUntilIdle(); | |
6022 | |
6023 HttpRequestInfo info3 = CreateGetRequest(); | |
6024 TestCompletionCallback callback3; | |
6025 scoped_ptr<HttpNetworkTransaction> trans3( | |
6026 new HttpNetworkTransaction(HIGHEST, helper.session().get())); | |
6027 rv = trans3->Start(&info3, callback3.callback(), BoundNetLog()); | |
6028 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6029 base::RunLoop().RunUntilIdle(); | |
6030 | |
6031 // We now have two SYN_STREAM frames queued up which will be | |
6032 // dequeued only once the first write completes, which we | |
6033 // now allow to happen. | |
6034 data.RunFor(2); | |
6035 EXPECT_EQ(OK, callback.WaitForResult()); | |
6036 | |
6037 // And now we can allow everything else to run to completion. | |
6038 data.SetStop(10); | |
6039 data.Run(); | |
6040 EXPECT_EQ(OK, callback2.WaitForResult()); | |
6041 EXPECT_EQ(OK, callback3.WaitForResult()); | |
6042 | |
6043 helper.VerifyDataConsumed(); | |
6044 } | |
6045 | |
6046 // The tests below are only for SPDY/3 and above. | |
6047 | |
6048 // Test that sent data frames and received WINDOW_UPDATE frames change | |
6049 // the send_window_size_ correctly. | |
6050 | |
6051 // WINDOW_UPDATE is different than most other frames in that it can arrive | |
6052 // while the client is still sending the request body. In order to enforce | |
6053 // this scenario, we feed a couple of dummy frames and give a delay of 0 to | |
6054 // socket data provider, so that initial read that is done as soon as the | |
6055 // stream is created, succeeds and schedules another read. This way reads | |
6056 // and writes are interleaved; after doing a full frame write, SpdyStream | |
6057 // will break out of DoLoop and will read and process a WINDOW_UPDATE. | |
6058 // Once our WINDOW_UPDATE is read, we cannot send SYN_REPLY right away | |
6059 // since request has not been completely written, therefore we feed | |
6060 // enough number of WINDOW_UPDATEs to finish the first read and cause a | |
6061 // write, leading to a complete write of request body; after that we send | |
6062 // a reply with a body, to cause a graceful shutdown. | |
6063 | |
6064 // TODO(agayev): develop a socket data provider where both, reads and | |
6065 // writes are ordered so that writing tests like these are easy and rewrite | |
6066 // all these tests using it. Right now we are working around the | |
6067 // limitations as described above and it's not deterministic, tests may | |
6068 // fail under specific circumstances. | |
6069 TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) { | |
6070 static int kFrameCount = 2; | |
6071 scoped_ptr<std::string> content( | |
6072 new std::string(kMaxSpdyFrameChunkSize, 'a')); | |
6073 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( | |
6074 kRequestUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0)); | |
6075 scoped_ptr<SpdyFrame> body( | |
6076 spdy_util_.ConstructSpdyBodyFrame( | |
6077 1, content->c_str(), content->size(), false)); | |
6078 scoped_ptr<SpdyFrame> body_end( | |
6079 spdy_util_.ConstructSpdyBodyFrame( | |
6080 1, content->c_str(), content->size(), true)); | |
6081 | |
6082 MockWrite writes[] = { | |
6083 CreateMockWrite(*req, 0), | |
6084 CreateMockWrite(*body, 1), | |
6085 CreateMockWrite(*body_end, 2), | |
6086 }; | |
6087 | |
6088 static const int32 kDeltaWindowSize = 0xff; | |
6089 static const int kDeltaCount = 4; | |
6090 scoped_ptr<SpdyFrame> window_update( | |
6091 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize)); | |
6092 scoped_ptr<SpdyFrame> window_update_dummy( | |
6093 spdy_util_.ConstructSpdyWindowUpdate(2, kDeltaWindowSize)); | |
6094 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
6095 MockRead reads[] = { | |
6096 CreateMockRead(*window_update_dummy, 3), | |
6097 CreateMockRead(*window_update_dummy, 4), | |
6098 CreateMockRead(*window_update_dummy, 5), | |
6099 CreateMockRead(*window_update, 6), // Four updates, therefore window | |
6100 CreateMockRead(*window_update, 7), // size should increase by | |
6101 CreateMockRead(*window_update, 8), // kDeltaWindowSize * 4 | |
6102 CreateMockRead(*window_update, 9), | |
6103 CreateMockRead(*resp, 10), | |
6104 CreateMockRead(*body_end, 11), | |
6105 MockRead(ASYNC, 0, 0, 12) // EOF | |
6106 }; | |
6107 | |
6108 DeterministicSocketData data(reads, arraysize(reads), | |
6109 writes, arraysize(writes)); | |
6110 | |
6111 ScopedVector<UploadElementReader> element_readers; | |
6112 for (int i = 0; i < kFrameCount; ++i) { | |
6113 element_readers.push_back( | |
6114 new UploadBytesElementReader(content->c_str(), content->size())); | |
6115 } | |
6116 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
6117 | |
6118 // Setup the request | |
6119 HttpRequestInfo request; | |
6120 request.method = "POST"; | |
6121 request.url = GURL(kDefaultURL); | |
6122 request.upload_data_stream = &upload_data_stream; | |
6123 | |
6124 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
6125 BoundNetLog(), GetParam(), NULL); | |
6126 helper.SetDeterministic(); | |
6127 helper.AddDeterministicData(&data); | |
6128 helper.RunPreTestSetup(); | |
6129 | |
6130 HttpNetworkTransaction* trans = helper.trans(); | |
6131 | |
6132 TestCompletionCallback callback; | |
6133 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
6134 | |
6135 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6136 | |
6137 data.RunFor(11); | |
6138 | |
6139 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
6140 ASSERT_TRUE(stream != NULL); | |
6141 ASSERT_TRUE(stream->stream() != NULL); | |
6142 EXPECT_EQ( | |
6143 static_cast<int>(SpdySession::GetInitialWindowSize(GetParam().protocol)) + | |
6144 kDeltaWindowSize * kDeltaCount - kMaxSpdyFrameChunkSize * kFrameCount, | |
6145 stream->stream()->send_window_size()); | |
6146 | |
6147 data.RunFor(1); | |
6148 | |
6149 rv = callback.WaitForResult(); | |
6150 EXPECT_EQ(OK, rv); | |
6151 | |
6152 helper.VerifyDataConsumed(); | |
6153 } | |
6154 | |
6155 // Test that received data frames and sent WINDOW_UPDATE frames change | |
6156 // the recv_window_size_ correctly. | |
6157 TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) { | |
6158 const int32 initial_window_size = | |
6159 SpdySession::GetInitialWindowSize(GetParam().protocol); | |
6160 // Amount of body required to trigger a sent window update. | |
6161 const size_t kTargetSize = initial_window_size / 2 + 1; | |
6162 | |
6163 scoped_ptr<SpdyFrame> req( | |
6164 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
6165 scoped_ptr<SpdyFrame> session_window_update( | |
6166 spdy_util_.ConstructSpdyWindowUpdate(0, kTargetSize)); | |
6167 scoped_ptr<SpdyFrame> window_update( | |
6168 spdy_util_.ConstructSpdyWindowUpdate(1, kTargetSize)); | |
6169 | |
6170 std::vector<MockWrite> writes; | |
6171 writes.push_back(CreateMockWrite(*req)); | |
6172 if (GetParam().protocol >= kProtoSPDY31) | |
6173 writes.push_back(CreateMockWrite(*session_window_update)); | |
6174 writes.push_back(CreateMockWrite(*window_update)); | |
6175 | |
6176 std::vector<MockRead> reads; | |
6177 scoped_ptr<SpdyFrame> resp( | |
6178 spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
6179 reads.push_back(CreateMockRead(*resp)); | |
6180 | |
6181 ScopedVector<SpdyFrame> body_frames; | |
6182 const std::string body_data(4096, 'x'); | |
6183 for (size_t remaining = kTargetSize; remaining != 0;) { | |
6184 size_t frame_size = std::min(remaining, body_data.size()); | |
6185 body_frames.push_back(spdy_util_.ConstructSpdyBodyFrame( | |
6186 1, body_data.data(), frame_size, false)); | |
6187 reads.push_back(CreateMockRead(*body_frames.back())); | |
6188 remaining -= frame_size; | |
6189 } | |
6190 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, 0)); // Yield. | |
6191 | |
6192 DelayedSocketData data(1, vector_as_array(&reads), reads.size(), | |
6193 vector_as_array(&writes), writes.size()); | |
6194 | |
6195 NormalSpdyTransactionHelper helper(CreateGetRequest(), DEFAULT_PRIORITY, | |
6196 BoundNetLog(), GetParam(), NULL); | |
6197 helper.AddData(&data); | |
6198 helper.RunPreTestSetup(); | |
6199 HttpNetworkTransaction* trans = helper.trans(); | |
6200 | |
6201 TestCompletionCallback callback; | |
6202 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
6203 | |
6204 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6205 rv = callback.WaitForResult(); | |
6206 EXPECT_EQ(OK, rv); | |
6207 | |
6208 SpdyHttpStream* stream = | |
6209 static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
6210 ASSERT_TRUE(stream != NULL); | |
6211 ASSERT_TRUE(stream->stream() != NULL); | |
6212 | |
6213 // All data has been read, but not consumed. The window reflects this. | |
6214 EXPECT_EQ(static_cast<int>(initial_window_size - kTargetSize), | |
6215 stream->stream()->recv_window_size()); | |
6216 | |
6217 const HttpResponseInfo* response = trans->GetResponseInfo(); | |
6218 ASSERT_TRUE(response != NULL); | |
6219 ASSERT_TRUE(response->headers.get() != NULL); | |
6220 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine()); | |
6221 EXPECT_TRUE(response->was_fetched_via_spdy); | |
6222 | |
6223 // Issue a read which will cause a WINDOW_UPDATE to be sent and window | |
6224 // size increased to default. | |
6225 scoped_refptr<net::IOBuffer> buf(new net::IOBuffer(kTargetSize)); | |
6226 EXPECT_EQ(static_cast<int>(kTargetSize), | |
6227 trans->Read(buf.get(), kTargetSize, CompletionCallback())); | |
6228 EXPECT_EQ(static_cast<int>(initial_window_size), | |
6229 stream->stream()->recv_window_size()); | |
6230 EXPECT_THAT(base::StringPiece(buf->data(), kTargetSize), Each(Eq('x'))); | |
6231 | |
6232 // Allow scheduled WINDOW_UPDATE frames to write. | |
6233 base::RunLoop().RunUntilIdle(); | |
6234 helper.VerifyDataConsumed(); | |
6235 } | |
6236 | |
6237 // Test that WINDOW_UPDATE frame causing overflow is handled correctly. | |
6238 TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) { | |
6239 // Number of full frames we hope to write (but will not, used to | |
6240 // set content-length header correctly) | |
6241 static int kFrameCount = 3; | |
6242 | |
6243 scoped_ptr<std::string> content( | |
6244 new std::string(kMaxSpdyFrameChunkSize, 'a')); | |
6245 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( | |
6246 kRequestUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, NULL, 0)); | |
6247 scoped_ptr<SpdyFrame> body( | |
6248 spdy_util_.ConstructSpdyBodyFrame( | |
6249 1, content->c_str(), content->size(), false)); | |
6250 scoped_ptr<SpdyFrame> rst( | |
6251 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_FLOW_CONTROL_ERROR)); | |
6252 | |
6253 // We're not going to write a data frame with FIN, we'll receive a bad | |
6254 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame. | |
6255 MockWrite writes[] = { | |
6256 CreateMockWrite(*req, 0), | |
6257 CreateMockWrite(*body, 2), | |
6258 CreateMockWrite(*rst, 3), | |
6259 }; | |
6260 | |
6261 static const int32 kDeltaWindowSize = 0x7fffffff; // cause an overflow | |
6262 scoped_ptr<SpdyFrame> window_update( | |
6263 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize)); | |
6264 MockRead reads[] = { | |
6265 CreateMockRead(*window_update, 1), | |
6266 MockRead(ASYNC, 0, 4) // EOF | |
6267 }; | |
6268 | |
6269 DeterministicSocketData data(reads, arraysize(reads), | |
6270 writes, arraysize(writes)); | |
6271 | |
6272 ScopedVector<UploadElementReader> element_readers; | |
6273 for (int i = 0; i < kFrameCount; ++i) { | |
6274 element_readers.push_back( | |
6275 new UploadBytesElementReader(content->c_str(), content->size())); | |
6276 } | |
6277 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
6278 | |
6279 // Setup the request | |
6280 HttpRequestInfo request; | |
6281 request.method = "POST"; | |
6282 request.url = GURL("http://www.google.com/"); | |
6283 request.upload_data_stream = &upload_data_stream; | |
6284 | |
6285 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
6286 BoundNetLog(), GetParam(), NULL); | |
6287 helper.SetDeterministic(); | |
6288 helper.RunPreTestSetup(); | |
6289 helper.AddDeterministicData(&data); | |
6290 HttpNetworkTransaction* trans = helper.trans(); | |
6291 | |
6292 TestCompletionCallback callback; | |
6293 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
6294 ASSERT_EQ(ERR_IO_PENDING, rv); | |
6295 | |
6296 data.RunFor(5); | |
6297 ASSERT_TRUE(callback.have_result()); | |
6298 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, callback.WaitForResult()); | |
6299 helper.VerifyDataConsumed(); | |
6300 } | |
6301 | |
6302 // Test that after hitting a send window size of 0, the write process | |
6303 // stalls and upon receiving WINDOW_UPDATE frame write resumes. | |
6304 | |
6305 // This test constructs a POST request followed by enough data frames | |
6306 // containing 'a' that would make the window size 0, followed by another | |
6307 // data frame containing default content (which is "hello!") and this frame | |
6308 // also contains a FIN flag. DelayedSocketData is used to enforce all | |
6309 // writes go through before a read could happen. However, the last frame | |
6310 // ("hello!") is not supposed to go through since by the time its turn | |
6311 // arrives, window size is 0. At this point MessageLoop::Run() called via | |
6312 // callback would block. Therefore we call MessageLoop::RunUntilIdle() | |
6313 // which returns after performing all possible writes. We use DCHECKS to | |
6314 // ensure that last data frame is still there and stream has stalled. | |
6315 // After that, next read is artifically enforced, which causes a | |
6316 // WINDOW_UPDATE to be read and I/O process resumes. | |
6317 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) { | |
6318 const int32 initial_window_size = | |
6319 SpdySession::GetInitialWindowSize(GetParam().protocol); | |
6320 // Number of frames we need to send to zero out the window size: data | |
6321 // frames plus SYN_STREAM plus the last data frame; also we need another | |
6322 // data frame that we will send once the WINDOW_UPDATE is received, | |
6323 // therefore +3. | |
6324 size_t num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3; | |
6325 | |
6326 // Calculate last frame's size; 0 size data frame is legal. | |
6327 size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize; | |
6328 | |
6329 // Construct content for a data frame of maximum size. | |
6330 std::string content(kMaxSpdyFrameChunkSize, 'a'); | |
6331 | |
6332 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( | |
6333 kRequestUrl, 1, initial_window_size + kUploadDataSize, LOWEST, NULL, 0)); | |
6334 | |
6335 // Full frames. | |
6336 scoped_ptr<SpdyFrame> body1( | |
6337 spdy_util_.ConstructSpdyBodyFrame( | |
6338 1, content.c_str(), content.size(), false)); | |
6339 | |
6340 // Last frame to zero out the window size. | |
6341 scoped_ptr<SpdyFrame> body2( | |
6342 spdy_util_.ConstructSpdyBodyFrame( | |
6343 1, content.c_str(), last_frame_size, false)); | |
6344 | |
6345 // Data frame to be sent once WINDOW_UPDATE frame is received. | |
6346 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
6347 | |
6348 // Fill in mock writes. | |
6349 scoped_ptr<MockWrite[]> writes(new MockWrite[num_writes]); | |
6350 size_t i = 0; | |
6351 writes[i] = CreateMockWrite(*req); | |
6352 for (i = 1; i < num_writes - 2; i++) | |
6353 writes[i] = CreateMockWrite(*body1); | |
6354 writes[i++] = CreateMockWrite(*body2); | |
6355 writes[i] = CreateMockWrite(*body3); | |
6356 | |
6357 // Construct read frame, give enough space to upload the rest of the | |
6358 // data. | |
6359 scoped_ptr<SpdyFrame> session_window_update( | |
6360 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize)); | |
6361 scoped_ptr<SpdyFrame> window_update( | |
6362 spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize)); | |
6363 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
6364 MockRead reads[] = { | |
6365 CreateMockRead(*session_window_update), | |
6366 CreateMockRead(*session_window_update), | |
6367 CreateMockRead(*window_update), | |
6368 CreateMockRead(*window_update), | |
6369 CreateMockRead(*reply), | |
6370 CreateMockRead(*body2), | |
6371 CreateMockRead(*body3), | |
6372 MockRead(ASYNC, 0, 0) // EOF | |
6373 }; | |
6374 | |
6375 // Skip the session window updates unless we're using SPDY/3.1 and | |
6376 // above. | |
6377 size_t read_offset = (GetParam().protocol >= kProtoSPDY31) ? 0 : 2; | |
6378 size_t num_reads = arraysize(reads) - read_offset; | |
6379 | |
6380 // Force all writes to happen before any read, last write will not | |
6381 // actually queue a frame, due to window size being 0. | |
6382 DelayedSocketData data(num_writes, reads + read_offset, num_reads, | |
6383 writes.get(), num_writes); | |
6384 | |
6385 ScopedVector<UploadElementReader> element_readers; | |
6386 std::string upload_data_string(initial_window_size, 'a'); | |
6387 upload_data_string.append(kUploadData, kUploadDataSize); | |
6388 element_readers.push_back(new UploadBytesElementReader( | |
6389 upload_data_string.c_str(), upload_data_string.size())); | |
6390 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
6391 | |
6392 HttpRequestInfo request; | |
6393 request.method = "POST"; | |
6394 request.url = GURL("http://www.google.com/"); | |
6395 request.upload_data_stream = &upload_data_stream; | |
6396 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
6397 BoundNetLog(), GetParam(), NULL); | |
6398 helper.AddData(&data); | |
6399 helper.RunPreTestSetup(); | |
6400 | |
6401 HttpNetworkTransaction* trans = helper.trans(); | |
6402 | |
6403 TestCompletionCallback callback; | |
6404 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
6405 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6406 | |
6407 base::RunLoop().RunUntilIdle(); // Write as much as we can. | |
6408 | |
6409 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
6410 ASSERT_TRUE(stream != NULL); | |
6411 ASSERT_TRUE(stream->stream() != NULL); | |
6412 EXPECT_EQ(0, stream->stream()->send_window_size()); | |
6413 // All the body data should have been read. | |
6414 // TODO(satorux): This is because of the weirdness in reading the request | |
6415 // body in OnSendBodyComplete(). See crbug.com/113107. | |
6416 EXPECT_TRUE(upload_data_stream.IsEOF()); | |
6417 // But the body is not yet fully sent (kUploadData is not yet sent) | |
6418 // since we're send-stalled. | |
6419 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control()); | |
6420 | |
6421 data.ForceNextRead(); // Read in WINDOW_UPDATE frame. | |
6422 rv = callback.WaitForResult(); | |
6423 helper.VerifyDataConsumed(); | |
6424 } | |
6425 | |
6426 // Test we correctly handle the case where the SETTINGS frame results in | |
6427 // unstalling the send window. | |
6428 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) { | |
6429 const int32 initial_window_size = | |
6430 SpdySession::GetInitialWindowSize(GetParam().protocol); | |
6431 | |
6432 // Number of frames we need to send to zero out the window size: data | |
6433 // frames plus SYN_STREAM plus the last data frame; also we need another | |
6434 // data frame that we will send once the SETTING is received, therefore +3. | |
6435 size_t num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3; | |
6436 | |
6437 // Calculate last frame's size; 0 size data frame is legal. | |
6438 size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize; | |
6439 | |
6440 // Construct content for a data frame of maximum size. | |
6441 std::string content(kMaxSpdyFrameChunkSize, 'a'); | |
6442 | |
6443 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( | |
6444 kRequestUrl, 1, initial_window_size + kUploadDataSize, LOWEST, NULL, 0)); | |
6445 | |
6446 // Full frames. | |
6447 scoped_ptr<SpdyFrame> body1( | |
6448 spdy_util_.ConstructSpdyBodyFrame( | |
6449 1, content.c_str(), content.size(), false)); | |
6450 | |
6451 // Last frame to zero out the window size. | |
6452 scoped_ptr<SpdyFrame> body2( | |
6453 spdy_util_.ConstructSpdyBodyFrame( | |
6454 1, content.c_str(), last_frame_size, false)); | |
6455 | |
6456 // Data frame to be sent once SETTINGS frame is received. | |
6457 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
6458 | |
6459 // Fill in mock reads/writes. | |
6460 std::vector<MockRead> reads; | |
6461 std::vector<MockWrite> writes; | |
6462 size_t i = 0; | |
6463 writes.push_back(CreateMockWrite(*req, i++)); | |
6464 while (i < num_writes - 2) | |
6465 writes.push_back(CreateMockWrite(*body1, i++)); | |
6466 writes.push_back(CreateMockWrite(*body2, i++)); | |
6467 | |
6468 // Construct read frame for SETTINGS that gives enough space to upload the | |
6469 // rest of the data. | |
6470 SettingsMap settings; | |
6471 settings[SETTINGS_INITIAL_WINDOW_SIZE] = | |
6472 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, initial_window_size * 2); | |
6473 scoped_ptr<SpdyFrame> settings_frame_large( | |
6474 spdy_util_.ConstructSpdySettings(settings)); | |
6475 | |
6476 reads.push_back(CreateMockRead(*settings_frame_large, i++)); | |
6477 | |
6478 scoped_ptr<SpdyFrame> session_window_update( | |
6479 spdy_util_.ConstructSpdyWindowUpdate(0, kUploadDataSize)); | |
6480 if (GetParam().protocol >= kProtoSPDY31) | |
6481 reads.push_back(CreateMockRead(*session_window_update, i++)); | |
6482 | |
6483 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); | |
6484 writes.push_back(CreateMockWrite(*settings_ack, i++)); | |
6485 | |
6486 writes.push_back(CreateMockWrite(*body3, i++)); | |
6487 | |
6488 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
6489 reads.push_back(CreateMockRead(*reply, i++)); | |
6490 reads.push_back(CreateMockRead(*body2, i++)); | |
6491 reads.push_back(CreateMockRead(*body3, i++)); | |
6492 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF | |
6493 | |
6494 // Force all writes to happen before any read, last write will not | |
6495 // actually queue a frame, due to window size being 0. | |
6496 DeterministicSocketData data(vector_as_array(&reads), reads.size(), | |
6497 vector_as_array(&writes), writes.size()); | |
6498 | |
6499 ScopedVector<UploadElementReader> element_readers; | |
6500 std::string upload_data_string(initial_window_size, 'a'); | |
6501 upload_data_string.append(kUploadData, kUploadDataSize); | |
6502 element_readers.push_back(new UploadBytesElementReader( | |
6503 upload_data_string.c_str(), upload_data_string.size())); | |
6504 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
6505 | |
6506 HttpRequestInfo request; | |
6507 request.method = "POST"; | |
6508 request.url = GURL("http://www.google.com/"); | |
6509 request.upload_data_stream = &upload_data_stream; | |
6510 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
6511 BoundNetLog(), GetParam(), NULL); | |
6512 helper.SetDeterministic(); | |
6513 helper.RunPreTestSetup(); | |
6514 helper.AddDeterministicData(&data); | |
6515 | |
6516 HttpNetworkTransaction* trans = helper.trans(); | |
6517 | |
6518 TestCompletionCallback callback; | |
6519 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
6520 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6521 | |
6522 data.RunFor(num_writes - 1); // Write as much as we can. | |
6523 | |
6524 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
6525 ASSERT_TRUE(stream != NULL); | |
6526 ASSERT_TRUE(stream->stream() != NULL); | |
6527 EXPECT_EQ(0, stream->stream()->send_window_size()); | |
6528 | |
6529 // All the body data should have been read. | |
6530 // TODO(satorux): This is because of the weirdness in reading the request | |
6531 // body in OnSendBodyComplete(). See crbug.com/113107. | |
6532 EXPECT_TRUE(upload_data_stream.IsEOF()); | |
6533 // But the body is not yet fully sent (kUploadData is not yet sent) | |
6534 // since we're send-stalled. | |
6535 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control()); | |
6536 | |
6537 data.RunFor(7); // Read in SETTINGS frame to unstall. | |
6538 rv = callback.WaitForResult(); | |
6539 helper.VerifyDataConsumed(); | |
6540 // If stream is NULL, that means it was unstalled and closed. | |
6541 EXPECT_TRUE(stream->stream() == NULL); | |
6542 } | |
6543 | |
6544 // Test we correctly handle the case where the SETTINGS frame results in a | |
6545 // negative send window size. | |
6546 TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) { | |
6547 const int32 initial_window_size = | |
6548 SpdySession::GetInitialWindowSize(GetParam().protocol); | |
6549 // Number of frames we need to send to zero out the window size: data | |
6550 // frames plus SYN_STREAM plus the last data frame; also we need another | |
6551 // data frame that we will send once the SETTING is received, therefore +3. | |
6552 size_t num_writes = initial_window_size / kMaxSpdyFrameChunkSize + 3; | |
6553 | |
6554 // Calculate last frame's size; 0 size data frame is legal. | |
6555 size_t last_frame_size = initial_window_size % kMaxSpdyFrameChunkSize; | |
6556 | |
6557 // Construct content for a data frame of maximum size. | |
6558 std::string content(kMaxSpdyFrameChunkSize, 'a'); | |
6559 | |
6560 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost( | |
6561 kRequestUrl, 1, initial_window_size + kUploadDataSize, LOWEST, NULL, 0)); | |
6562 | |
6563 // Full frames. | |
6564 scoped_ptr<SpdyFrame> body1( | |
6565 spdy_util_.ConstructSpdyBodyFrame( | |
6566 1, content.c_str(), content.size(), false)); | |
6567 | |
6568 // Last frame to zero out the window size. | |
6569 scoped_ptr<SpdyFrame> body2( | |
6570 spdy_util_.ConstructSpdyBodyFrame( | |
6571 1, content.c_str(), last_frame_size, false)); | |
6572 | |
6573 // Data frame to be sent once SETTINGS frame is received. | |
6574 scoped_ptr<SpdyFrame> body3(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
6575 | |
6576 // Fill in mock reads/writes. | |
6577 std::vector<MockRead> reads; | |
6578 std::vector<MockWrite> writes; | |
6579 size_t i = 0; | |
6580 writes.push_back(CreateMockWrite(*req, i++)); | |
6581 while (i < num_writes - 2) | |
6582 writes.push_back(CreateMockWrite(*body1, i++)); | |
6583 writes.push_back(CreateMockWrite(*body2, i++)); | |
6584 | |
6585 // Construct read frame for SETTINGS that makes the send_window_size | |
6586 // negative. | |
6587 SettingsMap new_settings; | |
6588 new_settings[SETTINGS_INITIAL_WINDOW_SIZE] = | |
6589 SettingsFlagsAndValue(SETTINGS_FLAG_NONE, initial_window_size / 2); | |
6590 scoped_ptr<SpdyFrame> settings_frame_small( | |
6591 spdy_util_.ConstructSpdySettings(new_settings)); | |
6592 // Construct read frames for WINDOW_UPDATE that makes the send_window_size | |
6593 // positive. | |
6594 scoped_ptr<SpdyFrame> session_window_update_init_size( | |
6595 spdy_util_.ConstructSpdyWindowUpdate(0, initial_window_size)); | |
6596 scoped_ptr<SpdyFrame> window_update_init_size( | |
6597 spdy_util_.ConstructSpdyWindowUpdate(1, initial_window_size)); | |
6598 | |
6599 reads.push_back(CreateMockRead(*settings_frame_small, i++)); | |
6600 reads.push_back(CreateMockRead(*session_window_update_init_size, i++)); | |
6601 reads.push_back(CreateMockRead(*window_update_init_size, i++)); | |
6602 | |
6603 scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck()); | |
6604 writes.push_back(CreateMockWrite(*settings_ack, i++)); | |
6605 | |
6606 writes.push_back(CreateMockWrite(*body3, i++)); | |
6607 | |
6608 scoped_ptr<SpdyFrame> reply(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); | |
6609 reads.push_back(CreateMockRead(*reply, i++)); | |
6610 reads.push_back(CreateMockRead(*body2, i++)); | |
6611 reads.push_back(CreateMockRead(*body3, i++)); | |
6612 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF | |
6613 | |
6614 // Force all writes to happen before any read, last write will not | |
6615 // actually queue a frame, due to window size being 0. | |
6616 DeterministicSocketData data(vector_as_array(&reads), reads.size(), | |
6617 vector_as_array(&writes), writes.size()); | |
6618 | |
6619 ScopedVector<UploadElementReader> element_readers; | |
6620 std::string upload_data_string(initial_window_size, 'a'); | |
6621 upload_data_string.append(kUploadData, kUploadDataSize); | |
6622 element_readers.push_back(new UploadBytesElementReader( | |
6623 upload_data_string.c_str(), upload_data_string.size())); | |
6624 ElementsUploadDataStream upload_data_stream(element_readers.Pass(), 0); | |
6625 | |
6626 HttpRequestInfo request; | |
6627 request.method = "POST"; | |
6628 request.url = GURL("http://www.google.com/"); | |
6629 request.upload_data_stream = &upload_data_stream; | |
6630 NormalSpdyTransactionHelper helper(request, DEFAULT_PRIORITY, | |
6631 BoundNetLog(), GetParam(), NULL); | |
6632 helper.SetDeterministic(); | |
6633 helper.RunPreTestSetup(); | |
6634 helper.AddDeterministicData(&data); | |
6635 | |
6636 HttpNetworkTransaction* trans = helper.trans(); | |
6637 | |
6638 TestCompletionCallback callback; | |
6639 int rv = trans->Start(&helper.request(), callback.callback(), BoundNetLog()); | |
6640 EXPECT_EQ(ERR_IO_PENDING, rv); | |
6641 | |
6642 data.RunFor(num_writes - 1); // Write as much as we can. | |
6643 | |
6644 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get()); | |
6645 ASSERT_TRUE(stream != NULL); | |
6646 ASSERT_TRUE(stream->stream() != NULL); | |
6647 EXPECT_EQ(0, stream->stream()->send_window_size()); | |
6648 | |
6649 // All the body data should have been read. | |
6650 // TODO(satorux): This is because of the weirdness in reading the request | |
6651 // body in OnSendBodyComplete(). See crbug.com/113107. | |
6652 EXPECT_TRUE(upload_data_stream.IsEOF()); | |
6653 // But the body is not yet fully sent (kUploadData is not yet sent) | |
6654 // since we're send-stalled. | |
6655 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control()); | |
6656 | |
6657 // Read in WINDOW_UPDATE or SETTINGS frame. | |
6658 data.RunFor((GetParam().protocol >= kProtoSPDY31) ? 9 : 8); | |
6659 rv = callback.WaitForResult(); | |
6660 helper.VerifyDataConsumed(); | |
6661 } | |
6662 | |
6663 TEST_P(SpdyNetworkTransactionTest, GoAwayOnOddPushStreamId) { | |
6664 if (spdy_util_.spdy_version() < SPDY3) | |
6665 return; | |
6666 | |
6667 scoped_ptr<SpdyHeaderBlock> push_headers(new SpdyHeaderBlock); | |
6668 spdy_util_.AddUrlToHeaderBlock("http://www.google.com/a.dat", | |
6669 push_headers.get()); | |
6670 scoped_ptr<SpdyFrame> push( | |
6671 spdy_util_.ConstructInitialSpdyPushFrame(push_headers.Pass(), 3, 1)); | |
6672 MockRead reads[] = {CreateMockRead(*push, 1)}; | |
6673 | |
6674 scoped_ptr<SpdyFrame> req( | |
6675 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
6676 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway( | |
6677 0, GOAWAY_PROTOCOL_ERROR, "Odd push stream id.")); | |
6678 MockWrite writes[] = { | |
6679 CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 2), | |
6680 }; | |
6681 | |
6682 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); | |
6683 NormalSpdyTransactionHelper helper( | |
6684 CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); | |
6685 helper.RunToCompletion(&data); | |
6686 TransactionHelperResult out = helper.output(); | |
6687 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
6688 } | |
6689 | |
6690 TEST_P(SpdyNetworkTransactionTest, | |
6691 GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted) { | |
6692 if (spdy_util_.spdy_version() < SPDY3) | |
6693 return; | |
6694 | |
6695 scoped_ptr<SpdyFrame> push_a(spdy_util_.ConstructSpdyPush( | |
6696 NULL, 0, 4, 1, "http://www.google.com/a.dat")); | |
6697 scoped_ptr<SpdyHeaderBlock> push_b_headers(new SpdyHeaderBlock); | |
6698 spdy_util_.AddUrlToHeaderBlock("http://www.google.com/b.dat", | |
6699 push_b_headers.get()); | |
6700 scoped_ptr<SpdyFrame> push_b( | |
6701 spdy_util_.ConstructInitialSpdyPushFrame(push_b_headers.Pass(), 2, 1)); | |
6702 MockRead reads[] = { | |
6703 CreateMockRead(*push_a, 1), CreateMockRead(*push_b, 2), | |
6704 }; | |
6705 | |
6706 scoped_ptr<SpdyFrame> req( | |
6707 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); | |
6708 scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway( | |
6709 4, | |
6710 GOAWAY_PROTOCOL_ERROR, | |
6711 "New push stream id must be greater than the last accepted.")); | |
6712 MockWrite writes[] = { | |
6713 CreateMockWrite(*req, 0), CreateMockWrite(*goaway, 3), | |
6714 }; | |
6715 | |
6716 DelayedSocketData data(1, reads, arraysize(reads), writes, arraysize(writes)); | |
6717 NormalSpdyTransactionHelper helper( | |
6718 CreateGetRequest(), DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); | |
6719 helper.RunToCompletion(&data); | |
6720 TransactionHelperResult out = helper.output(); | |
6721 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, out.rv); | |
6722 } | |
6723 | |
6724 class SpdyNetworkTransactionNoTLSUsageCheckTest | |
6725 : public SpdyNetworkTransactionTest { | |
6726 protected: | |
6727 void RunNoTLSUsageCheckTest(scoped_ptr<SSLSocketDataProvider> ssl_provider) { | |
6728 // Construct the request. | |
6729 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyGet( | |
6730 "https://www.google.com/", false, 1, LOWEST)); | |
6731 MockWrite writes[] = {CreateMockWrite(*req)}; | |
6732 | |
6733 scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); | |
6734 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true)); | |
6735 MockRead reads[] = { | |
6736 CreateMockRead(*resp), CreateMockRead(*body), | |
6737 MockRead(ASYNC, 0, 0) // EOF | |
6738 }; | |
6739 | |
6740 DelayedSocketData data( | |
6741 1, reads, arraysize(reads), writes, arraysize(writes)); | |
6742 HttpRequestInfo request; | |
6743 request.method = "GET"; | |
6744 request.url = GURL("https://www.google.com/"); | |
6745 NormalSpdyTransactionHelper helper( | |
6746 request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); | |
6747 helper.RunToCompletionWithSSLData(&data, ssl_provider.Pass()); | |
6748 TransactionHelperResult out = helper.output(); | |
6749 EXPECT_EQ(OK, out.rv); | |
6750 EXPECT_EQ("HTTP/1.1 200 OK", out.status_line); | |
6751 EXPECT_EQ("hello!", out.response_data); | |
6752 } | |
6753 }; | |
6754 | |
6755 //----------------------------------------------------------------------------- | |
6756 // All tests are run with three different connection types: SPDY after NPN | |
6757 // negotiation, SPDY without SSL, and SPDY with SSL. | |
6758 // | |
6759 // TODO(akalin): Use ::testing::Combine() when we are able to use | |
6760 // <tr1/tuple>. | |
6761 INSTANTIATE_TEST_CASE_P( | |
6762 Spdy, | |
6763 SpdyNetworkTransactionNoTLSUsageCheckTest, | |
6764 ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN))); | |
6765 | |
6766 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSVersionTooOld) { | |
6767 scoped_ptr<SSLSocketDataProvider> ssl_provider( | |
6768 new SSLSocketDataProvider(ASYNC, OK)); | |
6769 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3, | |
6770 &ssl_provider->connection_status); | |
6771 | |
6772 RunNoTLSUsageCheckTest(ssl_provider.Pass()); | |
6773 } | |
6774 | |
6775 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSCipherSuiteSucky) { | |
6776 scoped_ptr<SSLSocketDataProvider> ssl_provider( | |
6777 new SSLSocketDataProvider(ASYNC, OK)); | |
6778 // Set to TLS_RSA_WITH_NULL_MD5 | |
6779 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider->connection_status); | |
6780 | |
6781 RunNoTLSUsageCheckTest(ssl_provider.Pass()); | |
6782 } | |
6783 | |
6784 class SpdyNetworkTransactionTLSUsageCheckTest | |
6785 : public SpdyNetworkTransactionTest { | |
6786 protected: | |
6787 void RunTLSUsageCheckTest(scoped_ptr<SSLSocketDataProvider> ssl_provider) { | |
6788 scoped_ptr<SpdyFrame> goaway( | |
6789 spdy_util_.ConstructSpdyGoAway(0, GOAWAY_INADEQUATE_SECURITY, "")); | |
6790 MockWrite writes[] = {CreateMockWrite(*goaway)}; | |
6791 | |
6792 DelayedSocketData data(1, NULL, 0, writes, arraysize(writes)); | |
6793 HttpRequestInfo request; | |
6794 request.method = "GET"; | |
6795 request.url = GURL("https://www.google.com/"); | |
6796 NormalSpdyTransactionHelper helper( | |
6797 request, DEFAULT_PRIORITY, BoundNetLog(), GetParam(), NULL); | |
6798 helper.RunToCompletionWithSSLData(&data, ssl_provider.Pass()); | |
6799 TransactionHelperResult out = helper.output(); | |
6800 EXPECT_EQ(ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY, out.rv); | |
6801 } | |
6802 }; | |
6803 | |
6804 INSTANTIATE_TEST_CASE_P( | |
6805 Spdy, | |
6806 SpdyNetworkTransactionTLSUsageCheckTest, | |
6807 ::testing::Values( | |
6808 SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYNPN), | |
6809 SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYNPN))); | |
6810 | |
6811 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) { | |
6812 scoped_ptr<SSLSocketDataProvider> ssl_provider( | |
6813 new SSLSocketDataProvider(ASYNC, OK)); | |
6814 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3, | |
6815 &ssl_provider->connection_status); | |
6816 | |
6817 RunTLSUsageCheckTest(ssl_provider.Pass()); | |
6818 } | |
6819 | |
6820 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSCipherSuiteSucky) { | |
6821 scoped_ptr<SSLSocketDataProvider> ssl_provider( | |
6822 new SSLSocketDataProvider(ASYNC, OK)); | |
6823 // Set to TLS_RSA_WITH_NULL_MD5 | |
6824 SSLConnectionStatusSetCipherSuite(0x1, &ssl_provider->connection_status); | |
6825 | |
6826 RunTLSUsageCheckTest(ssl_provider.Pass()); | |
6827 } | |
6828 | |
6829 } // namespace net | |
OLD | NEW |