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

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: Address Misha's comments 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
« no previous file with comments | « net/http/bidirectional_stream_request_info.cc ('k') | net/http/http_network_transaction.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 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 if (deterministic_data_) {
259 EXPECT_TRUE(deterministic_data_->AllReadDataConsumed());
260 EXPECT_TRUE(deterministic_data_->AllWriteDataConsumed());
261 }
262 }
263
264 // Initializes the session using SequencedSocketData.
265 void InitSession(MockRead* reads,
266 size_t reads_count,
267 MockWrite* writes,
268 size_t writes_count,
269 const SpdySessionKey& key) {
270 ASSERT_TRUE(ssl_data_.cert.get());
271 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data_);
272 sequenced_data_.reset(
273 new SequencedSocketData(reads, reads_count, writes, writes_count));
274 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
275 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
276 session_ = CreateSecureSpdySession(http_session_.get(), key, BoundNetLog());
277 CHECK(!deterministic_data_);
278 }
279
280 // Initializes the session using DeterministicSocketData.
281 void InitSessionDeterministic(MockRead* reads,
282 size_t reads_count,
283 MockWrite* writes,
284 size_t writes_count,
285 const SpdySessionKey& key) {
286 ASSERT_TRUE(ssl_data_.cert.get());
287 session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(
288 &ssl_data_);
289 MockConnect connect_data(SYNCHRONOUS, OK);
290 deterministic_data_.reset(
291 new DeterministicSocketData(reads, reads_count, writes, writes_count));
292 deterministic_data_->set_connect_data(connect_data);
293 session_deps_.deterministic_socket_factory->AddSocketDataProvider(
294 deterministic_data_.get());
295 http_session_ =
296 SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
297 session_ = CreateSecureSpdySession(http_session_.get(), key, BoundNetLog());
298 CHECK(!sequenced_data_);
299 }
300
301 SpdyTestUtil spdy_util_;
302 SSLSocketDataProvider ssl_data_;
303 SpdySessionDependencies session_deps_;
304 scoped_ptr<SequencedSocketData> sequenced_data_;
305 scoped_ptr<DeterministicSocketData> deterministic_data_;
306 scoped_ptr<HttpNetworkSession> http_session_;
307 base::WeakPtr<SpdySession> session_;
308 };
309
310 TEST_F(BidirectionalStreamTest, CreateInsecureStream) {
311 BidirectionalStreamRequestInfo request_info;
312 request_info.method = "GET";
313 request_info.url = GURL("http://www.example.org/");
314
315 TestDelegateBase delegate(nullptr, 0);
316 HttpNetworkSession::Params params =
317 SpdySessionDependencies::CreateSessionParams(&session_deps_);
318 scoped_ptr<HttpNetworkSession> session(new HttpNetworkSession(params));
319 delegate.SetRunUntilCompletion(true);
320 delegate.Start(request_info, LOWEST, session.get());
321
322 EXPECT_EQ(ERR_DISALLOWED_URL_SCHEME, delegate.error());
323 }
324
325 // Simulates user calling ReadData after END_STREAM has been received in
326 // BidirectionalStreamSpdyJob.
327 TEST_F(BidirectionalStreamTest, TestReadDataAfterClose) {
328 scoped_ptr<SpdyFrame> req(
329 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
330 // Empty DATA frame with an END_STREAM flag.
331 scoped_ptr<SpdyFrame> end_stream(
332 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
333 MockWrite writes[] = {
334 CreateMockWrite(*req.get(), 0),
335 };
336
337 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
338
339 scoped_ptr<SpdyFrame> resp(
340 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
341
342 scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, false));
343 // Last body frame has END_STREAM flag set.
344 scoped_ptr<SpdyFrame> last_body_frame(
345 spdy_util_.ConstructSpdyBodyFrame(1, true));
346
347 MockRead reads[] = {
348 CreateMockRead(*resp, 1), CreateMockRead(*body_frame, 2),
349 CreateMockRead(*body_frame, 3), CreateMockRead(*last_body_frame, 4),
350 MockRead(SYNCHRONOUS, 0, 5),
351 };
352
353 HostPortPair host_port_pair("www.example.org", 443);
354 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
355 PRIVACY_MODE_DISABLED);
356 InitSessionDeterministic(reads, arraysize(reads), writes, arraysize(writes),
357 key);
358
359 BidirectionalStreamRequestInfo request_info;
360 request_info.method = "GET";
361 request_info.url = GURL("https://www.example.org/");
362 request_info.end_stream_on_headers = true;
363
364 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
365 // Create a MockTimer. Retain a raw pointer since the underlying
366 // BidirectionalStreamJob owns it.
367 MockTimer* timer = new MockTimer();
368 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
369 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
370 delegate->set_do_not_start_read(true);
371
372 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
373
374 // Write request, and deliver response headers.
375 deterministic_data_->RunFor(2);
376 base::RunLoop().RunUntilIdle();
377 EXPECT_FALSE(timer->IsRunning());
378 // ReadData returns asynchronously because no data is buffered.
379 int rv = delegate->ReadData();
380 EXPECT_EQ(ERR_IO_PENDING, rv);
381 // Deliver a DATA frame.
382 deterministic_data_->RunFor(1);
383 base::RunLoop().RunUntilIdle();
384 timer->Fire();
385 // Asynchronous completion callback is invoke.
386 EXPECT_EQ(1, delegate->on_read_complete_count());
387 EXPECT_EQ(kUploadDataSize * 1,
388 static_cast<int>(delegate->data_received().size()));
389
390 // Deliver the rest. Note that user has not called a second ReadData.
391 deterministic_data_->RunFor(3);
392 base::RunLoop().RunUntilIdle();
393 // ReadData now. Read should complete synchronously.
394 rv = delegate->ReadData();
395 EXPECT_EQ(kUploadDataSize * 2, rv);
396 rv = delegate->ReadData();
397 EXPECT_EQ(OK, rv); // EOF.
398 EXPECT_EQ(1, delegate->on_read_complete_count());
399
400 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
401 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
402 delegate->GetTotalSentBytes());
403 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
404 delegate->GetTotalReceivedBytes());
405 }
406
407 TEST_F(BidirectionalStreamTest, TestInterleaveReadDataAndSendData) {
408 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
409
410 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
411 "https://www.example.org", 1, kBodyDataSize * 3, LOWEST, NULL, 0));
412 scoped_ptr<SpdyFrame> data_frame1(
413 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
414 scoped_ptr<SpdyFrame> data_frame2(
415 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
416 scoped_ptr<SpdyFrame> data_frame3(
417 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN));
418 MockWrite writes[] = {
419 CreateMockWrite(*req, 0), // request
420 CreateMockWrite(*data_frame1, 2), CreateMockWrite(*data_frame2, 4),
421 CreateMockWrite(*data_frame3, 6),
422 };
423
424 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
425
426 scoped_ptr<SpdyFrame> resp(
427 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
428
429 scoped_ptr<SpdyFrame> response_body_frame1(
430 spdy_util_.ConstructSpdyBodyFrame(1, false));
431 scoped_ptr<SpdyFrame> response_body_frame2(
432 spdy_util_.ConstructSpdyBodyFrame(1, true));
433
434 MockRead reads[] = {
435 CreateMockRead(*resp, 1), CreateMockRead(*response_body_frame1, 3),
436 CreateMockRead(*response_body_frame2, 5), MockRead(ASYNC, 0, 7),
437 };
438
439 HostPortPair host_port_pair("www.example.org", 443);
440 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
441 PRIVACY_MODE_DISABLED);
442 InitSessionDeterministic(reads, arraysize(reads), writes, arraysize(writes),
443 key);
444
445 BidirectionalStreamRequestInfo request_info;
446 request_info.method = "POST";
447 request_info.url = GURL("https://www.example.org/");
448 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
449 base::SizeTToString(kBodyDataSize * 3));
450
451 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
452 MockTimer* timer = new MockTimer();
453 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
454 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
455 delegate->set_do_not_start_read(true);
456 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
457 // Send the request and receive response headers.
458 deterministic_data_->RunFor(2);
459 base::RunLoop().RunUntilIdle();
460 EXPECT_FALSE(timer->IsRunning());
461
462 // Send a DATA frame.
463 scoped_refptr<StringIOBuffer> buf(
464 new StringIOBuffer(std::string(kBodyData, kBodyDataSize)));
465 delegate->SendData(buf.get(), buf->size(), false);
466 deterministic_data_->RunFor(1);
467 base::RunLoop().RunUntilIdle();
468 EXPECT_EQ(1, delegate->on_data_sent_count());
469
470 // ReadData and it should return asynchronously because no data is buffered.
471 int rv = delegate->ReadData();
472 EXPECT_EQ(ERR_IO_PENDING, rv);
473 // Deliver a DATA frame, and fire the timer.
474 deterministic_data_->RunFor(1);
475 base::RunLoop().RunUntilIdle();
476 timer->Fire();
477 base::RunLoop().RunUntilIdle();
478 EXPECT_EQ(1, delegate->on_read_complete_count());
479
480 // Send a DATA frame.
481 delegate->SendData(buf.get(), buf->size(), false);
482 deterministic_data_->RunFor(1);
483 base::RunLoop().RunUntilIdle();
484 EXPECT_EQ(2, delegate->on_data_sent_count());
485
486 // ReadData and it should return asynchronously because no data is buffered.
487 rv = delegate->ReadData();
488 EXPECT_EQ(ERR_IO_PENDING, rv);
489 // Deliver a DATA frame, and fire the timer.
490 deterministic_data_->RunFor(1);
491 timer->Fire();
492 base::RunLoop().RunUntilIdle();
493 // Last DATA frame is read. Server half closes.
494 EXPECT_EQ(2, delegate->on_read_complete_count());
495
496 // Send last body frame. Client half closes.
497 delegate->SendData(buf.get(), buf->size(), true);
498 deterministic_data_->RunFor(1);
499 base::RunLoop().RunUntilIdle();
500 EXPECT_EQ(3, delegate->on_data_sent_count());
501
502 // OnClose is invoked since both sides are closed.
503 rv = delegate->ReadData();
504 EXPECT_EQ(OK, rv);
505 deterministic_data_->RunFor(1);
506 EXPECT_EQ(2, delegate->on_read_complete_count());
507 EXPECT_EQ(3, delegate->on_data_sent_count());
508
509 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
510 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
511 delegate->GetTotalSentBytes());
512 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
513 delegate->GetTotalReceivedBytes());
514 }
515
516 // Tests that BidirectionalStreamSpdyJob::OnClose will complete any remaining
517 // read even if the read queue is empty.
518 TEST_F(BidirectionalStreamTest, TestCompleteAsyncRead) {
519 scoped_ptr<SpdyFrame> req(
520 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
521 // Empty DATA frame with an END_STREAM flag.
522 scoped_ptr<SpdyFrame> end_stream(
523 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
524
525 MockWrite writes[] = {CreateMockWrite(*req.get(), 0)};
526
527 scoped_ptr<SpdyFrame> resp(
528 spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
529
530 scoped_ptr<SpdyFrame> response_body_frame(
531 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
532
533 MockRead reads[] = {
534 CreateMockRead(*resp, 1), CreateMockRead(*response_body_frame, 2),
535 MockRead(SYNCHRONOUS, 0, 3),
536 };
537
538 HostPortPair host_port_pair("www.example.org", 443);
539 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
540 PRIVACY_MODE_DISABLED);
541 InitSessionDeterministic(reads, arraysize(reads), writes, arraysize(writes),
542 key);
543
544 BidirectionalStreamRequestInfo request_info;
545 request_info.method = "GET";
546 request_info.url = GURL("https://www.example.org/");
547 request_info.end_stream_on_headers = true;
548
549 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
550 MockTimer* timer = new MockTimer();
551 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
552 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
553 delegate->set_do_not_start_read(true);
554 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
555 // Write request, and deliver response headers.
556 deterministic_data_->RunFor(2);
557 base::RunLoop().RunUntilIdle();
558 EXPECT_FALSE(timer->IsRunning());
559
560 // Let ReadData return asynchronously.
561 int rv = delegate->ReadData();
562 EXPECT_EQ(ERR_IO_PENDING, rv);
563 // Deliver END_STREAM.
564 // OnClose should trigger completion of the remaining read.
565 deterministic_data_->RunFor(3);
566 base::RunLoop().RunUntilIdle();
567 EXPECT_EQ(1, delegate->on_read_complete_count());
568 EXPECT_EQ(0u, delegate->data_received().size());
569
570 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
571 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
572 delegate->GetTotalSentBytes());
573 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
574 delegate->GetTotalReceivedBytes());
575 }
576
577 TEST_F(BidirectionalStreamTest, TestBuffering) {
578 scoped_ptr<SpdyFrame> req(
579 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
580 // Empty DATA frame with an END_STREAM flag.
581 scoped_ptr<SpdyFrame> end_stream(
582 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
583
584 MockWrite writes[] = {CreateMockWrite(*req.get(), 0)};
585
586 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
587
588 scoped_ptr<SpdyFrame> resp(
589 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
590
591 scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, false));
592 // Last body frame has END_STREAM flag set.
593 scoped_ptr<SpdyFrame> last_body_frame(
594 spdy_util_.ConstructSpdyBodyFrame(1, true));
595
596 MockRead reads[] = {
597 CreateMockRead(*resp, 1), CreateMockRead(*body_frame, 2),
598 CreateMockRead(*body_frame, 3), CreateMockRead(*last_body_frame, 4),
599 MockRead(SYNCHRONOUS, 0, 5),
600 };
601
602 HostPortPair host_port_pair("www.example.org", 443);
603 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
604 PRIVACY_MODE_DISABLED);
605 InitSessionDeterministic(reads, arraysize(reads), writes, arraysize(writes),
606 key);
607
608 BidirectionalStreamRequestInfo request_info;
609 request_info.method = "GET";
610 request_info.url = GURL("https://www.example.org/");
611 request_info.end_stream_on_headers = true;
612
613 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
614 MockTimer* timer = new MockTimer();
615 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
616 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
617 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
618 // Deliver two DATA frames together.
619 deterministic_data_->RunFor(4);
620 base::RunLoop().RunUntilIdle();
621 EXPECT_TRUE(timer->IsRunning());
622 timer->Fire();
623 base::RunLoop().RunUntilIdle();
624 // This should trigger |more_read_data_pending_| to execute the task at a
625 // later time, and Delegate::OnReadComplete should not have been called.
626 EXPECT_TRUE(timer->IsRunning());
627 EXPECT_EQ(0, delegate->on_read_complete_count());
628
629 // Fire the timer now, the two DATA frame should be combined into one
630 // single Delegate::OnReadComplete callback.
631 timer->Fire();
632 base::RunLoop().RunUntilIdle();
633 EXPECT_EQ(1, delegate->on_read_complete_count());
634 EXPECT_EQ(kUploadDataSize * 2,
635 static_cast<int>(delegate->data_received().size()));
636
637 // Deliver last DATA frame and EOF. There will be an additional
638 // Delegate::OnReadComplete callback.
639 deterministic_data_->RunFor(2);
640 EXPECT_EQ(2, delegate->on_read_complete_count());
641 const SpdyHeaderBlock response_headers = delegate->response_headers();
642 EXPECT_EQ("200", response_headers.find(":status")->second);
643 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
644
645 EXPECT_EQ(kUploadDataSize * 3,
646 static_cast<int>(delegate->data_received().size()));
647
648 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
649 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
650 delegate->GetTotalSentBytes());
651 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
652 delegate->GetTotalReceivedBytes());
653 }
654
655 TEST_F(BidirectionalStreamTest, TestBufferingWithTrailers) {
656 scoped_ptr<SpdyFrame> req(
657 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
658 // Empty DATA frame with an END_STREAM flag.
659 scoped_ptr<SpdyFrame> end_stream(
660 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
661
662 MockWrite writes[] = {
663 CreateMockWrite(*req.get(), 0),
664 };
665
666 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
667
668 scoped_ptr<SpdyFrame> resp(
669 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
670
671 scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, false));
672
673 const char* const kTrailers[] = {"foo", "bar"};
674 scoped_ptr<SpdyFrame> trailers(
675 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
676
677 MockRead reads[] = {
678 CreateMockRead(*resp, 1), CreateMockRead(*body_frame, 2),
679 CreateMockRead(*body_frame, 3), CreateMockRead(*body_frame, 4),
680 CreateMockRead(*trailers, 5), MockRead(SYNCHRONOUS, 0, 6),
681 };
682
683 HostPortPair host_port_pair("www.example.org", 443);
684 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
685 PRIVACY_MODE_DISABLED);
686 InitSessionDeterministic(reads, arraysize(reads), writes, arraysize(writes),
687 key);
688
689 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
690 MockTimer* timer = new MockTimer();
691 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
692 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
693
694 BidirectionalStreamRequestInfo request_info;
695 request_info.method = "GET";
696 request_info.url = GURL("https://www.example.org/");
697 request_info.end_stream_on_headers = true;
698
699 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
700 // Deliver all three DATA frames together.
701 deterministic_data_->RunFor(5);
mmenke 2015/12/14 19:48:37 Suggest using SequencedSocketData instead. We wan
xunjieli 2015/12/14 21:03:05 I am aware of the deprecation plan for Determinist
mmenke 2015/12/14 21:49:38 Hrm... If we're going to need to be able to test
Ryan Hamilton 2015/12/14 22:33:18 I believe that SequencedSocketData already has a m
702 base::RunLoop().RunUntilIdle();
mmenke 2015/12/14 19:48:37 In my experience, RunUntilIdle makes for flaky, re
xunjieli 2015/12/14 21:03:05 I will try adjusting it accordingly. But I still h
703 EXPECT_TRUE(timer->IsRunning());
704 timer->Fire();
705 base::RunLoop().RunUntilIdle();
706 // This should trigger |more_read_data_pending_| to execute the task at a
707 // later time, and Delegate::OnReadComplete should not have been called.
708 EXPECT_TRUE(timer->IsRunning());
709 EXPECT_EQ(0, delegate->on_read_complete_count());
710
711 // Deliver trailers. Remaining read should be completed, since OnClose is
712 // called right after OnTrailersReceived. The three DATA frames should be
713 // delivered in a single OnReadCompleted callback.
714 deterministic_data_->RunFor(2);
715 base::RunLoop().RunUntilIdle();
716 EXPECT_FALSE(timer->IsRunning());
717 EXPECT_EQ(1, delegate->on_read_complete_count());
718 EXPECT_EQ(kUploadDataSize * 3,
719 static_cast<int>(delegate->data_received().size()));
720 const SpdyHeaderBlock response_headers = delegate->response_headers();
721 EXPECT_EQ("200", response_headers.find(":status")->second);
722 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
723
724 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
725 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
726 delegate->GetTotalSentBytes());
727 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
728 delegate->GetTotalReceivedBytes());
729 }
730
731 TEST_F(BidirectionalStreamTest, CancelStream) {
732 scoped_ptr<SpdyFrame> req(
733 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
734
735 scoped_ptr<SpdyFrame> rst(
736 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
737 MockWrite writes[] = {
738 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
739 };
740
741 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
742
743 scoped_ptr<SpdyFrame> resp(
744 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
745
746 MockRead reads[] = {
747 CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
748 };
749
750 HostPortPair host_port_pair("www.example.org", 443);
751 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
752 PRIVACY_MODE_DISABLED);
753 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
754
755 BidirectionalStreamRequestInfo request_info;
756 request_info.method = "GET";
757 request_info.url = GURL("https://www.example.org/");
758 request_info.end_stream_on_headers = true;
759
760 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
761 scoped_ptr<CancelStreamDelegate> delegate(
762 new CancelStreamDelegate(read_buffer.get(), kReadBufferSize));
763 delegate->SetRunUntilCompletion(true);
764 delegate->Start(request_info, DEFAULT_PRIORITY, http_session_.get());
765 // Makes sure delegate does not get called.
766 base::RunLoop().RunUntilIdle();
767 const SpdyHeaderBlock response_headers = delegate->response_headers();
768 EXPECT_EQ("200", response_headers.find(":status")->second);
769 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
770 EXPECT_EQ(0u, delegate->data_received().size());
771
772 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
773
774 // Stream is canceled. The total received and sent bytes should be 0.
775 EXPECT_EQ(0, delegate->GetTotalSentBytes());
776 EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
777 }
778
779 } // namespace net
OLDNEW
« no previous file with comments | « net/http/bidirectional_stream_request_info.cc ('k') | net/http/http_network_transaction.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698