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

Side by Side Diff: net/http/bidirectional_stream_unittest.cc

Issue 1326503003: Added a net::BidirectionalStream to expose a bidirectional streaming interface (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Get rid of DeterministicSocketData Created 5 years 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
OLDNEW
(Empty)
1 // Copyright 2015 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/http/bidirectional_stream.h"
6
7 #include "base/macros.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/run_loop.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_piece.h"
12 #include "base/time/time.h"
13 #include "base/timer/mock_timer.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/test_data_directory.h"
16 #include "net/http/bidirectional_stream_request_info.h"
17 #include "net/http/http_network_session.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/log/net_log.h"
20 #include "net/socket/socket_test_util.h"
21 #include "net/spdy/spdy_session.h"
22 #include "net/spdy/spdy_test_util_common.h"
23 #include "net/spdy/spdy_test_util_common.h"
24 #include "net/test/cert_test_util.h"
25 #include "net/url_request/url_request_test_util.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27
28 namespace net {
29
30 namespace {
31
32 const char kBodyData[] = "Body data";
33 const size_t kBodyDataSize = arraysize(kBodyData);
34 // Size of the buffer to be allocated for each read.
35 const size_t kReadBufferSize = 4096;
36
37 // Delegate that reads data but does not send any data.
38 class TestDelegateBase : public BidirectionalStream::Delegate {
39 public:
40 TestDelegateBase(IOBuffer* read_buf, int read_buf_len)
41 : TestDelegateBase(read_buf,
42 read_buf_len,
43 make_scoped_ptr(new base::Timer(false, false))) {}
44
45 TestDelegateBase(IOBuffer* read_buf,
46 int read_buf_len,
47 scoped_ptr<base::Timer> timer)
48 : read_buf_(read_buf),
49 read_buf_len_(read_buf_len),
50 timer_(timer.release()),
51 loop_(nullptr),
52 error_(OK),
53 on_read_complete_count_(0),
54 on_data_sent_count_(0),
55 do_not_start_read_(false),
56 run_until_completion_(false),
57 not_expect_callback_(false) {}
58
59 ~TestDelegateBase() override {}
60
61 void OnHeadersSent() override { CHECK(!not_expect_callback_); }
62
63 void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
64 CHECK(!not_expect_callback_);
65
66 response_headers_ = response_headers;
67 if (!do_not_start_read_)
68 StartOrContinueReading();
69 }
70
71 void OnDataRead(int bytes_read) override {
72 CHECK(!not_expect_callback_);
73
74 ++on_read_complete_count_;
75 CHECK_GE(bytes_read, OK);
76 data_received_.append(read_buf_->data(), bytes_read);
77 if (!do_not_start_read_)
78 StartOrContinueReading();
79 }
80
81 void OnDataSent() override {
82 CHECK(!not_expect_callback_);
83
84 ++on_data_sent_count_;
85 }
86
87 void OnTrailersReceived(const SpdyHeaderBlock& trailers) override {
88 CHECK(!not_expect_callback_);
89
90 trailers_ = trailers;
91 if (run_until_completion_)
92 loop_->Quit();
93 }
94
95 void OnFailed(int error) override {
96 CHECK(!not_expect_callback_);
97 CHECK_EQ(OK, error_);
98 CHECK_NE(OK, error);
99
100 error_ = error;
101 if (run_until_completion_)
102 loop_->Quit();
103 }
104
105 void Start(const BidirectionalStreamRequestInfo& request_info,
106 RequestPriority priority,
107 HttpNetworkSession* session) {
108 stream_.reset(new BidirectionalStream(request_info, priority, session, this,
109 timer_.Pass()));
110 if (run_until_completion_)
111 loop_->Run();
112 }
113
114 void SendData(IOBuffer* data, int length, bool end_of_stream) {
115 not_expect_callback_ = true;
116 stream_->SendData(data, length, end_of_stream);
117 not_expect_callback_ = false;
118 }
119
120 // Starts or continues reading data from |stream_| until no more bytes
121 // can be read synchronously.
122 void StartOrContinueReading() {
123 int rv = ReadData();
124 while (rv > 0) {
125 rv = ReadData();
126 }
127 if (run_until_completion_ && rv == 0)
128 loop_->Quit();
129 }
130
131 // Calls ReadData on the |stream_| and updates internal states.
132 int ReadData() {
133 not_expect_callback_ = true;
134 int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
135 not_expect_callback_ = false;
136 if (rv > 0) {
137 data_received_.append(read_buf_->data(), rv);
138 }
139 return rv;
140 }
141
142 NextProto GetProtocol() const { return stream_->GetProtocol(); }
143
144 int64_t GetTotalReceivedBytes() const {
145 return stream_->GetTotalReceivedBytes();
146 }
147
148 int64_t GetTotalSentBytes() const { return stream_->GetTotalSentBytes(); }
149
150 // Const getters for internal states.
151 const std::string& data_received() const { return data_received_; }
152 int error() const { return error_; }
153 const SpdyHeaderBlock& response_headers() const { return response_headers_; }
154 const SpdyHeaderBlock& trailers() const { return trailers_; }
155 int on_read_complete_count() const { return on_read_complete_count_; }
156 int on_data_sent_count() const { return on_data_sent_count_; }
157
158 // Sets whether the delegate should automatically start reading.
159 void set_do_not_start_read(bool do_not_start_read) {
160 do_not_start_read_ = do_not_start_read;
161 }
162 // Sets whether the delegate should wait until the completion of the stream.
163 void SetRunUntilCompletion(bool run_until_completion) {
164 run_until_completion_ = run_until_completion;
165 loop_.reset(new base::RunLoop);
166 }
167
168 protected:
169 // Cancels |stream_|.
170 void CancelStream() { stream_->Cancel(); }
171 // Quits |loop_|.
172 void QuitLoop() { loop_->Quit(); }
173
174 private:
175 scoped_ptr<BidirectionalStream> stream_;
176 scoped_refptr<IOBuffer> read_buf_;
177 int read_buf_len_;
178 scoped_ptr<base::Timer> timer_;
179 std::string data_received_;
180 scoped_ptr<base::RunLoop> loop_;
181 SpdyHeaderBlock response_headers_;
182 SpdyHeaderBlock trailers_;
183 int error_;
184 int on_read_complete_count_;
185 int on_data_sent_count_;
186 bool do_not_start_read_;
187 bool run_until_completion_;
188 // This is to ensure that delegate callback is not invoked synchronously when
189 // calling into |stream_|.
190 bool not_expect_callback_;
191
192 DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
193 };
194
195 // A delegate that cancels the request after response headers are received.
196 class CancelStreamDelegate : public TestDelegateBase {
197 public:
198 CancelStreamDelegate(IOBuffer* buf, int buf_len)
199 : TestDelegateBase(buf, buf_len) {}
200 ~CancelStreamDelegate() override {}
201
202 void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
203 TestDelegateBase::OnHeadersReceived(response_headers);
204 CancelStream();
205 QuitLoop();
206 }
207
208 void OnDataSent() override { NOTREACHED(); }
209
210 void OnDataRead(int bytes_read) override { NOTREACHED(); }
211
212 void OnTrailersReceived(const SpdyHeaderBlock& trailers) override {
213 NOTREACHED();
214 }
215
216 void OnFailed(int error) override { NOTREACHED(); }
217
218 private:
219 DISALLOW_COPY_AND_ASSIGN(CancelStreamDelegate);
220 };
221
222 // A Timer that does not start a delayed task unless the timer is fired.
223 class MockTimer : public base::MockTimer {
224 public:
225 MockTimer() : base::MockTimer(false, false) {}
226 ~MockTimer() override {}
227
228 void Start(const tracked_objects::Location& posted_from,
229 base::TimeDelta delay,
230 const base::Closure& user_task) override {
231 // Sets a maximum delay, so the timer does not fire unless it is told to.
232 base::TimeDelta infinite_delay = base::TimeDelta::Max();
233 base::MockTimer::Start(posted_from, infinite_delay, user_task);
234 }
235
236 private:
237 DISALLOW_COPY_AND_ASSIGN(MockTimer);
238 };
239
240 } // namespace
241
242 class BidirectionalStreamTest : public testing::Test {
243 public:
244 BidirectionalStreamTest()
245 : spdy_util_(kProtoHTTP2, false),
246 ssl_data_(SSLSocketDataProvider(ASYNC, OK)),
247 session_deps_(kProtoHTTP2) {
248 ssl_data_.SetNextProto(kProtoHTTP2);
249 ssl_data_.cert = ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
250 }
251
252 protected:
253 void TearDown() override {
254 if (sequenced_data_) {
255 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
256 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
257 }
258 }
259
260 // Initializes the session using SequencedSocketData.
261 void InitSession(MockRead* reads,
262 size_t reads_count,
263 MockWrite* writes,
264 size_t writes_count,
265 const SpdySessionKey& key) {
266 ASSERT_TRUE(ssl_data_.cert.get());
267 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data_);
268 sequenced_data_.reset(
269 new SequencedSocketData(reads, reads_count, writes, writes_count));
270 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
271 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
272 session_ = CreateSecureSpdySession(http_session_.get(), key, BoundNetLog());
273 }
274
275 SpdyTestUtil spdy_util_;
276 SSLSocketDataProvider ssl_data_;
277 SpdySessionDependencies session_deps_;
278 scoped_ptr<SequencedSocketData> sequenced_data_;
279 scoped_ptr<HttpNetworkSession> http_session_;
280 base::WeakPtr<SpdySession> session_;
281 };
282
283 TEST_F(BidirectionalStreamTest, CreateInsecureStream) {
284 BidirectionalStreamRequestInfo request_info;
285 request_info.method = "GET";
286 request_info.url = GURL("http://www.example.org/");
287
288 TestDelegateBase delegate(nullptr, 0);
289 HttpNetworkSession::Params params =
290 SpdySessionDependencies::CreateSessionParams(&session_deps_);
291 scoped_ptr<HttpNetworkSession> session(new HttpNetworkSession(params));
292 delegate.SetRunUntilCompletion(true);
293 delegate.Start(request_info, LOWEST, session.get());
294
295 EXPECT_EQ(ERR_DISALLOWED_URL_SCHEME, delegate.error());
296 }
297
298 // Simulates user calling ReadData after END_STREAM has been received in
299 // BidirectionalStreamSpdyJob.
300 TEST_F(BidirectionalStreamTest, TestReadDataAfterClose) {
301 scoped_ptr<SpdyFrame> req(
302 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
303 // Empty DATA frame with an END_STREAM flag.
304 scoped_ptr<SpdyFrame> end_stream(
305 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
306 MockWrite writes[] = {
307 CreateMockWrite(*req.get(), 0),
308 };
309
310 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
311
312 scoped_ptr<SpdyFrame> resp(
313 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
314
315 scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, false));
316 // Last body frame has END_STREAM flag set.
317 scoped_ptr<SpdyFrame> last_body_frame(
318 spdy_util_.ConstructSpdyBodyFrame(1, true));
319
320 MockRead reads[] = {
321 CreateMockRead(*resp, 1),
322 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
323 CreateMockRead(*body_frame, 3),
324 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
325 CreateMockRead(*body_frame, 5),
326 CreateMockRead(*last_body_frame, 6),
327 MockRead(SYNCHRONOUS, 0, 7),
328 };
329
330 HostPortPair host_port_pair("www.example.org", 443);
331 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
332 PRIVACY_MODE_DISABLED);
333 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
334
335 BidirectionalStreamRequestInfo request_info;
336 request_info.method = "GET";
337 request_info.url = GURL("https://www.example.org/");
338 request_info.end_stream_on_headers = true;
339
340 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
341 // Create a MockTimer. Retain a raw pointer since the underlying
342 // BidirectionalStreamJob owns it.
343 MockTimer* timer = new MockTimer();
344 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
345 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
346 delegate->set_do_not_start_read(true);
347
348 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
349
350 // Write request, and deliver response headers.
351 base::RunLoop().RunUntilIdle();
352 EXPECT_FALSE(timer->IsRunning());
353 // ReadData returns asynchronously because no data is buffered.
354 int rv = delegate->ReadData();
355 EXPECT_EQ(ERR_IO_PENDING, rv);
356 // Deliver a DATA frame.
357 sequenced_data_->CompleteRead();
358 base::RunLoop().RunUntilIdle();
359 timer->Fire();
360 // Asynchronous completion callback is invoke.
361 EXPECT_EQ(1, delegate->on_read_complete_count());
362 EXPECT_EQ(kUploadDataSize * 1,
363 static_cast<int>(delegate->data_received().size()));
364
365 // Deliver the rest. Note that user has not called a second ReadData.
366 sequenced_data_->CompleteRead();
367 base::RunLoop().RunUntilIdle();
368 // ReadData now. Read should complete synchronously.
369 rv = delegate->ReadData();
370 EXPECT_EQ(kUploadDataSize * 2, rv);
371 rv = delegate->ReadData();
372 EXPECT_EQ(OK, rv); // EOF.
373 EXPECT_EQ(1, delegate->on_read_complete_count());
374
375 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
376 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
377 delegate->GetTotalSentBytes());
378 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
379 delegate->GetTotalReceivedBytes());
380 }
381
382 TEST_F(BidirectionalStreamTest, TestInterleaveReadDataAndSendData) {
383 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
384
385 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
386 "https://www.example.org", 1, kBodyDataSize * 3, LOWEST, NULL, 0));
387 scoped_ptr<SpdyFrame> data_frame1(
388 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
389 scoped_ptr<SpdyFrame> data_frame2(
390 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
391 scoped_ptr<SpdyFrame> data_frame3(
392 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN));
393 MockWrite writes[] = {
394 CreateMockWrite(*req, 0), CreateMockWrite(*data_frame1, 3),
395 CreateMockWrite(*data_frame2, 6), CreateMockWrite(*data_frame3, 9),
396 };
397
398 scoped_ptr<SpdyFrame> resp(
399 spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
400 scoped_ptr<SpdyFrame> response_body_frame1(
401 spdy_util_.ConstructSpdyBodyFrame(1, false));
402 scoped_ptr<SpdyFrame> response_body_frame2(
403 spdy_util_.ConstructSpdyBodyFrame(1, true));
404
405 MockRead reads[] = {
406 CreateMockRead(*resp, 1),
407 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
408 CreateMockRead(*response_body_frame1, 4),
409 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause.
410 CreateMockRead(*response_body_frame2, 7),
411 MockRead(ASYNC, ERR_IO_PENDING, 8), // Force a pause.
412 MockRead(ASYNC, 0, 10),
413 };
414
415 HostPortPair host_port_pair("www.example.org", 443);
416 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
417 PRIVACY_MODE_DISABLED);
418 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
419
420 BidirectionalStreamRequestInfo request_info;
421 request_info.method = "POST";
422 request_info.url = GURL("https://www.example.org/");
423 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
424 base::SizeTToString(kBodyDataSize * 3));
425
426 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
427 MockTimer* timer = new MockTimer();
428 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
429 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
430 delegate->set_do_not_start_read(true);
431 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
432 // Send the request and receive response headers.
433 base::RunLoop().RunUntilIdle();
434 EXPECT_FALSE(timer->IsRunning());
435
436 // Send a DATA frame.
437 scoped_refptr<StringIOBuffer> buf(
438 new StringIOBuffer(std::string(kBodyData, kBodyDataSize)));
439 delegate->SendData(buf.get(), buf->size(), false);
440 base::RunLoop().RunUntilIdle();
441 EXPECT_EQ(1, delegate->on_data_sent_count());
442
443 // ReadData and it should return asynchronously because no data is buffered.
444 int rv = delegate->ReadData();
445 EXPECT_EQ(ERR_IO_PENDING, rv);
446 // Deliver a DATA frame, and fire the timer.
447 sequenced_data_->CompleteRead();
448 timer->Fire();
449 base::RunLoop().RunUntilIdle();
450 EXPECT_EQ(1, delegate->on_read_complete_count());
451
452 // Send a DATA frame.
453 delegate->SendData(buf.get(), buf->size(), false);
454 base::RunLoop().RunUntilIdle();
455 EXPECT_EQ(2, delegate->on_data_sent_count());
456
457 // ReadData and it should return asynchronously because no data is buffered.
458 rv = delegate->ReadData();
459 EXPECT_EQ(ERR_IO_PENDING, rv);
460 // Deliver a DATA frame, and fire the timer.
461 sequenced_data_->CompleteRead();
462 timer->Fire();
463 base::RunLoop().RunUntilIdle();
464 // Last DATA frame is read. Server half closes.
465 EXPECT_EQ(2, delegate->on_read_complete_count());
466
467 // Send the last body frame. Client half closes.
468 delegate->SendData(buf.get(), buf->size(), true);
469 base::RunLoop().RunUntilIdle();
470 EXPECT_EQ(3, delegate->on_data_sent_count());
471 sequenced_data_->CompleteRead();
472
473 // OnClose is invoked since both sides are closed.
474 rv = delegate->ReadData();
475 EXPECT_EQ(OK, rv);
476 EXPECT_EQ(2, delegate->on_read_complete_count());
477 EXPECT_EQ(3, delegate->on_data_sent_count());
478
479 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
480 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
481 delegate->GetTotalSentBytes());
482 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
483 delegate->GetTotalReceivedBytes());
484 }
485
486 // Tests that BidirectionalStreamSpdyJob::OnClose will complete any remaining
487 // read even if the read queue is empty.
488 TEST_F(BidirectionalStreamTest, TestCompleteAsyncRead) {
489 scoped_ptr<SpdyFrame> req(
490 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
491 // Empty DATA frame with an END_STREAM flag.
492 scoped_ptr<SpdyFrame> end_stream(
493 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
494
495 MockWrite writes[] = {CreateMockWrite(*req.get(), 0)};
496
497 scoped_ptr<SpdyFrame> resp(
498 spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
499
500 scoped_ptr<SpdyFrame> response_body_frame(
501 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
502
503 MockRead reads[] = {
504 CreateMockRead(*resp, 1),
505 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
506 CreateMockRead(*response_body_frame, 3), MockRead(SYNCHRONOUS, 0, 4),
507 };
508
509 HostPortPair host_port_pair("www.example.org", 443);
510 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
511 PRIVACY_MODE_DISABLED);
512 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
513
514 BidirectionalStreamRequestInfo request_info;
515 request_info.method = "GET";
516 request_info.url = GURL("https://www.example.org/");
517 request_info.end_stream_on_headers = true;
518
519 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
520 MockTimer* timer = new MockTimer();
521 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
522 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
523 delegate->set_do_not_start_read(true);
524 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
525 // Write request, and deliver response headers.
526 base::RunLoop().RunUntilIdle();
527 EXPECT_FALSE(timer->IsRunning());
528
529 // ReadData should return asynchronously because no data is buffered.
530 int rv = delegate->ReadData();
531 EXPECT_EQ(ERR_IO_PENDING, rv);
532 // Deliver END_STREAM.
533 // OnClose should trigger completion of the remaining read.
534 sequenced_data_->CompleteRead();
535 base::RunLoop().RunUntilIdle();
536 EXPECT_EQ(1, delegate->on_read_complete_count());
537 EXPECT_EQ(0u, delegate->data_received().size());
538
539 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
540 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
541 delegate->GetTotalSentBytes());
542 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
543 delegate->GetTotalReceivedBytes());
544 }
545
546 TEST_F(BidirectionalStreamTest, TestBuffering) {
547 scoped_ptr<SpdyFrame> req(
548 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
549 // Empty DATA frame with an END_STREAM flag.
550 scoped_ptr<SpdyFrame> end_stream(
551 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
552
553 MockWrite writes[] = {CreateMockWrite(*req.get(), 0)};
554
555 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
556
557 scoped_ptr<SpdyFrame> resp(
558 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
559
560 scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, false));
561 // Last body frame has END_STREAM flag set.
562 scoped_ptr<SpdyFrame> last_body_frame(
563 spdy_util_.ConstructSpdyBodyFrame(1, true));
564
565 MockRead reads[] = {
566 CreateMockRead(*resp, 1),
567 CreateMockRead(*body_frame, 2),
568 CreateMockRead(*body_frame, 3),
569 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
570 CreateMockRead(*last_body_frame, 5),
571 MockRead(SYNCHRONOUS, 0, 6),
572 };
573
574 HostPortPair host_port_pair("www.example.org", 443);
575 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
576 PRIVACY_MODE_DISABLED);
577 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
578
579 BidirectionalStreamRequestInfo request_info;
580 request_info.method = "GET";
581 request_info.url = GURL("https://www.example.org/");
582 request_info.end_stream_on_headers = true;
583
584 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
585 MockTimer* timer = new MockTimer();
586 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
587 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
588 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
589 // Deliver two DATA frames together.
590 base::RunLoop().RunUntilIdle();
591 EXPECT_TRUE(timer->IsRunning());
592 timer->Fire();
593 base::RunLoop().RunUntilIdle();
594 // This should trigger |more_read_data_pending_| to execute the task at a
595 // later time, and Delegate::OnReadComplete should not have been called.
596 EXPECT_TRUE(timer->IsRunning());
597 EXPECT_EQ(0, delegate->on_read_complete_count());
598
599 // Fire the timer now, the two DATA frame should be combined into one
600 // single Delegate::OnReadComplete callback.
601 timer->Fire();
602 base::RunLoop().RunUntilIdle();
603 EXPECT_EQ(1, delegate->on_read_complete_count());
604 EXPECT_EQ(kUploadDataSize * 2,
605 static_cast<int>(delegate->data_received().size()));
606
607 // Deliver last DATA frame and EOF. There will be an additional
608 // Delegate::OnReadComplete callback.
609 sequenced_data_->CompleteRead();
610 EXPECT_EQ(2, delegate->on_read_complete_count());
611 const SpdyHeaderBlock response_headers = delegate->response_headers();
612 EXPECT_EQ("200", response_headers.find(":status")->second);
613 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
614
615 EXPECT_EQ(kUploadDataSize * 3,
616 static_cast<int>(delegate->data_received().size()));
617
618 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
619 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
620 delegate->GetTotalSentBytes());
621 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
622 delegate->GetTotalReceivedBytes());
623 }
624
625 TEST_F(BidirectionalStreamTest, TestBufferingWithTrailers) {
626 scoped_ptr<SpdyFrame> req(
627 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
628 // Empty DATA frame with an END_STREAM flag.
629 scoped_ptr<SpdyFrame> end_stream(
630 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
631
632 MockWrite writes[] = {
633 CreateMockWrite(*req.get(), 0),
634 };
635
636 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
637
638 scoped_ptr<SpdyFrame> resp(
639 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
640
641 scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, false));
642
643 const char* const kTrailers[] = {"foo", "bar"};
644 scoped_ptr<SpdyFrame> trailers(
645 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
646
647 MockRead reads[] = {
648 CreateMockRead(*resp, 1), CreateMockRead(*body_frame, 2),
649 CreateMockRead(*body_frame, 3), CreateMockRead(*body_frame, 4),
650 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause.
651 CreateMockRead(*trailers, 6), MockRead(SYNCHRONOUS, 0, 7),
652 };
653
654 HostPortPair host_port_pair("www.example.org", 443);
655 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
656 PRIVACY_MODE_DISABLED);
657 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
658
659 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
660 MockTimer* timer = new MockTimer();
661 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
662 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
663
664 BidirectionalStreamRequestInfo request_info;
665 request_info.method = "GET";
666 request_info.url = GURL("https://www.example.org/");
667 request_info.end_stream_on_headers = true;
668
669 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
670 // Deliver all three DATA frames together.
671 base::RunLoop().RunUntilIdle();
672 EXPECT_TRUE(timer->IsRunning());
673 timer->Fire();
674 base::RunLoop().RunUntilIdle();
675 // This should trigger |more_read_data_pending_| to execute the task at a
676 // later time, and Delegate::OnReadComplete should not have been called.
677 EXPECT_TRUE(timer->IsRunning());
678 EXPECT_EQ(0, delegate->on_read_complete_count());
679
680 // Deliver trailers. Remaining read should be completed, since OnClose is
681 // called right after OnTrailersReceived. The three DATA frames should be
682 // delivered in a single OnReadCompleted callback.
683 sequenced_data_->CompleteRead();
684 EXPECT_EQ(1, delegate->on_read_complete_count());
685 EXPECT_EQ(kUploadDataSize * 3,
686 static_cast<int>(delegate->data_received().size()));
687 const SpdyHeaderBlock response_headers = delegate->response_headers();
688 EXPECT_EQ("200", response_headers.find(":status")->second);
689 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
690
691 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
692 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
693 delegate->GetTotalSentBytes());
694 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
695 delegate->GetTotalReceivedBytes());
696 }
697
698 TEST_F(BidirectionalStreamTest, CancelStream) {
699 scoped_ptr<SpdyFrame> req(
700 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
701
702 scoped_ptr<SpdyFrame> rst(
703 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
704 MockWrite writes[] = {
705 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
706 };
707
708 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
709
710 scoped_ptr<SpdyFrame> resp(
711 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
712
713 MockRead reads[] = {
714 CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
715 };
716
717 HostPortPair host_port_pair("www.example.org", 443);
718 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
719 PRIVACY_MODE_DISABLED);
720 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
721
722 BidirectionalStreamRequestInfo request_info;
723 request_info.method = "GET";
724 request_info.url = GURL("https://www.example.org/");
725 request_info.end_stream_on_headers = true;
726
727 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
728 scoped_ptr<CancelStreamDelegate> delegate(
729 new CancelStreamDelegate(read_buffer.get(), kReadBufferSize));
730 delegate->SetRunUntilCompletion(true);
731 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
732 // Makes sure delegate does not get called.
733 base::RunLoop().RunUntilIdle();
734 const SpdyHeaderBlock response_headers = delegate->response_headers();
735 EXPECT_EQ("200", response_headers.find(":status")->second);
736 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
737 EXPECT_EQ(0u, delegate->data_received().size());
738
739 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
740
741 // Stream is canceled. The total received and sent bytes should be 0.
742 EXPECT_EQ(0, delegate->GetTotalSentBytes());
743 EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
744 }
745
746 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698