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

Side by Side Diff: net/spdy/bidirectional_spdy_stream_unittest.cc

Issue 1326503003: Added a net::BidirectionalStream to expose a bidirectional streaming interface (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address Comments Created 5 years, 2 months 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_spdy_stream.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
32 class TestBidirectionalStreamDelegate : public BidirectionalStream::Delegate {
33 public:
34 TestBidirectionalStreamDelegate(base::WeakPtr<SpdySession> session,
35 IOBuffer* buf,
36 int buf_len)
37 : bytes_read_(0),
38 stream_(new BidirectionalSpdyStream(session)),
39 loop_(new base::RunLoop),
40 buf_(buf),
41 buf_len_(buf_len) {}
42
43 ~TestBidirectionalStreamDelegate() override {}
44
45 void OnFailed(int rv) override { loop_->Quit(); }
46
47 void OnRequestHeadersSent() override {}
48
49 void OnHeaders(const SpdyHeaderBlock& response_headers) override {
50 response_headers_ = response_headers;
51 int rv = stream_->ReadData(buf_.get(), buf_len_);
52 if (rv != ERR_IO_PENDING)
53 bytes_read_ += rv;
54 }
55
56 void OnReadCompleted(int bytes_read) override {
57 DCHECK_GT(bytes_read, OK);
58 bytes_read_ += bytes_read;
59 }
60
61 void OnDataSent() override {}
62
63 void OnTrailers(const SpdyHeaderBlock& trailers) override {
64 trailers_ = trailers;
65 }
66
67 void OnClose(int status) override {
68 close_status_ = status;
69 loop_->Quit();
70 }
71
72 void Start(HttpRequestInfo* request,
73 RequestPriority priority,
74 const BoundNetLog& net_log) {
75 stream_->Start(request, priority, net_log, this);
76 loop_->Run();
77 }
78
79 void SendData(IOBuffer* data, int length, bool end_of_stream) {
80 stream_->SendData(data, length, end_of_stream);
81 }
82
83 SpdyHeaderBlock response_headers_;
84 SpdyHeaderBlock trailers_;
85 int bytes_read_;
86 int close_status_;
87
88 protected:
89 scoped_ptr<BidirectionalStream> stream_;
90 scoped_ptr<base::RunLoop> loop_;
91
92 private:
93 scoped_refptr<IOBuffer> buf_;
94 int buf_len_;
95 };
96
97 // A delegate that sends data after request headers are sent.
98 class SendDataDelegate : public TestBidirectionalStreamDelegate {
99 public:
100 SendDataDelegate(base::WeakPtr<SpdySession> session,
101 IOBuffer* buf,
102 int buf_len,
103 base::StringPiece data)
104 : TestBidirectionalStreamDelegate(session, buf, buf_len), data_(data) {}
105
106 ~SendDataDelegate() override {}
107
108 void OnRequestHeadersSent() override {
109 TestBidirectionalStreamDelegate::OnRequestHeadersSent();
110 if (data_.data()) {
111 scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(data_.as_string()));
112 SendData(buf.get(), buf->size(), NO_MORE_DATA_TO_SEND);
113 }
114 }
115
116 private:
117 base::StringPiece data_;
118 };
119
120 // A delegate that cancels the request after response headers are received.
121 class CancelStreamDelegate : public TestBidirectionalStreamDelegate {
122 public:
123 CancelStreamDelegate(base::WeakPtr<SpdySession> session,
124 IOBuffer* buf,
125 int buf_len)
126 : TestBidirectionalStreamDelegate(session, buf, buf_len) {}
127
128 ~CancelStreamDelegate() override {}
129
130 void OnHeaders(const SpdyHeaderBlock& response_headers) override {
131 TestBidirectionalStreamDelegate::OnHeaders(response_headers);
132 stream_->Cancel();
133 }
134 };
135
136 } // namespace
137
138 class BidirectionalSpdyStreamTest : public testing::Test {
139 public:
140 BidirectionalSpdyStreamTest()
141 : spdy_util_(kProtoHTTP2), session_deps_(kProtoHTTP2) {}
142
143 protected:
144 void TearDown() override {
145 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
146 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
147 }
148
149 // Initializes the session using SequencedSocketData.
150 void InitSession(MockRead* reads,
151 size_t reads_count,
152 MockWrite* writes,
153 size_t writes_count,
154 const SpdySessionKey& key) {
155 sequenced_data_.reset(
156 new SequencedSocketData(reads, reads_count, writes, writes_count));
157 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
158 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
159 session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog());
160 }
161
162 SpdyTestUtil spdy_util_;
163 SpdySessionDependencies session_deps_;
164 scoped_ptr<SequencedSocketData> sequenced_data_;
165 scoped_refptr<HttpNetworkSession> http_session_;
166 base::WeakPtr<SpdySession> session_;
167 };
168
169 TEST_F(BidirectionalSpdyStreamTest, SendGetRequest) {
170 scoped_ptr<SpdyFrame> req(
171 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
172 MockWrite writes[] = {
173 CreateMockWrite(*req.get(), 0),
174 };
175
176 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
177
178 scoped_ptr<SpdyFrame> resp(
179 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
180
181 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
182
183 const char* const kTrailers[] = {"foo", "bar"};
184 scoped_ptr<SpdyFrame> trailers(
185 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
186
187 MockRead reads[] = {
188 CreateMockRead(*resp, 1), CreateMockRead(*body, 2),
189 CreateMockRead(*trailers, 3), MockRead(SYNCHRONOUS, 0, 4),
190 };
191
192 HostPortPair host_port_pair("www.example.org", 80);
193 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
194 PRIVACY_MODE_DISABLED);
195 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
196
197 HttpRequestInfo request;
198 request.method = "GET";
199 request.url = GURL("http://www.example.org/");
200
201 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
202 scoped_ptr<TestBidirectionalStreamDelegate> delegate(
203 new TestBidirectionalStreamDelegate(session_, read_buffer.get(),
204 kReadBufferSize));
205 BoundNetLog net_log;
206 delegate->Start(&request, DEFAULT_PRIORITY, net_log);
207 base::StringPiece status = delegate->response_headers_[":status"];
208 EXPECT_EQ("200", status);
209 base::StringPiece extra_header = delegate->response_headers_["header-name"];
210 EXPECT_EQ("header-value", extra_header);
211 EXPECT_EQ(kUploadData,
212 std::string(read_buffer->data(), delegate->bytes_read_));
213 base::StringPiece trailer = delegate->trailers_["foo"];
214 EXPECT_EQ("bar", trailer);
215 EXPECT_EQ(OK, delegate->close_status_);
216 }
217
218 TEST_F(BidirectionalSpdyStreamTest, CancelStream) {
219 scoped_ptr<SpdyFrame> req(
220 spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
221 MockWrite writes[] = {
222 CreateMockWrite(*req.get(), 0),
223 };
224
225 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
226
227 scoped_ptr<SpdyFrame> resp(
228 spdy_util_.ConstructSpdyGetSynReply(kExtraResponseHeaders, 1, 1));
229
230 scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
231
232 const char* const kTrailers[] = {"foo", "bar"};
233 scoped_ptr<SpdyFrame> trailers(
234 spdy_util_.ConstructSpdyHeaderFrame(1, kTrailers, 1, true));
235
236 MockRead reads[] = {
237 CreateMockRead(*resp, 1), MockRead(SYNCHRONOUS, 0, 2),
238 };
239
240 HostPortPair host_port_pair("www.example.org", 80);
241 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
242 PRIVACY_MODE_DISABLED);
243 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
244
245 HttpRequestInfo request;
246 request.method = "GET";
247 request.url = GURL("http://www.example.org/");
248
249 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
250 scoped_ptr<TestBidirectionalStreamDelegate> delegate(
251 new CancelStreamDelegate(session_, read_buffer.get(), kReadBufferSize));
252 BoundNetLog net_log;
253 delegate->Start(&request, DEFAULT_PRIORITY, net_log);
254 base::StringPiece status = delegate->response_headers_[":status"];
255 EXPECT_EQ("200", status);
256 base::StringPiece extra_header = delegate->response_headers_["header-name"];
257 EXPECT_EQ("header-value", extra_header);
258 EXPECT_EQ(0, delegate->bytes_read_);
259 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate->close_status_);
260 }
261
262 TEST_F(BidirectionalSpdyStreamTest, SendPostRequest) {
263 BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
264
265 scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
266 scoped_ptr<SpdyFrame> body(
267 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN));
268 MockWrite writes[] = {
269 CreateMockWrite(*req, 0), // request
270 CreateMockWrite(*body, 1), // POST upload frame
271 };
272 const char* const kExtraResponseHeaders[] = {"header-name", "header-value"};
273 scoped_ptr<SpdyFrame> resp(
274 spdy_util_.ConstructSpdyPostSynReply(kExtraResponseHeaders, 1));
275
276 scoped_ptr<SpdyFrame> resp_data(
277 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
278
279 const char* const kExtraHeaders[] = {"foo", "bar"};
280 scoped_ptr<SpdyFrame> trailers(
281 spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1, true));
282
283 MockRead reads[] = {
284 CreateMockRead(*resp, 2), CreateMockRead(*resp_data, 3),
285 CreateMockRead(*trailers, 4), MockRead(SYNCHRONOUS, 0, 5) // EOF
286 };
287
288 HostPortPair host_port_pair("www.example.org", 80);
289 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
290 PRIVACY_MODE_DISABLED);
291 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
292
293 HttpRequestInfo request;
294 request.method = "POST";
295 request.url = GURL("http://www.example.org/");
296
297 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
298 scoped_ptr<TestBidirectionalStreamDelegate> delegate(new SendDataDelegate(
299 session_, read_buffer.get(), kReadBufferSize, kBodyDataStringPiece));
300 BoundNetLog net_log;
301 delegate->Start(&request, DEFAULT_PRIORITY, net_log);
302
303 base::StringPiece header = delegate->response_headers_[":status"];
304 EXPECT_EQ("200", header);
305 base::StringPiece extra_header = delegate->response_headers_["header-name"];
306 EXPECT_EQ("header-value", extra_header);
307 EXPECT_EQ(std::string(kBodyData, kBodyDataSize),
308 std::string(read_buffer->data(), delegate->bytes_read_));
309 base::StringPiece trailer = delegate->trailers_["foo"];
310 EXPECT_EQ("bar", trailer);
311 EXPECT_EQ(OK, delegate->close_status_);
312 }
313
314 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698