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

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: Use private inheritance 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/test/cert_test_util.h"
24 #include "net/url_request/url_request_test_util.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26
27 namespace net {
28
29 namespace {
30
31 const char kBodyData[] = "Body data";
32 const size_t kBodyDataSize = arraysize(kBodyData);
33 // Size of the buffer to be allocated for each read.
34 const size_t kReadBufferSize = 4096;
35
36 // Delegate that reads data but does not send any data.
37 class TestDelegateBase : public BidirectionalStream::Delegate {
38 public:
39 TestDelegateBase(IOBuffer* read_buf, int read_buf_len)
40 : TestDelegateBase(read_buf,
41 read_buf_len,
42 make_scoped_ptr(new base::Timer(false, false))) {}
43
44 TestDelegateBase(IOBuffer* read_buf,
45 int read_buf_len,
46 scoped_ptr<base::Timer> timer)
47 : read_buf_(read_buf),
48 read_buf_len_(read_buf_len),
49 timer_(timer.release()),
50 loop_(nullptr),
51 error_(OK),
52 on_data_read_count_(0),
53 on_data_sent_count_(0),
54 do_not_start_read_(false),
55 run_until_completion_(false),
56 not_expect_callback_(false) {}
57
58 ~TestDelegateBase() override {}
59
60 void OnHeadersSent() override { CHECK(!not_expect_callback_); }
61
62 void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
63 CHECK(!not_expect_callback_);
64
65 response_headers_ = response_headers;
66 if (!do_not_start_read_)
67 StartOrContinueReading();
68 }
69
70 void OnDataRead(int bytes_read) override {
71 CHECK(!not_expect_callback_);
72
73 ++on_data_read_count_;
74 CHECK_GE(bytes_read, OK);
75 data_received_.append(read_buf_->data(), bytes_read);
76 if (!do_not_start_read_)
77 StartOrContinueReading();
78 }
79
80 void OnDataSent() override {
81 CHECK(!not_expect_callback_);
82
83 ++on_data_sent_count_;
84 }
85
86 void OnTrailersReceived(const SpdyHeaderBlock& trailers) override {
87 CHECK(!not_expect_callback_);
88
89 trailers_ = trailers;
90 if (run_until_completion_)
91 loop_->Quit();
92 }
93
94 void OnFailed(int error) override {
95 CHECK(!not_expect_callback_);
96 CHECK_EQ(OK, error_);
97 CHECK_NE(OK, error);
98
99 error_ = error;
100 if (run_until_completion_)
101 loop_->Quit();
102 }
103
104 void Start(const BidirectionalStreamRequestInfo* request_info,
105 HttpNetworkSession* session) {
106 stream_.reset(
107 new BidirectionalStream(request_info, session, this, timer_.Pass()));
108 if (run_until_completion_)
109 loop_->Run();
110 }
111
112 void SendData(IOBuffer* data, int length, bool end_of_stream) {
113 not_expect_callback_ = true;
114 stream_->SendData(data, length, end_of_stream);
115 not_expect_callback_ = false;
116 }
117
118 // Starts or continues reading data from |stream_| until no more bytes
119 // can be read synchronously.
120 void StartOrContinueReading() {
121 int rv = ReadData();
122 while (rv > 0) {
123 rv = ReadData();
124 }
125 if (run_until_completion_ && rv == 0)
126 loop_->Quit();
127 }
128
129 // Calls ReadData on the |stream_| and updates internal states.
130 int ReadData() {
131 not_expect_callback_ = true;
132 int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
133 not_expect_callback_ = false;
134 if (rv > 0)
135 data_received_.append(read_buf_->data(), rv);
136 return rv;
137 }
138
139 // Cancels |stream_|.
140 void CancelStream() { stream_->Cancel(); }
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_data_read_count() const { return on_data_read_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 // Quits |loop_|.
170 void QuitLoop() { loop_->Quit(); }
171
172 private:
173 scoped_ptr<BidirectionalStream> stream_;
174 scoped_refptr<IOBuffer> read_buf_;
175 int read_buf_len_;
176 scoped_ptr<base::Timer> timer_;
177 std::string data_received_;
178 scoped_ptr<base::RunLoop> loop_;
179 SpdyHeaderBlock response_headers_;
180 SpdyHeaderBlock trailers_;
181 int error_;
182 int on_data_read_count_;
183 int on_data_sent_count_;
184 bool do_not_start_read_;
185 bool run_until_completion_;
186 // This is to ensure that delegate callback is not invoked synchronously when
187 // calling into |stream_|.
188 bool not_expect_callback_;
189
190 DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
191 };
192
193 // A delegate that cancels the request after response headers are received.
194 class CancelStreamDelegate : public TestDelegateBase {
mmenke 2015/12/16 23:04:37 A bit of a pain, but if we allow cancellation in o
xunjieli 2015/12/17 18:18:55 Done. Good idea!
195 public:
196 CancelStreamDelegate(IOBuffer* buf, int buf_len)
197 : TestDelegateBase(buf, buf_len) {}
198 ~CancelStreamDelegate() override {}
199
200 void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
201 TestDelegateBase::OnHeadersReceived(response_headers);
202 CancelStream();
203 QuitLoop();
204 }
205
206 void OnDataSent() override { NOTREACHED(); }
207
208 void OnDataRead(int bytes_read) override { NOTREACHED(); }
209
210 void OnTrailersReceived(const SpdyHeaderBlock& trailers) override {
211 NOTREACHED();
212 }
213
214 void OnFailed(int error) override { NOTREACHED(); }
215
216 private:
217 DISALLOW_COPY_AND_ASSIGN(CancelStreamDelegate);
218 };
219
220 // A Timer that does not start a delayed task unless the timer is fired.
221 class MockTimer : public base::MockTimer {
222 public:
223 MockTimer() : base::MockTimer(false, false) {}
224 ~MockTimer() override {}
225
226 void Start(const tracked_objects::Location& posted_from,
227 base::TimeDelta delay,
228 const base::Closure& user_task) override {
229 // Sets a maximum delay, so the timer does not fire unless it is told to.
230 base::TimeDelta infinite_delay = base::TimeDelta::Max();
231 base::MockTimer::Start(posted_from, infinite_delay, user_task);
232 }
233
234 private:
235 DISALLOW_COPY_AND_ASSIGN(MockTimer);
236 };
237
238 } // namespace
239
240 class BidirectionalStreamTest : public testing::Test {
241 public:
242 BidirectionalStreamTest()
243 : spdy_util_(kProtoHTTP2, false),
244 session_deps_(kProtoHTTP2),
245 ssl_data_(SSLSocketDataProvider(ASYNC, OK)) {
246 ssl_data_.SetNextProto(kProtoHTTP2);
247 ssl_data_.cert = ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
248 }
249
250 protected:
251 void TearDown() override {
252 if (sequenced_data_) {
253 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
254 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
255 }
256 }
257
258 // Initializes the session using SequencedSocketData.
259 void InitSession(MockRead* reads,
260 size_t reads_count,
261 MockWrite* writes,
262 size_t writes_count,
263 const SpdySessionKey& key) {
264 ASSERT_TRUE(ssl_data_.cert.get());
265 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data_);
266 sequenced_data_.reset(
267 new SequencedSocketData(reads, reads_count, writes, writes_count));
268 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
269 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
270 session_ = CreateSecureSpdySession(http_session_.get(), key, BoundNetLog());
271 }
272
273 SpdyTestUtil spdy_util_;
274 SpdySessionDependencies session_deps_;
275 scoped_ptr<SequencedSocketData> sequenced_data_;
276 scoped_ptr<HttpNetworkSession> http_session_;
277
278 private:
279 SSLSocketDataProvider ssl_data_;
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, 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 request_info.priority = LOWEST;
340
341 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
342 // Create a MockTimer. Retain a raw pointer since the underlying
343 // BidirectionalStreamJob owns it.
344 MockTimer* timer = new MockTimer();
345 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
346 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
347 delegate->set_do_not_start_read(true);
348
349 delegate->Start(&request_info, http_session_.get());
350
351 // Write request, and deliver response headers.
352 base::RunLoop().RunUntilIdle();
353 EXPECT_FALSE(timer->IsRunning());
354 // ReadData returns asynchronously because no data is buffered.
355 int rv = delegate->ReadData();
356 EXPECT_EQ(ERR_IO_PENDING, rv);
357 // Deliver a DATA frame.
358 sequenced_data_->CompleteRead();
359 base::RunLoop().RunUntilIdle();
360 timer->Fire();
361 // Asynchronous completion callback is invoke.
362 EXPECT_EQ(1, delegate->on_data_read_count());
363 EXPECT_EQ(kUploadDataSize * 1,
364 static_cast<int>(delegate->data_received().size()));
365
366 // Deliver the rest. Note that user has not called a second ReadData.
367 sequenced_data_->CompleteRead();
368 base::RunLoop().RunUntilIdle();
369 // ReadData now. Read should complete synchronously.
370 rv = delegate->ReadData();
371 EXPECT_EQ(kUploadDataSize * 2, rv);
372 rv = delegate->ReadData();
373 EXPECT_EQ(OK, rv); // EOF.
374
375 const SpdyHeaderBlock response_headers = delegate->response_headers();
376 EXPECT_EQ("200", response_headers.find(":status")->second);
377 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
378 EXPECT_EQ(1, delegate->on_data_read_count());
379 EXPECT_EQ(0, delegate->on_data_sent_count());
380 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
381 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
382 delegate->GetTotalSentBytes());
383 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
384 delegate->GetTotalReceivedBytes());
385 }
386
387 TEST_F(BidirectionalStreamTest, TestInterleaveReadDataAndSendData) {
388 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
389
390 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
391 "https://www.example.org", 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
392 scoped_ptr<SpdyFrame> data_frame1(
393 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
394 scoped_ptr<SpdyFrame> data_frame2(
395 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
396 scoped_ptr<SpdyFrame> data_frame3(
397 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN));
398 MockWrite writes[] = {
399 CreateMockWrite(*req, 0), CreateMockWrite(*data_frame1, 3),
400 CreateMockWrite(*data_frame2, 6), CreateMockWrite(*data_frame3, 9),
401 };
402
403 scoped_ptr<SpdyFrame> resp(
404 spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
405 scoped_ptr<SpdyFrame> response_body_frame1(
406 spdy_util_.ConstructSpdyBodyFrame(1, false));
407 scoped_ptr<SpdyFrame> response_body_frame2(
408 spdy_util_.ConstructSpdyBodyFrame(1, true));
409
410 MockRead reads[] = {
411 CreateMockRead(*resp, 1),
412 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
413 CreateMockRead(*response_body_frame1, 4),
414 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause.
415 CreateMockRead(*response_body_frame2, 7),
416 MockRead(ASYNC, ERR_IO_PENDING, 8), // Force a pause.
417 MockRead(ASYNC, 0, 10),
418 };
419
420 HostPortPair host_port_pair("www.example.org", 443);
421 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
422 PRIVACY_MODE_DISABLED);
423 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
424
425 BidirectionalStreamRequestInfo request_info;
426 request_info.method = "POST";
427 request_info.url = GURL("https://www.example.org/");
428 request_info.priority = LOWEST;
429 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
430 base::SizeTToString(kBodyDataSize * 3));
431
432 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
433 MockTimer* timer = new MockTimer();
434 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
435 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
436 delegate->set_do_not_start_read(true);
437 delegate->Start(&request_info, http_session_.get());
438 // Send the request and receive response headers.
439 base::RunLoop().RunUntilIdle();
440 EXPECT_FALSE(timer->IsRunning());
441
442 // Send a DATA frame.
443 scoped_refptr<StringIOBuffer> buf(
444 new StringIOBuffer(std::string(kBodyData, kBodyDataSize)));
445 delegate->SendData(buf.get(), buf->size(), false);
446 base::RunLoop().RunUntilIdle();
447 EXPECT_EQ(1, delegate->on_data_sent_count());
448
449 // ReadData and it should return asynchronously because no data is buffered.
450 int rv = delegate->ReadData();
451 EXPECT_EQ(ERR_IO_PENDING, rv);
452 // Deliver a DATA frame, and fire the timer.
453 sequenced_data_->CompleteRead();
454 timer->Fire();
455 base::RunLoop().RunUntilIdle();
456 EXPECT_EQ(1, delegate->on_data_read_count());
457
458 // Send a DATA frame.
459 delegate->SendData(buf.get(), buf->size(), false);
460 base::RunLoop().RunUntilIdle();
461 EXPECT_EQ(2, delegate->on_data_sent_count());
462
463 // ReadData and it should return asynchronously because no data is buffered.
464 rv = delegate->ReadData();
465 EXPECT_EQ(ERR_IO_PENDING, rv);
466 // Deliver a DATA frame, and fire the timer.
467 sequenced_data_->CompleteRead();
468 timer->Fire();
469 base::RunLoop().RunUntilIdle();
470 // Last DATA frame is read. Server half closes.
471 EXPECT_EQ(2, delegate->on_data_read_count());
472
473 // Send the last body frame. Client half closes.
474 delegate->SendData(buf.get(), buf->size(), true);
475 base::RunLoop().RunUntilIdle();
476 EXPECT_EQ(3, delegate->on_data_sent_count());
477 sequenced_data_->CompleteRead();
478
479 // OnClose is invoked since both sides are closed.
480 rv = delegate->ReadData();
481 EXPECT_EQ(OK, rv);
482
483 EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
484 EXPECT_EQ(2, delegate->on_data_read_count());
485 EXPECT_EQ(3, delegate->on_data_sent_count());
486 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
487 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
488 delegate->GetTotalSentBytes());
489 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
490 delegate->GetTotalReceivedBytes());
491 }
492
493 // Tests that BidirectionalStreamSpdyJob::OnClose will complete any remaining
494 // read even if the read queue is empty.
495 TEST_F(BidirectionalStreamTest, TestCompleteAsyncRead) {
496 scoped_ptr<SpdyFrame> req(
497 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
498 // Empty DATA frame with an END_STREAM flag.
499 scoped_ptr<SpdyFrame> end_stream(
500 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
501
502 MockWrite writes[] = {CreateMockWrite(*req.get(), 0)};
503
504 scoped_ptr<SpdyFrame> resp(
505 spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
506
507 scoped_ptr<SpdyFrame> response_body_frame(
508 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
509
510 MockRead reads[] = {
511 CreateMockRead(*resp, 1),
512 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
513 CreateMockRead(*response_body_frame, 3), MockRead(SYNCHRONOUS, 0, 4),
514 };
515
516 HostPortPair host_port_pair("www.example.org", 443);
517 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
518 PRIVACY_MODE_DISABLED);
519 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
520
521 BidirectionalStreamRequestInfo request_info;
522 request_info.method = "GET";
523 request_info.url = GURL("https://www.example.org/");
524 request_info.priority = LOWEST;
525 request_info.end_stream_on_headers = true;
526
527 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
528 MockTimer* timer = new MockTimer();
529 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
530 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
531 delegate->set_do_not_start_read(true);
532 delegate->Start(&request_info, http_session_.get());
533 // Write request, and deliver response headers.
534 base::RunLoop().RunUntilIdle();
535 EXPECT_FALSE(timer->IsRunning());
536
537 // ReadData should return asynchronously because no data is buffered.
538 int rv = delegate->ReadData();
539 EXPECT_EQ(ERR_IO_PENDING, rv);
540 // Deliver END_STREAM.
541 // OnClose should trigger completion of the remaining read.
542 sequenced_data_->CompleteRead();
543 base::RunLoop().RunUntilIdle();
544
545 EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
546 EXPECT_EQ(1, delegate->on_data_read_count());
547 EXPECT_EQ(0u, delegate->data_received().size());
548 EXPECT_EQ(0, delegate->on_data_sent_count());
549 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
550 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
551 delegate->GetTotalSentBytes());
552 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
553 delegate->GetTotalReceivedBytes());
554 }
555
556 TEST_F(BidirectionalStreamTest, TestBuffering) {
557 scoped_ptr<SpdyFrame> req(
558 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
559 // Empty DATA frame with an END_STREAM flag.
560 scoped_ptr<SpdyFrame> end_stream(
561 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
562
563 MockWrite writes[] = {CreateMockWrite(*req.get(), 0)};
564
565 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
566
567 scoped_ptr<SpdyFrame> resp(
568 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
569
570 scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, false));
571 // Last body frame has END_STREAM flag set.
572 scoped_ptr<SpdyFrame> last_body_frame(
573 spdy_util_.ConstructSpdyBodyFrame(1, true));
574
575 MockRead reads[] = {
576 CreateMockRead(*resp, 1),
577 CreateMockRead(*body_frame, 2),
578 CreateMockRead(*body_frame, 3),
579 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
580 CreateMockRead(*last_body_frame, 5),
581 MockRead(SYNCHRONOUS, 0, 6),
582 };
583
584 HostPortPair host_port_pair("www.example.org", 443);
585 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
586 PRIVACY_MODE_DISABLED);
587 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
588
589 BidirectionalStreamRequestInfo request_info;
590 request_info.method = "GET";
591 request_info.url = GURL("https://www.example.org/");
592 request_info.priority = LOWEST;
593 request_info.end_stream_on_headers = true;
594
595 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
596 MockTimer* timer = new MockTimer();
597 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
598 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
599 delegate->Start(&request_info, http_session_.get());
600 // Deliver two DATA frames together.
601 base::RunLoop().RunUntilIdle();
602 EXPECT_TRUE(timer->IsRunning());
603 timer->Fire();
604 base::RunLoop().RunUntilIdle();
605 // This should trigger |more_read_data_pending_| to execute the task at a
606 // later time, and Delegate::OnReadComplete should not have been called.
607 EXPECT_TRUE(timer->IsRunning());
608 EXPECT_EQ(0, delegate->on_data_read_count());
609
610 // Fire the timer now, the two DATA frame should be combined into one
611 // single Delegate::OnReadComplete callback.
612 timer->Fire();
613 base::RunLoop().RunUntilIdle();
614 EXPECT_EQ(1, delegate->on_data_read_count());
615 EXPECT_EQ(kUploadDataSize * 2,
616 static_cast<int>(delegate->data_received().size()));
617
618 // Deliver last DATA frame and EOF. There will be an additional
619 // Delegate::OnReadComplete callback.
620 sequenced_data_->CompleteRead();
621 EXPECT_EQ(2, delegate->on_data_read_count());
622 EXPECT_EQ(kUploadDataSize * 3,
623 static_cast<int>(delegate->data_received().size()));
624
625 const SpdyHeaderBlock response_headers = delegate->response_headers();
626 EXPECT_EQ("200", response_headers.find(":status")->second);
627 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
628 EXPECT_EQ(0, delegate->on_data_sent_count());
629 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
630 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
631 delegate->GetTotalSentBytes());
632 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
633 delegate->GetTotalReceivedBytes());
634 }
635
636 TEST_F(BidirectionalStreamTest, TestBufferingWithTrailers) {
637 scoped_ptr<SpdyFrame> req(
638 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
639 // Empty DATA frame with an END_STREAM flag.
640 scoped_ptr<SpdyFrame> end_stream(
641 spdy_util_.ConstructSpdyBodyFrame(1, nullptr, 0, true));
642
643 MockWrite writes[] = {
644 CreateMockWrite(*req.get(), 0),
645 };
646
647 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
648
649 scoped_ptr<SpdyFrame> resp(
650 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
651
652 scoped_ptr<SpdyFrame> body_frame(spdy_util_.ConstructSpdyBodyFrame(1, false));
653
654 const char* const kTrailers[] = {"foo", "bar"};
655 scoped_ptr<SpdyFrame> trailers(
656 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
657
658 MockRead reads[] = {
659 CreateMockRead(*resp, 1), CreateMockRead(*body_frame, 2),
660 CreateMockRead(*body_frame, 3), CreateMockRead(*body_frame, 4),
661 MockRead(ASYNC, ERR_IO_PENDING, 5), // Force a pause.
662 CreateMockRead(*trailers, 6), MockRead(SYNCHRONOUS, 0, 7),
663 };
664
665 HostPortPair host_port_pair("www.example.org", 443);
666 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
667 PRIVACY_MODE_DISABLED);
668 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
669
670 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
671 MockTimer* timer = new MockTimer();
672 scoped_ptr<TestDelegateBase> delegate(new TestDelegateBase(
673 read_buffer.get(), kReadBufferSize, make_scoped_ptr(timer)));
674
675 BidirectionalStreamRequestInfo request_info;
676 request_info.method = "GET";
677 request_info.url = GURL("https://www.example.org/");
678 request_info.priority = LOWEST;
679 request_info.end_stream_on_headers = true;
680
681 delegate->Start(&request_info, http_session_.get());
682 // Deliver all three DATA frames together.
683 base::RunLoop().RunUntilIdle();
684 EXPECT_TRUE(timer->IsRunning());
685 timer->Fire();
686 base::RunLoop().RunUntilIdle();
687 // This should trigger |more_read_data_pending_| to execute the task at a
688 // later time, and Delegate::OnReadComplete should not have been called.
689 EXPECT_TRUE(timer->IsRunning());
690 EXPECT_EQ(0, delegate->on_data_read_count());
691
692 // Deliver trailers. Remaining read should be completed, since OnClose is
693 // called right after OnTrailersReceived. The three DATA frames should be
694 // delivered in a single OnReadCompleted callback.
695 sequenced_data_->CompleteRead();
696 EXPECT_EQ(1, delegate->on_data_read_count());
697 EXPECT_EQ(kUploadDataSize * 3,
698 static_cast<int>(delegate->data_received().size()));
699 const SpdyHeaderBlock response_headers = delegate->response_headers();
700 EXPECT_EQ("200", response_headers.find(":status")->second);
701 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
702 EXPECT_EQ(0, delegate->on_data_sent_count());
703 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
704 EXPECT_EQ(CountWriteBytes(writes, arraysize(writes)),
705 delegate->GetTotalSentBytes());
706 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
707 delegate->GetTotalReceivedBytes());
708 }
709
710 TEST_F(BidirectionalStreamTest, CancelStream) {
711 scoped_ptr<SpdyFrame> req(
712 spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
713
714 scoped_ptr<SpdyFrame> rst(
715 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
716 MockWrite writes[] = {
717 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
718 };
719
720 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
721
722 scoped_ptr<SpdyFrame> resp(
723 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
724
725 MockRead reads[] = {
726 CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
727 };
728
729 HostPortPair host_port_pair("www.example.org", 443);
730 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
731 PRIVACY_MODE_DISABLED);
732 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
733
734 BidirectionalStreamRequestInfo request_info;
735 request_info.method = "GET";
736 request_info.url = GURL("https://www.example.org/");
737 request_info.priority = LOWEST;
738 request_info.end_stream_on_headers = true;
739
740 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
741 scoped_ptr<CancelStreamDelegate> delegate(
742 new CancelStreamDelegate(read_buffer.get(), kReadBufferSize));
743 delegate->SetRunUntilCompletion(true);
744 delegate->Start(&request_info, http_session_.get());
745 // Makes sure delegate does not get called.
746 base::RunLoop().RunUntilIdle();
747 const SpdyHeaderBlock response_headers = delegate->response_headers();
748 EXPECT_EQ("200", response_headers.find(":status")->second);
749 EXPECT_EQ("header-value", response_headers.find("header-name")->second);
750 EXPECT_EQ(0u, delegate->data_received().size());
751 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
752
753 // Stream is canceled. The total received and sent bytes should be 0.
754 EXPECT_EQ(0, delegate->GetTotalSentBytes());
755 EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
756 EXPECT_EQ(0, delegate->on_data_sent_count());
757 EXPECT_EQ(0, delegate->on_data_read_count());
758 }
759
760 TEST_F(BidirectionalStreamTest, CancelStreamAfterSendData) {
761 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
762
763 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
764 "https://www.example.org", 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
765 scoped_ptr<SpdyFrame> data_frame(
766 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
767 scoped_ptr<SpdyFrame> rst(
768 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
769
770 MockWrite writes[] = {
771 CreateMockWrite(*req, 0), CreateMockWrite(*data_frame, 3),
772 CreateMockWrite(*rst, 4),
773 };
774
775 scoped_ptr<SpdyFrame> resp(
776 spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
777 scoped_ptr<SpdyFrame> response_body_frame(
778 spdy_util_.ConstructSpdyBodyFrame(1, false));
779
780 MockRead reads[] = {
781 CreateMockRead(*resp, 1),
782 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
783 MockRead(ASYNC, 0, 5),
784 };
785
786 HostPortPair host_port_pair("www.example.org", 443);
787 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
788 PRIVACY_MODE_DISABLED);
789 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
790
791 BidirectionalStreamRequestInfo request_info;
792 request_info.method = "POST";
793 request_info.url = GURL("https://www.example.org/");
794 request_info.priority = LOWEST;
795 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
796 base::SizeTToString(kBodyDataSize * 3));
797
798 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
799 scoped_ptr<TestDelegateBase> delegate(
800 new TestDelegateBase(read_buffer.get(), kReadBufferSize));
801 delegate->set_do_not_start_read(true);
802 delegate->Start(&request_info, http_session_.get());
803 // Send the request and receive response headers.
804 base::RunLoop().RunUntilIdle();
805
806 // Send a DATA frame.
807 scoped_refptr<StringIOBuffer> buf(
808 new StringIOBuffer(std::string(kBodyData, kBodyDataSize)));
809 delegate->SendData(buf.get(), buf->size(), false);
810 base::RunLoop().RunUntilIdle();
811 EXPECT_EQ(1, delegate->on_data_sent_count());
812 // Cancel the stream.
813 delegate->CancelStream();
814 base::RunLoop().RunUntilIdle();
815 sequenced_data_->CompleteRead();
816
817 base::RunLoop().RunUntilIdle();
818
819 EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
820 EXPECT_EQ(0, delegate->on_data_read_count());
821 EXPECT_EQ(1, delegate->on_data_sent_count());
822 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
823 EXPECT_EQ(0, delegate->GetTotalSentBytes());
824 EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
825 }
826
827 TEST_F(BidirectionalStreamTest, CancelStreamDuringReadData) {
828 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
829
830 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
831 "https://www.example.org", 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
832 scoped_ptr<SpdyFrame> data_frame(
833 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
834 scoped_ptr<SpdyFrame> rst(
835 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
836
837 MockWrite writes[] = {
838 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 4),
839 };
840
841 scoped_ptr<SpdyFrame> resp(
842 spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
843 scoped_ptr<SpdyFrame> response_body_frame(
844 spdy_util_.ConstructSpdyBodyFrame(1, false));
845
846 MockRead reads[] = {
847 CreateMockRead(*resp, 1),
848 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
849 CreateMockRead(*response_body_frame, 3), MockRead(ASYNC, 0, 5),
850 };
851
852 HostPortPair host_port_pair("www.example.org", 443);
853 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
854 PRIVACY_MODE_DISABLED);
855 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
856
857 BidirectionalStreamRequestInfo request_info;
858 request_info.method = "POST";
859 request_info.url = GURL("https://www.example.org/");
860 request_info.priority = LOWEST;
861 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
862 base::SizeTToString(kBodyDataSize * 3));
863
864 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
865 scoped_ptr<TestDelegateBase> delegate(
866 new TestDelegateBase(read_buffer.get(), kReadBufferSize));
867 delegate->set_do_not_start_read(true);
868 delegate->Start(&request_info, http_session_.get());
869 // Send the request and receive response headers.
870 base::RunLoop().RunUntilIdle();
871
872 EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
873 // Cancel the stream after ReadData returns ERR_IO_PENDING.
874 int rv = delegate->ReadData();
875 EXPECT_EQ(ERR_IO_PENDING, rv);
876 delegate->CancelStream();
877 sequenced_data_->CompleteRead();
878 base::RunLoop().RunUntilIdle();
879
880 EXPECT_EQ(0, delegate->on_data_read_count());
881 EXPECT_EQ(0, delegate->on_data_sent_count());
882 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
883 EXPECT_EQ(0, delegate->GetTotalSentBytes());
884 EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
885 }
886
887 // Receiving a header with uppercase ASCII will result in a protocol error,
888 // which should be propagated via Delegate::OnFailed.
889 TEST_F(BidirectionalStreamTest, PropagateProtocolError) {
890 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructSpdyPost(
891 "https://www.example.org", 1, kBodyDataSize * 3, LOW, nullptr, 0));
892 scoped_ptr<SpdyFrame> rst(
893 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
894
895 MockWrite writes[] = {
896 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
897 };
898
899 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
900 scoped_ptr<SpdyFrame> resp(
901 spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
902
903 MockRead reads[] = {
904 CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
905 };
906
907 HostPortPair host_port_pair("www.example.org", 443);
908 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
909 PRIVACY_MODE_DISABLED);
910 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
911
912 BidirectionalStreamRequestInfo request_info;
913 request_info.method = "POST";
914 request_info.url = GURL("https://www.example.org/");
915 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
916 base::SizeTToString(kBodyDataSize * 3));
917
918 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
919 scoped_ptr<TestDelegateBase> delegate(
920 new TestDelegateBase(read_buffer.get(), kReadBufferSize));
921 delegate->SetRunUntilCompletion(true);
922 delegate->Start(&request_info, http_session_.get());
923
924 base::RunLoop().RunUntilIdle();
925 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate->error());
926 EXPECT_EQ(delegate->response_headers().end(),
927 delegate->response_headers().find(":status"));
928 EXPECT_EQ(0, delegate->on_data_read_count());
929 EXPECT_EQ(0, delegate->on_data_sent_count());
930 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
931 // BidirectionalStreamSpdyStreamJob does not count the bytes sent for |rst|
932 // because it is sent after SpdyStream::Delegate::OnClose is called.
933 EXPECT_EQ(CountWriteBytes(writes, 1), delegate->GetTotalSentBytes());
934 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
935 delegate->GetTotalReceivedBytes());
936 }
937
938 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698