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

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

Powered by Google App Engine
This is Rietveld 408576698