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

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: Rebased Created 5 years, 1 month 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/memory/scoped_ptr.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_piece.h"
12 #include "net/base/net_errors.h"
13 #include "net/http/http_request_info.h"
14 #include "net/http/http_response_headers.h"
15 #include "net/http/http_response_info.h"
16 #include "net/socket/socket_test_util.h"
17 #include "net/spdy/spdy_read_queue.h"
18 #include "net/spdy/spdy_session.h"
19 #include "net/spdy/spdy_test_util_common.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace net {
23
24 namespace {
25
26 const char kBodyData[] = "Body data";
27 const size_t kBodyDataSize = arraysize(kBodyData);
28 const base::StringPiece kBodyDataStringPiece(kBodyData, kBodyDataSize);
29 // Size of the buffer to be allocated for each read.
30 const size_t kReadBufferSize = 4096;
31 const size_t kSmallReadBufferSize = 4;
32
33 class TestBidirectionalStreamSpdyJobDelegate
34 : public BidirectionalStreamJob::Delegate {
35 public:
36 TestBidirectionalStreamSpdyJobDelegate(base::WeakPtr<SpdySession> session,
37 IOBuffer* read_buf,
38 int read_buf_len)
39 : bytes_read_(0),
40 close_status_(ERR_FAILED),
41 stream_(new BidirectionalStreamSpdyJob(session)),
42 loop_(new base::RunLoop),
43 read_buf_(read_buf),
44 read_buf_len_(read_buf_len) {}
45
46 ~TestBidirectionalStreamSpdyJobDelegate() override {}
47
48 void OnFailed(Error rv) override { loop_->Quit(); }
49
50 void OnRequestHeadersSent() override {}
51
52 void OnHeaders(const SpdyHeaderBlock& response_headers) override {
53 response_headers_ = response_headers;
54 StartOrContinueReading();
55 }
56
57 void OnReadCompleted(int bytes_read) override {
58 CHECK_GT(bytes_read, OK);
59 bytes_read_ += bytes_read;
60 data_received_.append(read_buf_->data(), bytes_read_);
61 StartOrContinueReading();
62 }
63
64 void OnDataSent() override {}
65
66 void OnTrailers(const SpdyHeaderBlock& trailers) override {
67 trailers_ = trailers;
68 }
69
70 void OnClose(int status) override {
71 close_status_ = status;
72 loop_->Quit();
73 }
74
75 void Start(const HttpRequestInfo& request,
76 RequestPriority priority,
77 const BoundNetLog& net_log) {
78 stream_->Start(request, priority, net_log, this);
79 loop_->Run();
80 }
81
82 void SendData(IOBuffer* data, int length, bool end_of_stream) {
83 stream_->SendData(data, length, end_of_stream);
84 }
85
86 const std::string& data_received() const { return data_received_; }
87
88 SpdyHeaderBlock response_headers_;
89 SpdyHeaderBlock trailers_;
90 int bytes_read_;
91 int close_status_;
92
93 protected:
94 scoped_ptr<BidirectionalStreamSpdyJob> stream_;
95 scoped_ptr<base::RunLoop> loop_;
96
97 private:
98 void StartOrContinueReading() {
99 int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
100 while (rv > 0) {
101 bytes_read_ += rv;
102 data_received_.append(read_buf_->data(), rv);
103 rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
104 }
105 }
106
107 scoped_refptr<IOBuffer> read_buf_;
108 int read_buf_len_;
109 std::string data_received_;
110 };
111
112 // A delegate that sends data after request headers are sent.
113 class SendDataDelegate : public TestBidirectionalStreamSpdyJobDelegate {
114 public:
115 SendDataDelegate(base::WeakPtr<SpdySession> session,
116 IOBuffer* buf,
117 int buf_len,
118 base::StringPiece data)
119 : TestBidirectionalStreamSpdyJobDelegate(session, buf, buf_len),
120 data_(data) {}
121
122 ~SendDataDelegate() override {}
123
124 void OnRequestHeadersSent() override {
125 TestBidirectionalStreamSpdyJobDelegate::OnRequestHeadersSent();
126 if (data_.data()) {
127 scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(data_.as_string()));
128 SendData(buf.get(), buf->size(), NO_MORE_DATA_TO_SEND);
129 }
130 }
131
132 private:
133 base::StringPiece data_;
134 };
135
136 // A delegate that cancels the request after response headers are received.
137 class CancelStreamDelegate : public TestBidirectionalStreamSpdyJobDelegate {
138 public:
139 CancelStreamDelegate(base::WeakPtr<SpdySession> session,
140 IOBuffer* buf,
141 int buf_len)
142 : TestBidirectionalStreamSpdyJobDelegate(session, buf, buf_len) {}
143
144 ~CancelStreamDelegate() override {}
145
146 void OnHeaders(const SpdyHeaderBlock& response_headers) override {
147 TestBidirectionalStreamSpdyJobDelegate::OnHeaders(response_headers);
148 stream_->Cancel();
149 loop_->Quit();
150 }
151
152 void OnDataSent() override { ASSERT_TRUE(false); }
153
154 void OnReadCompleted(int bytes_read) override { ASSERT_TRUE(false); }
155
156 void OnTrailers(const SpdyHeaderBlock& trailers) override {
157 ASSERT_TRUE(false);
158 }
159
160 void OnClose(int error) override { ASSERT_TRUE(false); }
161 };
162
163 } // namespace
164
165 class BidirectionalStreamSpdyJobTest : public testing::Test {
166 public:
167 BidirectionalStreamSpdyJobTest()
168 : spdy_util_(kProtoHTTP2), session_deps_(kProtoHTTP2) {}
169
170 protected:
171 void TearDown() override {
172 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
173 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
174 }
175
176 // Initializes the session using SequencedSocketData.
177 void InitSession(MockRead* reads,
178 size_t reads_count,
179 MockWrite* writes,
180 size_t writes_count,
181 const SpdySessionKey& key) {
182 sequenced_data_.reset(
183 new SequencedSocketData(reads, reads_count, writes, writes_count));
184 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
185 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
186 session_ =
187 CreateInsecureSpdySession(http_session_.get(), key, BoundNetLog());
188 }
189
190 SpdyTestUtil spdy_util_;
191 SpdySessionDependencies session_deps_;
192 scoped_ptr<SequencedSocketData> sequenced_data_;
193 scoped_ptr<HttpNetworkSession> http_session_;
194 base::WeakPtr<SpdySession> session_;
195 };
196
197 TEST_F(BidirectionalStreamSpdyJobTest, SendGetRequest) {
198 scoped_ptr<SpdyFrame> req(
199 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
200 MockWrite writes[] = {
201 CreateMockWrite(*req.get(), 0),
202 };
203
204 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
205
206 scoped_ptr<SpdyFrame> resp(
207 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
208
209 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
210
211 const char* const kTrailers[] = {"foo", "bar"};
212 scoped_ptr<SpdyFrame> trailers(
213 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
214
215 MockRead reads[] = {
216 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
217 CreateMockRead(*trailers, 3), MockRead(SYNCHRONOUS, 0, 4),
218 };
219
220 HostPortPair host_port_pair("www.example.org", 80);
221 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
222 PRIVACY_MODE_DISABLED);
223 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
224
225 HttpRequestInfo request;
226 request.method = "GET";
227 request.url = GURL("http://www.example.org/");
228
229 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
230 scoped_ptr<TestBidirectionalStreamSpdyJobDelegate> delegate(
231 new TestBidirectionalStreamSpdyJobDelegate(session_, read_buffer.get(),
232 kReadBufferSize));
233 BoundNetLog net_log;
234 delegate->Start(request, DEFAULT_PRIORITY, net_log);
235 base::StringPiece status = delegate->response_headers_[":status"];
236 EXPECT_EQ("200", status);
237 base::StringPiece extra_header = delegate->response_headers_["header-name"];
238 EXPECT_EQ("header-value", extra_header);
239 EXPECT_EQ(kUploadDataSize, delegate->bytes_read_);
240 EXPECT_EQ(kUploadData, delegate->data_received());
241 base::StringPiece trailer = delegate->trailers_["foo"];
242 EXPECT_EQ("bar", trailer);
243 EXPECT_EQ(OK, delegate->close_status_);
244 }
245
246 TEST_F(BidirectionalStreamSpdyJobTest, SendGetRequestSmallReadBuffer) {
247 scoped_ptr<SpdyFrame> req(
248 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
249 MockWrite writes[] = {
250 CreateMockWrite(*req.get(), 0),
251 };
252
253 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
254
255 scoped_ptr<SpdyFrame> resp(
256 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
257
258 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
259
260 const char* const kTrailers[] = {"foo", "bar"};
261 scoped_ptr<SpdyFrame> trailers(
262 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
263
264 MockRead reads[] = {
265 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
266 CreateMockRead(*trailers, 3), MockRead(SYNCHRONOUS, 0, 4),
267 };
268
269 HostPortPair host_port_pair("www.example.org", 80);
270 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
271 PRIVACY_MODE_DISABLED);
272 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
273
274 HttpRequestInfo request;
275 request.method = "GET";
276 request.url = GURL("http://www.example.org/");
277
278 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kSmallReadBufferSize));
279 scoped_ptr<TestBidirectionalStreamSpdyJobDelegate> delegate(
280 new TestBidirectionalStreamSpdyJobDelegate(session_, read_buffer.get(),
281 kSmallReadBufferSize));
282 BoundNetLog net_log;
283 delegate->Start(request, DEFAULT_PRIORITY, net_log);
284 base::StringPiece status = delegate->response_headers_[":status"];
285 EXPECT_EQ("200", status);
286 base::StringPiece extra_header = delegate->response_headers_["header-name"];
287 EXPECT_EQ("header-value", extra_header);
288 EXPECT_EQ(kUploadDataSize, delegate->bytes_read_);
289 EXPECT_EQ(kUploadData, delegate->data_received());
290 base::StringPiece trailer = delegate->trailers_["foo"];
291 EXPECT_EQ("bar", trailer);
292 EXPECT_EQ(OK, delegate->close_status_);
293 }
294
295 TEST_F(BidirectionalStreamSpdyJobTest, SendGetRequestNoTrailers) {
296 scoped_ptr<SpdyFrame> req(
297 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
298 MockWrite writes[] = {
299 CreateMockWrite(*req.get(), 0),
300 };
301
302 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
303
304 scoped_ptr<SpdyFrame> resp(
305 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
306
307 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
308
309 MockRead reads[] = {
310 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
311 MockRead(SYNCHRONOUS, 0, 3),
312 };
313
314 HostPortPair host_port_pair("www.example.org", 80);
315 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
316 PRIVACY_MODE_DISABLED);
317 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
318
319 HttpRequestInfo request;
320 request.method = "GET";
321 request.url = GURL("http://www.example.org/");
322
323 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
324 scoped_ptr<TestBidirectionalStreamSpdyJobDelegate> delegate(
325 new TestBidirectionalStreamSpdyJobDelegate(session_, read_buffer.get(),
326 kReadBufferSize));
327 BoundNetLog net_log;
328 delegate->Start(request, DEFAULT_PRIORITY, net_log);
329 base::StringPiece status = delegate->response_headers_[":status"];
330 EXPECT_EQ("200", status);
331 base::StringPiece extra_header = delegate->response_headers_["header-name"];
332 EXPECT_EQ("header-value", extra_header);
333 EXPECT_EQ(kUploadDataSize, delegate->bytes_read_);
334 EXPECT_EQ(kUploadData, delegate->data_received());
335 EXPECT_EQ(OK, delegate->close_status_);
336 }
337
338 TEST_F(BidirectionalStreamSpdyJobTest, CancelStream) {
339 scoped_ptr<SpdyFrame> req(
340 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
341 scoped_ptr<SpdyFrame> rst(
342 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
343 MockWrite writes[] = {
344 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
345 };
346
347 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
348
349 scoped_ptr<SpdyFrame> resp(
350 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
351
352 MockRead reads[] = {
353 CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
354 };
355
356 HostPortPair host_port_pair("www.example.org", 80);
357 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
358 PRIVACY_MODE_DISABLED);
359 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
360
361 HttpRequestInfo request;
362 request.method = "GET";
363 request.url = GURL("http://www.example.org/");
364
365 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
366 scoped_ptr<TestBidirectionalStreamSpdyJobDelegate> delegate(
367 new CancelStreamDelegate(session_, read_buffer.get(), kReadBufferSize));
368 BoundNetLog net_log;
369 delegate->Start(request, DEFAULT_PRIORITY, net_log);
370 // Makes sure delegate does not get called.
371 base::RunLoop().RunUntilIdle();
372 base::StringPiece status = delegate->response_headers_[":status"];
373 EXPECT_EQ("200", status);
374 base::StringPiece extra_header = delegate->response_headers_["header-name"];
375 EXPECT_EQ("header-value", extra_header);
376 EXPECT_EQ(0, delegate->bytes_read_);
377 }
378
379 TEST_F(BidirectionalStreamSpdyJobTest, SendPostRequest) {
380 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
381
382 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
383 scoped_ptr<SpdyFrame> body(
384 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN));
385 MockWrite writes[] = {
386 CreateMockWrite(*req, 0), // request
387 CreateMockWrite(*body, 1), // POST upload frame
388 };
389 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
390 scoped_ptr<SpdyFrame> resp(
391 spdy_util_.ConstructSpdyPostSynReply(kExtraResponseHeaders, 1));
392
393 scoped_ptr<SpdyFrame> resp_data(
394 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
395
396 const char* const kExtraHeaders[] = {"foo", "bar"};
397 scoped_ptr<SpdyFrame> trailers(
398 spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1, true));
399
400 MockRead reads[] = {
401 CreateMockRead(*resp, 2), CreateMockRead(*resp_data, 3),
402 CreateMockRead(*trailers, 4), MockRead(SYNCHRONOUS, 0, 5) // EOF
403 };
404
405 HostPortPair host_port_pair("www.example.org", 80);
406 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
407 PRIVACY_MODE_DISABLED);
408 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
409
410 HttpRequestInfo request;
411 request.method = "POST";
412 request.url = GURL("http://www.example.org/");
413
414 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
415 scoped_ptr<TestBidirectionalStreamSpdyJobDelegate> delegate(
416 new SendDataDelegate(session_, read_buffer.get(), kReadBufferSize,
417 kBodyDataStringPiece));
418 BoundNetLog net_log;
419 delegate->Start(request, DEFAULT_PRIORITY, net_log);
420
421 base::StringPiece header = delegate->response_headers_[":status"];
422 EXPECT_EQ("200", header);
423 base::StringPiece extra_header = delegate->response_headers_["header-name"];
424 EXPECT_EQ("header-value", extra_header);
425 EXPECT_EQ((int)kBodyDataSize, delegate->bytes_read_);
426 EXPECT_EQ(std::string(kBodyData, kBodyDataSize), delegate->data_received());
427 base::StringPiece trailer = delegate->trailers_["foo"];
428 EXPECT_EQ("bar", trailer);
429 EXPECT_EQ(OK, delegate->close_status_);
430 }
431
432 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698