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

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

Powered by Google App Engine
This is Rietveld 408576698