Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(674)

Side by Side Diff: net/spdy/spdy_network_transaction_unittest.cc

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

Powered by Google App Engine
This is Rietveld 408576698