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 "net/spdy/spdy_http_stream.h"
6
7 #include <stdint.h>
8
9 #include <string>
10
11 #include "base/bind.h"
12 #include "base/run_loop.h"
13 #include "base/stl_util.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "crypto/ec_private_key.h"
16 #include "crypto/ec_signature_creator.h"
17 #include "crypto/signature_creator.h"
18 #include "net/base/chunked_upload_data_stream.h"
19 #include "net/base/load_timing_info.h"
20 #include "net/base/load_timing_info_test_util.h"
21 #include "net/base/test_completion_callback.h"
22 #include "net/cert/asn1_util.h"
23 #include "net/http/http_request_info.h"
24 #include "net/http/http_response_headers.h"
25 #include "net/http/http_response_info.h"
26 #include "net/log/net_log_with_source.h"
27 #include "net/log/test_net_log.h"
28 #include "net/socket/socket_tag.h"
29 #include "net/socket/socket_test_util.h"
30 #include "net/spdy/spdy_http_utils.h"
31 #include "net/spdy/spdy_test_util_common.h"
32 #include "net/test/cert_test_util.h"
33 #include "net/test/gtest_util.h"
34 #include "net/test/test_data_directory.h"
35 #include "net/test/test_with_task_environment.h"
36 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
37 #include "testing/gmock/include/gmock/gmock.h"
38 #include "testing/gtest/include/gtest/gtest.h"
39
40 namespace net {
41
42 namespace test {
43
44 namespace {
45
46 // Tests the load timing of a stream that's connected and is not the first
47 // request sent on a connection.
TestLoadTimingReused(const HttpStream & stream)48 void TestLoadTimingReused(const HttpStream& stream) {
49 LoadTimingInfo load_timing_info;
50 EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
51
52 EXPECT_TRUE(load_timing_info.socket_reused);
53 EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
54
55 ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
56 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
57 }
58
59 // Tests the load timing of a stream that's connected and using a fresh
60 // connection.
TestLoadTimingNotReused(const HttpStream & stream)61 void TestLoadTimingNotReused(const HttpStream& stream) {
62 LoadTimingInfo load_timing_info;
63 EXPECT_TRUE(stream.GetLoadTimingInfo(&load_timing_info));
64
65 EXPECT_FALSE(load_timing_info.socket_reused);
66 EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
67
68 ExpectConnectTimingHasTimes(
69 load_timing_info.connect_timing,
70 CONNECT_TIMING_HAS_DNS_TIMES | CONNECT_TIMING_HAS_SSL_TIMES);
71 ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
72 }
73
74 class ReadErrorUploadDataStream : public UploadDataStream {
75 public:
76 enum class FailureMode { SYNC, ASYNC };
77
ReadErrorUploadDataStream(FailureMode mode)78 explicit ReadErrorUploadDataStream(FailureMode mode)
79 : UploadDataStream(true, 0), async_(mode) {}
80
81 private:
CompleteRead()82 void CompleteRead() { UploadDataStream::OnReadCompleted(ERR_FAILED); }
83
84 // UploadDataStream implementation:
InitInternal(const NetLogWithSource & net_log)85 int InitInternal(const NetLogWithSource& net_log) override { return OK; }
86
ReadInternal(IOBuffer * buf,int buf_len)87 int ReadInternal(IOBuffer* buf, int buf_len) override {
88 if (async_ == FailureMode::ASYNC) {
89 base::ThreadTaskRunnerHandle::Get()->PostTask(
90 FROM_HERE, base::BindOnce(&ReadErrorUploadDataStream::CompleteRead,
91 weak_factory_.GetWeakPtr()));
92 return ERR_IO_PENDING;
93 }
94 return ERR_FAILED;
95 }
96
ResetInternal()97 void ResetInternal() override {}
98
99 const FailureMode async_;
100
101 base::WeakPtrFactory<ReadErrorUploadDataStream> weak_factory_{this};
102
103 DISALLOW_COPY_AND_ASSIGN(ReadErrorUploadDataStream);
104 };
105
106 class CancelStreamCallback : public TestCompletionCallbackBase {
107 public:
CancelStreamCallback(SpdyHttpStream * stream)108 explicit CancelStreamCallback(SpdyHttpStream* stream) : stream_(stream) {}
109
callback()110 CompletionOnceCallback callback() {
111 return base::BindOnce(&CancelStreamCallback::CancelStream,
112 base::Unretained(this));
113 }
114
115 private:
CancelStream(int result)116 void CancelStream(int result) {
117 stream_->Cancel();
118 SetResult(result);
119 }
120
121 SpdyHttpStream* stream_;
122 };
123
124 } // namespace
125
126 class SpdyHttpStreamTest : public TestWithTaskEnvironment {
127 public:
SpdyHttpStreamTest()128 SpdyHttpStreamTest()
129 : url_(kDefaultUrl),
130 host_port_pair_(HostPortPair::FromURL(url_)),
131 key_(host_port_pair_,
132 ProxyServer::Direct(),
133 PRIVACY_MODE_DISABLED,
134 SpdySessionKey::IsProxySession::kFalse,
135 SocketTag(),
136 NetworkIsolationKey(),
137 false /* disable_secure_dns */),
138 ssl_(SYNCHRONOUS, OK) {
139 session_deps_.net_log = &net_log_;
140 }
141
142 ~SpdyHttpStreamTest() override = default;
143
144 protected:
TearDown()145 void TearDown() override {
146 crypto::ECSignatureCreator::SetFactoryForTesting(nullptr);
147 base::RunLoop().RunUntilIdle();
148 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
149 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
150 }
151
152 // Initializes the session using SequencedSocketData.
InitSession(base::span<const MockRead> reads,base::span<const MockWrite> writes)153 void InitSession(base::span<const MockRead> reads,
154 base::span<const MockWrite> writes) {
155 sequenced_data_ = std::make_unique<SequencedSocketData>(reads, writes);
156 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
157
158 ssl_.ssl_info.cert =
159 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
160 ASSERT_TRUE(ssl_.ssl_info.cert);
161 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_);
162
163 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
164 session_ = CreateSpdySession(http_session_.get(), key_, NetLogWithSource());
165 }
166
167 SpdyTestUtil spdy_util_;
168 RecordingTestNetLog net_log_;
169 SpdySessionDependencies session_deps_;
170 const GURL url_;
171 const HostPortPair host_port_pair_;
172 const SpdySessionKey key_;
173 std::unique_ptr<SequencedSocketData> sequenced_data_;
174 std::unique_ptr<HttpNetworkSession> http_session_;
175 base::WeakPtr<SpdySession> session_;
176
177 private:
178 MockECSignatureCreatorFactory ec_signature_creator_factory_;
179 SSLSocketDataProvider ssl_;
180 };
181
TEST_F(SpdyHttpStreamTest,SendRequest)182 TEST_F(SpdyHttpStreamTest, SendRequest) {
183 spdy::SpdySerializedFrame req(
184 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
185 MockWrite writes[] = {
186 CreateMockWrite(req, 0),
187 };
188 spdy::SpdySerializedFrame resp(
189 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
190 MockRead reads[] = {
191 CreateMockRead(resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
192 };
193
194 InitSession(reads, writes);
195
196 HttpRequestInfo request;
197 request.method = "GET";
198 request.url = url_;
199 request.traffic_annotation =
200 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
201 TestCompletionCallback callback;
202 HttpResponseInfo response;
203 HttpRequestHeaders headers;
204 NetLogWithSource net_log;
205 auto http_stream = std::make_unique<SpdyHttpStream>(
206 session_, kNoPushedStreamFound, net_log.source());
207 // Make sure getting load timing information the stream early does not crash.
208 LoadTimingInfo load_timing_info;
209 EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
210
211 ASSERT_THAT(http_stream->InitializeStream(&request, true, DEFAULT_PRIORITY,
212 net_log, CompletionOnceCallback()),
213 IsOk());
214 EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
215
216 EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
217 IsError(ERR_IO_PENDING));
218 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
219 EXPECT_FALSE(http_stream->GetLoadTimingInfo(&load_timing_info));
220
221 callback.WaitForResult();
222
223 // Can get timing information once the stream connects.
224 TestLoadTimingNotReused(*http_stream);
225
226 // Because we abandoned the stream, we don't expect to find a session in the
227 // pool anymore.
228 EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
229
230 TestLoadTimingNotReused(*http_stream);
231 http_stream->Close(true);
232 // Test that there's no crash when trying to get the load timing after the
233 // stream has been closed.
234 TestLoadTimingNotReused(*http_stream);
235
236 EXPECT_EQ(static_cast<int64_t>(req.size()), http_stream->GetTotalSentBytes());
237 EXPECT_EQ(static_cast<int64_t>(resp.size()),
238 http_stream->GetTotalReceivedBytes());
239 }
240
TEST_F(SpdyHttpStreamTest,RequestInfoDestroyedBeforeRead)241 TEST_F(SpdyHttpStreamTest, RequestInfoDestroyedBeforeRead) {
242 spdy::SpdySerializedFrame req(
243 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
244 MockWrite writes[] = {CreateMockWrite(req, 0)};
245 spdy::SpdySerializedFrame resp(
246 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
247 spdy::SpdySerializedFrame body(
248 spdy_util_.ConstructSpdyDataFrame(1, "", true));
249 MockRead reads[] = {
250 CreateMockRead(resp, 1), CreateMockRead(body, 2),
251 MockRead(ASYNC, 0, 3) // EOF
252 };
253
254 InitSession(reads, writes);
255
256 std::unique_ptr<HttpRequestInfo> request =
257 std::make_unique<HttpRequestInfo>();
258 request->method = "GET";
259 request->url = url_;
260 request->traffic_annotation =
261 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
262 TestCompletionCallback callback;
263 HttpResponseInfo response;
264 HttpRequestHeaders headers;
265 NetLogWithSource net_log;
266 auto http_stream = std::make_unique<SpdyHttpStream>(
267 session_, kNoPushedStreamFound, net_log.source());
268
269 ASSERT_THAT(
270 http_stream->InitializeStream(request.get(), true, DEFAULT_PRIORITY,
271 net_log, CompletionOnceCallback()),
272 IsOk());
273 EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
274 IsError(ERR_IO_PENDING));
275 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
276
277 EXPECT_LE(0, callback.WaitForResult());
278
279 TestLoadTimingNotReused(*http_stream);
280 LoadTimingInfo load_timing_info;
281 EXPECT_TRUE(http_stream->GetLoadTimingInfo(&load_timing_info));
282
283 // Perform all async reads.
284 base::RunLoop().RunUntilIdle();
285
286 // Destroy the request info before Read starts.
287 request.reset();
288
289 // Read stream to completion.
290 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(1);
291 ASSERT_EQ(0,
292 http_stream->ReadResponseBody(buf.get(), 1, callback.callback()));
293
294 // Stream 1 has been read to completion.
295 TestLoadTimingNotReused(*http_stream);
296
297 EXPECT_EQ(static_cast<int64_t>(req.size()), http_stream->GetTotalSentBytes());
298 EXPECT_EQ(static_cast<int64_t>(resp.size() + body.size()),
299 http_stream->GetTotalReceivedBytes());
300 }
301
TEST_F(SpdyHttpStreamTest,LoadTimingTwoRequests)302 TEST_F(SpdyHttpStreamTest, LoadTimingTwoRequests) {
303 spdy::SpdySerializedFrame req1(
304 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
305 spdy::SpdySerializedFrame req2(
306 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
307 MockWrite writes[] = {
308 CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
309 };
310 spdy::SpdySerializedFrame resp1(
311 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
312 spdy::SpdySerializedFrame body1(
313 spdy_util_.ConstructSpdyDataFrame(1, "", true));
314 spdy::SpdySerializedFrame resp2(
315 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
316 spdy::SpdySerializedFrame body2(
317 spdy_util_.ConstructSpdyDataFrame(3, "", true));
318 MockRead reads[] = {
319 CreateMockRead(resp1, 2), CreateMockRead(body1, 3),
320 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
321 MockRead(ASYNC, 0, 6) // EOF
322 };
323
324 InitSession(reads, writes);
325
326 HttpRequestInfo request1;
327 request1.method = "GET";
328 request1.url = url_;
329 request1.traffic_annotation =
330 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
331 TestCompletionCallback callback1;
332 HttpResponseInfo response1;
333 HttpRequestHeaders headers1;
334 NetLogWithSource net_log;
335 auto http_stream1 = std::make_unique<SpdyHttpStream>(
336 session_, kNoPushedStreamFound, net_log.source());
337
338 HttpRequestInfo request2;
339 request2.method = "GET";
340 request2.url = url_;
341 request2.traffic_annotation =
342 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
343 TestCompletionCallback callback2;
344 HttpResponseInfo response2;
345 HttpRequestHeaders headers2;
346 auto http_stream2 = std::make_unique<SpdyHttpStream>(
347 session_, kNoPushedStreamFound, net_log.source());
348
349 // First write.
350 ASSERT_THAT(http_stream1->InitializeStream(&request1, true, DEFAULT_PRIORITY,
351 net_log, CompletionOnceCallback()),
352 IsOk());
353 EXPECT_THAT(
354 http_stream1->SendRequest(headers1, &response1, callback1.callback()),
355 IsError(ERR_IO_PENDING));
356 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
357
358 EXPECT_LE(0, callback1.WaitForResult());
359
360 TestLoadTimingNotReused(*http_stream1);
361 LoadTimingInfo load_timing_info1;
362 LoadTimingInfo load_timing_info2;
363 EXPECT_TRUE(http_stream1->GetLoadTimingInfo(&load_timing_info1));
364 EXPECT_FALSE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
365
366 // Second write.
367 ASSERT_THAT(http_stream2->InitializeStream(&request2, true, DEFAULT_PRIORITY,
368 net_log, CompletionOnceCallback()),
369 IsOk());
370 EXPECT_THAT(
371 http_stream2->SendRequest(headers2, &response2, callback2.callback()),
372 IsError(ERR_IO_PENDING));
373 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
374
375 EXPECT_LE(0, callback2.WaitForResult());
376
377 // Perform all async reads.
378 base::RunLoop().RunUntilIdle();
379
380 TestLoadTimingReused(*http_stream2);
381 EXPECT_TRUE(http_stream2->GetLoadTimingInfo(&load_timing_info2));
382 EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
383
384 // Read stream 1 to completion, before making sure we can still read load
385 // timing from both streams.
386 scoped_refptr<IOBuffer> buf1 = base::MakeRefCounted<IOBuffer>(1);
387 ASSERT_EQ(
388 0, http_stream1->ReadResponseBody(buf1.get(), 1, callback1.callback()));
389
390 // Stream 1 has been read to completion.
391 TestLoadTimingNotReused(*http_stream1);
392
393 EXPECT_EQ(static_cast<int64_t>(req1.size()),
394 http_stream1->GetTotalSentBytes());
395 EXPECT_EQ(static_cast<int64_t>(resp1.size() + body1.size()),
396 http_stream1->GetTotalReceivedBytes());
397
398 // Stream 2 still has queued body data.
399 TestLoadTimingReused(*http_stream2);
400
401 EXPECT_EQ(static_cast<int64_t>(req2.size()),
402 http_stream2->GetTotalSentBytes());
403 EXPECT_EQ(static_cast<int64_t>(resp2.size() + body2.size()),
404 http_stream2->GetTotalReceivedBytes());
405 }
406
TEST_F(SpdyHttpStreamTest,SendChunkedPost)407 TEST_F(SpdyHttpStreamTest, SendChunkedPost) {
408 spdy::SpdySerializedFrame req(
409 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
410 spdy::SpdySerializedFrame body(
411 spdy_util_.ConstructSpdyDataFrame(1, kUploadData,
412 /*fin=*/true));
413 MockWrite writes[] = {
414 CreateMockWrite(req, 0), // request
415 CreateMockWrite(body, 1) // POST upload frame
416 };
417
418 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
419 MockRead reads[] = {
420 CreateMockRead(resp, 2), CreateMockRead(body, 3, SYNCHRONOUS),
421 MockRead(SYNCHRONOUS, 0, 4) // EOF
422 };
423
424 InitSession(reads, writes);
425
426 ChunkedUploadDataStream upload_stream(0);
427 const int kFirstChunkSize = kUploadDataSize/2;
428 upload_stream.AppendData(kUploadData, kFirstChunkSize, false);
429 upload_stream.AppendData(kUploadData + kFirstChunkSize,
430 kUploadDataSize - kFirstChunkSize, true);
431
432 HttpRequestInfo request;
433 request.method = "POST";
434 request.url = url_;
435 request.traffic_annotation =
436 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
437 request.upload_data_stream = &upload_stream;
438
439 ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
440 NetLogWithSource()),
441 IsOk());
442
443 TestCompletionCallback callback;
444 HttpResponseInfo response;
445 HttpRequestHeaders headers;
446 NetLogWithSource net_log;
447 SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
448 ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
449 net_log, CompletionOnceCallback()),
450 IsOk());
451
452 EXPECT_THAT(http_stream.SendRequest(headers, &response, callback.callback()),
453 IsError(ERR_IO_PENDING));
454 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
455
456 EXPECT_THAT(callback.WaitForResult(), IsOk());
457
458 EXPECT_EQ(static_cast<int64_t>(req.size() + body.size()),
459 http_stream.GetTotalSentBytes());
460 EXPECT_EQ(static_cast<int64_t>(resp.size() + body.size()),
461 http_stream.GetTotalReceivedBytes());
462
463 // Because the server closed the connection, we there shouldn't be a session
464 // in the pool anymore.
465 EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
466 }
467
468 // This unittest tests the request callback is properly called and handled.
TEST_F(SpdyHttpStreamTest,SendChunkedPostLastEmpty)469 TEST_F(SpdyHttpStreamTest, SendChunkedPostLastEmpty) {
470 spdy::SpdySerializedFrame req(
471 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
472 spdy::SpdySerializedFrame chunk(
473 spdy_util_.ConstructSpdyDataFrame(1, "", true));
474 MockWrite writes[] = {
475 CreateMockWrite(req, 0), // request
476 CreateMockWrite(chunk, 1),
477 };
478
479 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
480 MockRead reads[] = {
481 CreateMockRead(resp, 2), CreateMockRead(chunk, 3, SYNCHRONOUS),
482 MockRead(SYNCHRONOUS, 0, 4) // EOF
483 };
484
485 InitSession(reads, writes);
486
487 ChunkedUploadDataStream upload_stream(0);
488 upload_stream.AppendData(nullptr, 0, true);
489
490 HttpRequestInfo request;
491 request.method = "POST";
492 request.url = url_;
493 request.traffic_annotation =
494 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
495 request.upload_data_stream = &upload_stream;
496
497 ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
498 NetLogWithSource()),
499 IsOk());
500
501 TestCompletionCallback callback;
502 HttpResponseInfo response;
503 HttpRequestHeaders headers;
504 NetLogWithSource net_log;
505 SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
506 ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
507 net_log, CompletionOnceCallback()),
508 IsOk());
509 EXPECT_THAT(http_stream.SendRequest(headers, &response, callback.callback()),
510 IsError(ERR_IO_PENDING));
511 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
512
513 EXPECT_THAT(callback.WaitForResult(), IsOk());
514
515 EXPECT_EQ(static_cast<int64_t>(req.size() + chunk.size()),
516 http_stream.GetTotalSentBytes());
517 EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk.size()),
518 http_stream.GetTotalReceivedBytes());
519
520 // Because the server closed the connection, there shouldn't be a session
521 // in the pool anymore.
522 EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
523 }
524
TEST_F(SpdyHttpStreamTest,ConnectionClosedDuringChunkedPost)525 TEST_F(SpdyHttpStreamTest, ConnectionClosedDuringChunkedPost) {
526 spdy::SpdySerializedFrame req(
527 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
528 spdy::SpdySerializedFrame body(
529 spdy_util_.ConstructSpdyDataFrame(1, kUploadData,
530 /*fin=*/false));
531 MockWrite writes[] = {
532 CreateMockWrite(req, 0), // Request
533 CreateMockWrite(body, 1) // First POST upload frame
534 };
535
536 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
537 MockRead reads[] = {
538 MockRead(ASYNC, ERR_CONNECTION_CLOSED, 2) // Server hangs up early.
539 };
540
541 InitSession(reads, writes);
542
543 ChunkedUploadDataStream upload_stream(0);
544 // Append first chunk.
545 upload_stream.AppendData(kUploadData, kUploadDataSize, false);
546
547 HttpRequestInfo request;
548 request.method = "POST";
549 request.url = url_;
550 request.traffic_annotation =
551 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
552 request.upload_data_stream = &upload_stream;
553
554 ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
555 NetLogWithSource()),
556 IsOk());
557
558 TestCompletionCallback callback;
559 HttpResponseInfo response;
560 HttpRequestHeaders headers;
561 NetLogWithSource net_log;
562 SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
563 ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
564 net_log, CompletionOnceCallback()),
565 IsOk());
566
567 EXPECT_THAT(http_stream.SendRequest(headers, &response, callback.callback()),
568 IsError(ERR_IO_PENDING));
569 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
570
571 EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
572
573 EXPECT_EQ(static_cast<int64_t>(req.size() + body.size()),
574 http_stream.GetTotalSentBytes());
575 EXPECT_EQ(0, http_stream.GetTotalReceivedBytes());
576
577 // Because the server closed the connection, we there shouldn't be a session
578 // in the pool anymore.
579 EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
580
581 // Appending a second chunk now should not result in a crash.
582 upload_stream.AppendData(kUploadData, kUploadDataSize, true);
583 // Appending data is currently done synchronously, but seems best to be
584 // paranoid.
585 base::RunLoop().RunUntilIdle();
586
587 // The total sent and received bytes should be unchanged.
588 EXPECT_EQ(static_cast<int64_t>(req.size() + body.size()),
589 http_stream.GetTotalSentBytes());
590 EXPECT_EQ(0, http_stream.GetTotalReceivedBytes());
591 }
592
593 // Test to ensure the SpdyStream state machine does not get confused when a
594 // chunk becomes available while a write is pending.
TEST_F(SpdyHttpStreamTest,DelayedSendChunkedPost)595 TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPost) {
596 const char kUploadData1[] = "12345678";
597 const int kUploadData1Size = base::size(kUploadData1) - 1;
598 spdy::SpdySerializedFrame req(
599 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
600 spdy::SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, false));
601 spdy::SpdySerializedFrame chunk2(
602 spdy_util_.ConstructSpdyDataFrame(1, kUploadData1, false));
603 spdy::SpdySerializedFrame chunk3(spdy_util_.ConstructSpdyDataFrame(1, true));
604 MockWrite writes[] = {
605 CreateMockWrite(req, 0),
606 CreateMockWrite(chunk1, 1), // POST upload frames
607 CreateMockWrite(chunk2, 2), CreateMockWrite(chunk3, 3),
608 };
609 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
610 MockRead reads[] = {
611 CreateMockRead(resp, 4), CreateMockRead(chunk1, 5),
612 CreateMockRead(chunk2, 6), CreateMockRead(chunk3, 7),
613 MockRead(ASYNC, 0, 8) // EOF
614 };
615
616 InitSession(reads, writes);
617
618 ChunkedUploadDataStream upload_stream(0);
619
620 HttpRequestInfo request;
621 request.method = "POST";
622 request.url = url_;
623 request.traffic_annotation =
624 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
625 request.upload_data_stream = &upload_stream;
626
627 ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
628 NetLogWithSource()),
629 IsOk());
630 upload_stream.AppendData(kUploadData, kUploadDataSize, false);
631
632 NetLogWithSource net_log;
633 auto http_stream = std::make_unique<SpdyHttpStream>(
634 session_, kNoPushedStreamFound, net_log.source());
635 ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY,
636 net_log, CompletionOnceCallback()),
637 IsOk());
638
639 TestCompletionCallback callback;
640 HttpRequestHeaders headers;
641 HttpResponseInfo response;
642 // This will attempt to Write() the initial request and headers, which will
643 // complete asynchronously.
644 EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
645 IsError(ERR_IO_PENDING));
646 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
647
648 // Complete the initial request write and the first chunk.
649 base::RunLoop().RunUntilIdle();
650 ASSERT_FALSE(callback.have_result());
651
652 // Now append the final two chunks which will enqueue two more writes.
653 upload_stream.AppendData(kUploadData1, kUploadData1Size, false);
654 upload_stream.AppendData(kUploadData, kUploadDataSize, true);
655
656 // Finish writing all the chunks and do all reads.
657 base::RunLoop().RunUntilIdle();
658 ASSERT_TRUE(callback.have_result());
659 EXPECT_THAT(callback.WaitForResult(), IsOk());
660
661 EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size() + chunk2.size() +
662 chunk3.size()),
663 http_stream->GetTotalSentBytes());
664 EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk1.size() + chunk2.size() +
665 chunk3.size()),
666 http_stream->GetTotalReceivedBytes());
667
668 // Check response headers.
669 ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
670
671 // Check |chunk1| response.
672 scoped_refptr<IOBuffer> buf1 =
673 base::MakeRefCounted<IOBuffer>(kUploadDataSize);
674 ASSERT_EQ(kUploadDataSize,
675 http_stream->ReadResponseBody(
676 buf1.get(), kUploadDataSize, callback.callback()));
677 EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
678
679 // Check |chunk2| response.
680 scoped_refptr<IOBuffer> buf2 =
681 base::MakeRefCounted<IOBuffer>(kUploadData1Size);
682 ASSERT_EQ(kUploadData1Size,
683 http_stream->ReadResponseBody(
684 buf2.get(), kUploadData1Size, callback.callback()));
685 EXPECT_EQ(kUploadData1, std::string(buf2->data(), kUploadData1Size));
686
687 // Check |chunk3| response.
688 scoped_refptr<IOBuffer> buf3 =
689 base::MakeRefCounted<IOBuffer>(kUploadDataSize);
690 ASSERT_EQ(kUploadDataSize,
691 http_stream->ReadResponseBody(
692 buf3.get(), kUploadDataSize, callback.callback()));
693 EXPECT_EQ(kUploadData, std::string(buf3->data(), kUploadDataSize));
694
695 ASSERT_TRUE(response.headers.get());
696 ASSERT_EQ(200, response.headers->response_code());
697 }
698
699 // Test that the SpdyStream state machine can handle sending a final empty data
700 // frame when uploading a chunked data stream.
TEST_F(SpdyHttpStreamTest,DelayedSendChunkedPostWithEmptyFinalDataFrame)701 TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPostWithEmptyFinalDataFrame) {
702 spdy::SpdySerializedFrame req(
703 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
704 spdy::SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, false));
705 spdy::SpdySerializedFrame chunk2(
706 spdy_util_.ConstructSpdyDataFrame(1, "", true));
707 MockWrite writes[] = {
708 CreateMockWrite(req, 0),
709 CreateMockWrite(chunk1, 1), // POST upload frames
710 CreateMockWrite(chunk2, 2),
711 };
712 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
713 MockRead reads[] = {
714 CreateMockRead(resp, 3), CreateMockRead(chunk1, 4),
715 CreateMockRead(chunk2, 5), MockRead(ASYNC, 0, 6) // EOF
716 };
717
718 InitSession(reads, writes);
719
720 ChunkedUploadDataStream upload_stream(0);
721
722 HttpRequestInfo request;
723 request.method = "POST";
724 request.url = url_;
725 request.traffic_annotation =
726 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
727 request.upload_data_stream = &upload_stream;
728
729 ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
730 NetLogWithSource()),
731 IsOk());
732 upload_stream.AppendData(kUploadData, kUploadDataSize, false);
733
734 NetLogWithSource net_log;
735 auto http_stream = std::make_unique<SpdyHttpStream>(
736 session_, kNoPushedStreamFound, net_log.source());
737 ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY,
738 net_log, CompletionOnceCallback()),
739 IsOk());
740
741 TestCompletionCallback callback;
742 HttpRequestHeaders headers;
743 HttpResponseInfo response;
744 // This will attempt to Write() the initial request and headers, which will
745 // complete asynchronously.
746 EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
747 IsError(ERR_IO_PENDING));
748 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
749
750 // Complete the initial request write and the first chunk.
751 base::RunLoop().RunUntilIdle();
752 ASSERT_FALSE(callback.have_result());
753
754 EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size()),
755 http_stream->GetTotalSentBytes());
756 EXPECT_EQ(0, http_stream->GetTotalReceivedBytes());
757
758 // Now end the stream with an empty data frame and the FIN set.
759 upload_stream.AppendData(nullptr, 0, true);
760
761 // Finish writing the final frame, and perform all reads.
762 base::RunLoop().RunUntilIdle();
763 ASSERT_TRUE(callback.have_result());
764 EXPECT_THAT(callback.WaitForResult(), IsOk());
765
766 // Check response headers.
767 ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
768
769 EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size() + chunk2.size()),
770 http_stream->GetTotalSentBytes());
771 EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk1.size() + chunk2.size()),
772 http_stream->GetTotalReceivedBytes());
773
774 // Check |chunk1| response.
775 scoped_refptr<IOBuffer> buf1 =
776 base::MakeRefCounted<IOBuffer>(kUploadDataSize);
777 ASSERT_EQ(kUploadDataSize,
778 http_stream->ReadResponseBody(
779 buf1.get(), kUploadDataSize, callback.callback()));
780 EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
781
782 // Check |chunk2| response.
783 ASSERT_EQ(0,
784 http_stream->ReadResponseBody(
785 buf1.get(), kUploadDataSize, callback.callback()));
786
787 ASSERT_TRUE(response.headers.get());
788 ASSERT_EQ(200, response.headers->response_code());
789 }
790
791 // Test that the SpdyStream state machine handles a chunked upload with no
792 // payload. Unclear if this is a case worth supporting.
TEST_F(SpdyHttpStreamTest,ChunkedPostWithEmptyPayload)793 TEST_F(SpdyHttpStreamTest, ChunkedPostWithEmptyPayload) {
794 spdy::SpdySerializedFrame req(
795 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
796 spdy::SpdySerializedFrame chunk(
797 spdy_util_.ConstructSpdyDataFrame(1, "", true));
798 MockWrite writes[] = {
799 CreateMockWrite(req, 0), CreateMockWrite(chunk, 1),
800 };
801 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
802 MockRead reads[] = {
803 CreateMockRead(resp, 2), CreateMockRead(chunk, 3),
804 MockRead(ASYNC, 0, 4) // EOF
805 };
806
807 InitSession(reads, writes);
808
809 ChunkedUploadDataStream upload_stream(0);
810
811 HttpRequestInfo request;
812 request.method = "POST";
813 request.url = url_;
814 request.traffic_annotation =
815 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
816 request.upload_data_stream = &upload_stream;
817
818 ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
819 NetLogWithSource()),
820 IsOk());
821 upload_stream.AppendData("", 0, true);
822
823 NetLogWithSource net_log;
824 auto http_stream = std::make_unique<SpdyHttpStream>(
825 session_, kNoPushedStreamFound, net_log.source());
826 ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY,
827 net_log, CompletionOnceCallback()),
828 IsOk());
829
830 TestCompletionCallback callback;
831 HttpRequestHeaders headers;
832 HttpResponseInfo response;
833 // This will attempt to Write() the initial request and headers, which will
834 // complete asynchronously.
835 EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
836 IsError(ERR_IO_PENDING));
837 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
838
839 // Complete writing request, followed by a FIN.
840 base::RunLoop().RunUntilIdle();
841 ASSERT_TRUE(callback.have_result());
842 EXPECT_THAT(callback.WaitForResult(), IsOk());
843
844 EXPECT_EQ(static_cast<int64_t>(req.size() + chunk.size()),
845 http_stream->GetTotalSentBytes());
846 EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk.size()),
847 http_stream->GetTotalReceivedBytes());
848
849 // Check response headers.
850 ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
851
852 // Check |chunk| response.
853 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(1);
854 ASSERT_EQ(0,
855 http_stream->ReadResponseBody(
856 buf.get(), 1, callback.callback()));
857
858 ASSERT_TRUE(response.headers.get());
859 ASSERT_EQ(200, response.headers->response_code());
860 }
861
862 // Test case for https://crbug.com/50058.
TEST_F(SpdyHttpStreamTest,SpdyURLTest)863 TEST_F(SpdyHttpStreamTest, SpdyURLTest) {
864 const char* const full_url = "https://www.example.org/foo?query=what#anchor";
865 const char* const base_url = "https://www.example.org/foo?query=what";
866 spdy::SpdySerializedFrame req(
867 spdy_util_.ConstructSpdyGet(base_url, 1, LOWEST));
868 MockWrite writes[] = {
869 CreateMockWrite(req, 0),
870 };
871 spdy::SpdySerializedFrame resp(
872 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
873 MockRead reads[] = {
874 CreateMockRead(resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
875 };
876
877 InitSession(reads, writes);
878
879 HttpRequestInfo request;
880 request.method = "GET";
881 request.url = GURL(full_url);
882 request.traffic_annotation =
883 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
884 TestCompletionCallback callback;
885 HttpResponseInfo response;
886 HttpRequestHeaders headers;
887 NetLogWithSource net_log;
888 auto http_stream = std::make_unique<SpdyHttpStream>(
889 session_, kNoPushedStreamFound, net_log.source());
890 ASSERT_THAT(http_stream->InitializeStream(&request, true, DEFAULT_PRIORITY,
891 net_log, CompletionOnceCallback()),
892 IsOk());
893
894 EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
895 IsError(ERR_IO_PENDING));
896
897 EXPECT_EQ(base_url, http_stream->stream()->url().spec());
898
899 callback.WaitForResult();
900
901 EXPECT_EQ(static_cast<int64_t>(req.size()), http_stream->GetTotalSentBytes());
902 EXPECT_EQ(static_cast<int64_t>(resp.size()),
903 http_stream->GetTotalReceivedBytes());
904
905 // Because we abandoned the stream, we don't expect to find a session in the
906 // pool anymore.
907 EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
908 }
909
910 // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
911 // made available is handled correctly.
TEST_F(SpdyHttpStreamTest,DelayedSendChunkedPostWithWindowUpdate)912 TEST_F(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
913 spdy::SpdySerializedFrame req(
914 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
915 spdy::SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, true));
916 MockWrite writes[] = {
917 CreateMockWrite(req, 0), CreateMockWrite(chunk1, 1),
918 };
919 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
920 spdy::SpdySerializedFrame window_update(
921 spdy_util_.ConstructSpdyWindowUpdate(1, kUploadDataSize));
922 MockRead reads[] = {
923 CreateMockRead(window_update, 2), MockRead(ASYNC, ERR_IO_PENDING, 3),
924 CreateMockRead(resp, 4), CreateMockRead(chunk1, 5),
925 MockRead(ASYNC, 0, 6) // EOF
926 };
927
928 InitSession(reads, writes);
929
930 ChunkedUploadDataStream upload_stream(0);
931
932 HttpRequestInfo request;
933 request.method = "POST";
934 request.url = url_;
935 request.traffic_annotation =
936 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
937 request.upload_data_stream = &upload_stream;
938
939 ASSERT_THAT(upload_stream.Init(TestCompletionCallback().callback(),
940 NetLogWithSource()),
941 IsOk());
942
943 NetLogWithSource net_log;
944 auto http_stream = std::make_unique<SpdyHttpStream>(
945 session_, kNoPushedStreamFound, net_log.source());
946 ASSERT_THAT(http_stream->InitializeStream(&request, false, DEFAULT_PRIORITY,
947 net_log, CompletionOnceCallback()),
948 IsOk());
949
950 HttpRequestHeaders headers;
951 HttpResponseInfo response;
952 // This will attempt to Write() the initial request and headers, which will
953 // complete asynchronously.
954 TestCompletionCallback callback;
955 EXPECT_THAT(http_stream->SendRequest(headers, &response, callback.callback()),
956 IsError(ERR_IO_PENDING));
957 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
958
959 // Complete the initial request write and first chunk.
960 base::RunLoop().RunUntilIdle();
961 ASSERT_FALSE(callback.have_result());
962
963 EXPECT_EQ(static_cast<int64_t>(req.size()), http_stream->GetTotalSentBytes());
964 EXPECT_EQ(0, http_stream->GetTotalReceivedBytes());
965
966 upload_stream.AppendData(kUploadData, kUploadDataSize, true);
967
968 // Verify that the window size has decreased.
969 ASSERT_TRUE(http_stream->stream() != nullptr);
970 EXPECT_NE(static_cast<int>(kDefaultInitialWindowSize),
971 http_stream->stream()->send_window_size());
972
973 // Read window update.
974 base::RunLoop().RunUntilIdle();
975
976 ASSERT_TRUE(callback.have_result());
977 EXPECT_THAT(callback.WaitForResult(), IsOk());
978
979 EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size()),
980 http_stream->GetTotalSentBytes());
981 // The window update is not counted in the total received bytes.
982 EXPECT_EQ(0, http_stream->GetTotalReceivedBytes());
983
984 // Verify the window update.
985 ASSERT_TRUE(http_stream->stream() != nullptr);
986 EXPECT_EQ(static_cast<int>(kDefaultInitialWindowSize),
987 http_stream->stream()->send_window_size());
988
989 // Read rest of data.
990 sequenced_data_->Resume();
991 base::RunLoop().RunUntilIdle();
992
993 EXPECT_EQ(static_cast<int64_t>(req.size() + chunk1.size()),
994 http_stream->GetTotalSentBytes());
995 EXPECT_EQ(static_cast<int64_t>(resp.size() + chunk1.size()),
996 http_stream->GetTotalReceivedBytes());
997
998 // Check response headers.
999 ASSERT_THAT(http_stream->ReadResponseHeaders(callback.callback()), IsOk());
1000
1001 // Check |chunk1| response.
1002 scoped_refptr<IOBuffer> buf1 =
1003 base::MakeRefCounted<IOBuffer>(kUploadDataSize);
1004 ASSERT_EQ(kUploadDataSize,
1005 http_stream->ReadResponseBody(
1006 buf1.get(), kUploadDataSize, callback.callback()));
1007 EXPECT_EQ(kUploadData, std::string(buf1->data(), kUploadDataSize));
1008
1009 ASSERT_TRUE(response.headers.get());
1010 ASSERT_EQ(200, response.headers->response_code());
1011 }
1012
TEST_F(SpdyHttpStreamTest,DataReadErrorSynchronous)1013 TEST_F(SpdyHttpStreamTest, DataReadErrorSynchronous) {
1014 spdy::SpdySerializedFrame req(
1015 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1016
1017 // Server receives spdy::ERROR_CODE_INTERNAL_ERROR on client's internal
1018 // failure. The failure is a reading error in this case caused by
1019 // UploadDataStream::Read().
1020 spdy::SpdySerializedFrame rst_frame(
1021 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_INTERNAL_ERROR));
1022
1023 MockWrite writes[] = {
1024 CreateMockWrite(req, 0, SYNCHRONOUS), // Request
1025 CreateMockWrite(rst_frame, 1, SYNCHRONOUS) // Reset frame
1026 };
1027
1028 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
1029
1030 MockRead reads[] = {
1031 CreateMockRead(resp, 2), MockRead(SYNCHRONOUS, 0, 3),
1032 };
1033
1034 InitSession(reads, writes);
1035
1036 ReadErrorUploadDataStream upload_data_stream(
1037 ReadErrorUploadDataStream::FailureMode::SYNC);
1038 ASSERT_THAT(upload_data_stream.Init(TestCompletionCallback().callback(),
1039 NetLogWithSource()),
1040 IsOk());
1041
1042 HttpRequestInfo request;
1043 request.method = "POST";
1044 request.url = url_;
1045 request.traffic_annotation =
1046 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
1047 request.upload_data_stream = &upload_data_stream;
1048
1049 TestCompletionCallback callback;
1050 HttpResponseInfo response;
1051 HttpRequestHeaders headers;
1052 NetLogWithSource net_log;
1053 SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
1054 ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
1055 net_log, CompletionOnceCallback()),
1056 IsOk());
1057
1058 int result = http_stream.SendRequest(headers, &response, callback.callback());
1059 EXPECT_THAT(callback.GetResult(result), IsError(ERR_FAILED));
1060
1061 // Run posted SpdyHttpStream::ResetStreamInternal() task.
1062 base::RunLoop().RunUntilIdle();
1063
1064 // Because the server has not closed the connection yet, there shouldn't be
1065 // a stream but a session in the pool
1066 EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
1067 }
1068
TEST_F(SpdyHttpStreamTest,DataReadErrorAsynchronous)1069 TEST_F(SpdyHttpStreamTest, DataReadErrorAsynchronous) {
1070 spdy::SpdySerializedFrame req(
1071 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1072
1073 // Server receives spdy::ERROR_CODE_INTERNAL_ERROR on client's internal
1074 // failure. The failure is a reading error in this case caused by
1075 // UploadDataStream::Read().
1076 spdy::SpdySerializedFrame rst_frame(
1077 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_INTERNAL_ERROR));
1078
1079 MockWrite writes[] = {
1080 CreateMockWrite(req, 0), // Request
1081 CreateMockWrite(rst_frame, 1) // Reset frame
1082 };
1083
1084 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
1085
1086 MockRead reads[] = {
1087 MockRead(ASYNC, 0, 2),
1088 };
1089
1090 InitSession(reads, writes);
1091
1092 ReadErrorUploadDataStream upload_data_stream(
1093 ReadErrorUploadDataStream::FailureMode::ASYNC);
1094 ASSERT_THAT(upload_data_stream.Init(TestCompletionCallback().callback(),
1095 NetLogWithSource()),
1096 IsOk());
1097
1098 HttpRequestInfo request;
1099 request.method = "POST";
1100 request.url = url_;
1101 request.traffic_annotation =
1102 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
1103 request.upload_data_stream = &upload_data_stream;
1104
1105 TestCompletionCallback callback;
1106 HttpResponseInfo response;
1107 HttpRequestHeaders headers;
1108 NetLogWithSource net_log;
1109 SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
1110 ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
1111 net_log, CompletionOnceCallback()),
1112 IsOk());
1113
1114 int result = http_stream.SendRequest(headers, &response, callback.callback());
1115 EXPECT_THAT(result, IsError(ERR_IO_PENDING));
1116 EXPECT_THAT(callback.GetResult(result), IsError(ERR_FAILED));
1117
1118 // Run posted SpdyHttpStream::ResetStreamInternal() task.
1119 base::RunLoop().RunUntilIdle();
1120
1121 // Because the server has closed the connection, there shouldn't be a session
1122 // in the pool anymore.
1123 EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
1124 }
1125
1126 // Regression test for https://crbug.com/622447.
TEST_F(SpdyHttpStreamTest,RequestCallbackCancelsStream)1127 TEST_F(SpdyHttpStreamTest, RequestCallbackCancelsStream) {
1128 spdy::SpdySerializedFrame req(
1129 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1130 spdy::SpdySerializedFrame chunk(
1131 spdy_util_.ConstructSpdyDataFrame(1, "", true));
1132 spdy::SpdySerializedFrame rst(
1133 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
1134 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(chunk, 1),
1135 CreateMockWrite(rst, 2)};
1136 MockRead reads[] = {MockRead(ASYNC, 0, 3)};
1137 InitSession(reads, writes);
1138
1139 HttpRequestInfo request;
1140 request.method = "POST";
1141 request.url = url_;
1142 request.traffic_annotation =
1143 MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
1144 ChunkedUploadDataStream upload_stream(0);
1145 request.upload_data_stream = &upload_stream;
1146
1147 TestCompletionCallback upload_callback;
1148 ASSERT_THAT(
1149 upload_stream.Init(upload_callback.callback(), NetLogWithSource()),
1150 IsOk());
1151 upload_stream.AppendData("", 0, true);
1152
1153 NetLogWithSource net_log;
1154 SpdyHttpStream http_stream(session_, kNoPushedStreamFound, net_log.source());
1155 ASSERT_THAT(http_stream.InitializeStream(&request, false, DEFAULT_PRIORITY,
1156 net_log, CompletionOnceCallback()),
1157 IsOk());
1158
1159 CancelStreamCallback callback(&http_stream);
1160 HttpRequestHeaders headers;
1161 HttpResponseInfo response;
1162 // This will attempt to Write() the initial request and headers, which will
1163 // complete asynchronously.
1164 EXPECT_THAT(http_stream.SendRequest(headers, &response, callback.callback()),
1165 IsError(ERR_IO_PENDING));
1166 EXPECT_TRUE(HasSpdySession(http_session_->spdy_session_pool(), key_));
1167
1168 // The callback cancels |http_stream|.
1169 EXPECT_THAT(callback.WaitForResult(), IsOk());
1170
1171 // Finish async network reads/writes.
1172 base::RunLoop().RunUntilIdle();
1173
1174 EXPECT_FALSE(HasSpdySession(http_session_->spdy_session_pool(), key_));
1175 }
1176
1177 // TODO(willchan): Write a longer test for SpdyStream that exercises all
1178 // methods.
1179
1180 } // namespace test
1181
1182 } // namespace net
1183