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

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

Issue 2032733002: Do not crash on null stream in writing to bidirectional streams (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@fix_crash
Patch Set: Added spdy tests Created 4 years, 6 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 2016 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_impl.h"
6
7 #include <memory>
8 #include <string>
9
10 #include "base/macros.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/run_loop.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_piece.h"
15 #include "base/time/time.h"
16 #include "base/timer/mock_timer.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/test_data_directory.h"
19 #include "net/http/http_request_info.h"
20 #include "net/http/http_response_headers.h"
21 #include "net/http/http_response_info.h"
22 #include "net/log/net_log.h"
23 #include "net/log/test_net_log.h"
24 #include "net/socket/socket_test_util.h"
25 #include "net/spdy/spdy_session.h"
26 #include "net/spdy/spdy_test_util_common.h"
27 #include "net/test/cert_test_util.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29
30 namespace net {
31
32 namespace {
33
34 const char kBodyData[] = "Body data";
35 const size_t kBodyDataSize = arraysize(kBodyData);
36 // Size of the buffer to be allocated for each read.
37 const size_t kReadBufferSize = 4096;
38
39 // Delegate that reads data but does not send any data.
40 class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
41 public:
42 TestDelegateBase(base::WeakPtr<SpdySession> session,
43 IOBuffer* read_buf,
44 int read_buf_len)
45 : stream_(new BidirectionalStreamSpdyImpl(session)),
46 read_buf_(read_buf),
47 read_buf_len_(read_buf_len),
48 loop_(nullptr),
49 error_(OK),
50 bytes_read_(0),
51 on_data_read_count_(0),
52 on_data_sent_count_(0),
53 do_not_start_read_(false),
54 run_until_completion_(false),
55 not_expect_callback_(false),
56 on_failed_called_(false) {}
57
58 ~TestDelegateBase() override {}
59
60 void OnStreamReady(bool request_headers_sent) override {
61 CHECK(!on_failed_called_);
62 }
63
64 void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
65 CHECK(!on_failed_called_);
66 CHECK(!not_expect_callback_);
67 response_headers_ = response_headers;
68 if (!do_not_start_read_)
69 StartOrContinueReading();
70 }
71
72 void OnDataRead(int bytes_read) override {
73 CHECK(!on_failed_called_);
74 CHECK(!not_expect_callback_);
75 on_data_read_count_++;
76 CHECK_GE(bytes_read, OK);
77 bytes_read_ += bytes_read;
78 data_received_.append(read_buf_->data(), bytes_read);
79 if (!do_not_start_read_)
80 StartOrContinueReading();
81 }
82
83 void OnDataSent() override {
84 CHECK(!on_failed_called_);
85 CHECK(!not_expect_callback_);
86 on_data_sent_count_++;
87 }
88
89 void OnTrailersReceived(const SpdyHeaderBlock& trailers) override {
90 CHECK(!on_failed_called_);
91 trailers_ = trailers;
92 if (run_until_completion_)
93 loop_->Quit();
94 }
95
96 void OnFailed(int error) override {
97 CHECK(!on_failed_called_);
98 CHECK(!not_expect_callback_);
99 CHECK_NE(OK, error);
100 error_ = error;
101 on_failed_called_ = true;
102 if (run_until_completion_)
103 loop_->Quit();
104 }
105
106 void Start(const BidirectionalStreamRequestInfo* request,
107 const BoundNetLog& net_log) {
108 stream_->Start(request, net_log,
109 /*send_request_headers_automatically=*/false, this,
110 base::WrapUnique(new base::Timer(false, false)));
111 not_expect_callback_ = false;
112 }
113
114 void SendData(IOBuffer* data, int length, bool end_of_stream) {
115 not_expect_callback_ = true;
116 stream_->SendData(data, length, end_of_stream);
117 not_expect_callback_ = false;
118 }
119
120 void SendvData(const std::vector<scoped_refptr<IOBuffer>>& data,
121 const std::vector<int>& length,
122 bool end_of_stream) {
123 not_expect_callback_ = true;
124 stream_->SendvData(data, length, end_of_stream);
125 not_expect_callback_ = false;
126 }
127
128 // Sets whether the delegate should wait until the completion of the stream.
129 void SetRunUntilCompletion(bool run_until_completion) {
130 run_until_completion_ = run_until_completion;
131 loop_.reset(new base::RunLoop);
132 }
133
134 // Starts or continues read data from |stream_| until there is no more
135 // byte can be read synchronously.
136 void StartOrContinueReading() {
137 int rv = ReadData();
138 while (rv > 0) {
139 rv = ReadData();
140 }
141 if (run_until_completion_ && rv == 0)
142 loop_->Quit();
143 }
144
145 // Calls ReadData on the |stream_| and updates internal states.
146 int ReadData() {
147 int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
148 if (rv > 0) {
149 data_received_.append(read_buf_->data(), rv);
150 bytes_read_ += rv;
151 }
152 return rv;
153 }
154
155 NextProto GetProtocol() const { return stream_->GetProtocol(); }
156
157 int64_t GetTotalReceivedBytes() const {
158 return stream_->GetTotalReceivedBytes();
159 }
160
161 int64_t GetTotalSentBytes() const { return stream_->GetTotalSentBytes(); }
162
163 // Const getters for internal states.
164 const std::string& data_received() const { return data_received_; }
165 int bytes_read() const { return bytes_read_; }
166 int error() const { return error_; }
167 const SpdyHeaderBlock response_headers() const { return response_headers_; }
168 const SpdyHeaderBlock trailers() const { return trailers_; }
169 int on_data_read_count() const { return on_data_read_count_; }
170 int on_data_sent_count() const { return on_data_sent_count_; }
171 bool on_failed_called() const { return on_failed_called_; }
172
173 // Sets whether the delegate should automatically start reading.
174 void set_do_not_start_read(bool do_not_start_read) {
175 do_not_start_read_ = do_not_start_read;
176 }
177
178 // Cancels |stream_|.
179 void CancelStream() { stream_->Cancel(); }
180
181 private:
182 std::unique_ptr<BidirectionalStreamSpdyImpl> stream_;
183 scoped_refptr<IOBuffer> read_buf_;
184 int read_buf_len_;
185 std::string data_received_;
186 std::unique_ptr<base::RunLoop> loop_;
187 SpdyHeaderBlock response_headers_;
188 SpdyHeaderBlock trailers_;
189 int error_;
190 int bytes_read_;
191 int on_data_read_count_;
192 int on_data_sent_count_;
193 bool do_not_start_read_;
194 bool run_until_completion_;
195 bool not_expect_callback_;
196 bool on_failed_called_;
197
198 DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
199 };
200
201 } // namespace
202
203 class BidirectionalStreamSpdyImplTest : public testing::Test {
204 public:
205 BidirectionalStreamSpdyImplTest()
206 : spdy_util_(kProtoHTTP2, true),
207 session_deps_(kProtoHTTP2),
208 ssl_data_(SSLSocketDataProvider(ASYNC, OK)) {
209 ssl_data_.SetNextProto(kProtoHTTP2);
210 ssl_data_.cert = ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
211 }
212
213 protected:
214 void TearDown() override {
215 if (sequenced_data_) {
216 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
217 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
218 }
219 }
220
221 // Initializes the session using SequencedSocketData.
222 void InitSession(MockRead* reads,
223 size_t reads_count,
224 MockWrite* writes,
225 size_t writes_count,
226 const SpdySessionKey& key) {
227 ASSERT_TRUE(ssl_data_.cert.get());
228 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data_);
229 sequenced_data_.reset(
230 new SequencedSocketData(reads, reads_count, writes, writes_count));
231 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
232 session_deps_.net_log = net_log_.bound().net_log();
233 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
234 session_ =
235 CreateSecureSpdySession(http_session_.get(), key, net_log_.bound());
236 }
237
238 BoundTestNetLog net_log_;
239 SpdyTestUtil spdy_util_;
240 SpdySessionDependencies session_deps_;
241 std::unique_ptr<SequencedSocketData> sequenced_data_;
242 std::unique_ptr<HttpNetworkSession> http_session_;
243 base::WeakPtr<SpdySession> session_;
244
245 private:
246 SSLSocketDataProvider ssl_data_;
247 };
248
249 TEST_F(BidirectionalStreamSpdyImplTest, SendDataAfterStreamFailed) {
250 std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
251 "https://www.example.org", 1, kBodyDataSize * 3, LOW, nullptr, 0));
252 std::unique_ptr<SpdySerializedFrame> rst(
253 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
254
255 MockWrite writes[] = {
256 CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
257 };
258
259 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
260 std::unique_ptr<SpdySerializedFrame> resp(
261 spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
262
263 MockRead reads[] = {
264 CreateMockRead(*resp, 1), MockRead(ASYNC, 0, 3),
265 };
266
267 HostPortPair host_port_pair("www.example.org", 443);
268 SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
269 PRIVACY_MODE_DISABLED);
270 InitSession(reads, arraysize(reads), writes, arraysize(writes), key);
271
272 BidirectionalStreamRequestInfo request_info;
273 request_info.method = "POST";
274 request_info.url = GURL("https://www.example.org/");
275 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
276 base::SizeTToString(kBodyDataSize * 3));
277
278 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
279 std::unique_ptr<TestDelegateBase> delegate(
280 new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize));
281 delegate->SetRunUntilCompletion(true);
282 delegate->Start(&request_info, net_log_.bound());
283 base::RunLoop().RunUntilIdle();
284
285 EXPECT_TRUE(delegate->on_failed_called());
286
287 // Try to send data after OnFailed(), should not get called back.
288 scoped_refptr<StringIOBuffer> buf(new StringIOBuffer("dummy"));
289 delegate->SendData(buf.get(), buf->size(), false);
290 base::RunLoop().RunUntilIdle();
291
292 EXPECT_EQ(ERR_SPDY_PROTOCOL_ERROR, delegate->error());
293 EXPECT_EQ(0, delegate->on_data_read_count());
294 EXPECT_EQ(0, delegate->on_data_sent_count());
295 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
296 // BidirectionalStreamSpdyStreamJob does not count the bytes sent for |rst|
297 // because it is sent after SpdyStream::Delegate::OnClose is called.
298 EXPECT_EQ(CountWriteBytes(writes, 1), delegate->GetTotalSentBytes());
299 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
300 delegate->GetTotalReceivedBytes());
301 }
302
303 TEST_F(BidirectionalStreamSpdyImplTest, SendDataAfterCancelStream) {
304 BufferedSpdyFramer framer(spdy_util_.spdy_version());
305
306 std::unique_ptr<SpdySerializedFrame> req(spdy_util_.ConstructSpdyPost(
307 "https://www.example.org", 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
308 std::unique_ptr<SpdySerializedFrame> data_frame(
309 framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE));
310 std::unique_ptr<SpdySerializedFrame> rst(
311 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
312
313 MockWrite writes[] = {
314 CreateMockWrite(*req, 0), CreateMockWrite(*data_frame, 3),
315 CreateMockWrite(*rst, 5),
316 };
317
318 std::unique_ptr<SpdySerializedFrame> resp(
319 spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
320 std::unique_ptr<SpdySerializedFrame> response_body_frame(
321 spdy_util_.ConstructSpdyBodyFrame(1, false));
322
323 MockRead reads[] = {
324 CreateMockRead(*resp, 1),
325 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
326 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
327 MockRead(ASYNC, 0, 6),
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 = "POST";
337 request_info.url = GURL("https://www.example.org/");
338 request_info.priority = LOWEST;
339 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
340 base::SizeTToString(kBodyDataSize * 3));
341
342 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
343 std::unique_ptr<TestDelegateBase> delegate(
344 new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize));
345 delegate->set_do_not_start_read(true);
346 delegate->Start(&request_info, net_log_.bound());
347 // Send the request and receive response headers.
348 sequenced_data_->RunUntilPaused();
349 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
350
351 // Send a DATA frame.
352 scoped_refptr<StringIOBuffer> buf(
353 new StringIOBuffer(std::string(kBodyData, kBodyDataSize)));
354 delegate->SendData(buf.get(), buf->size(), false);
355 sequenced_data_->Resume();
356 base::RunLoop().RunUntilIdle();
357 // Cancel the stream.
358 delegate->CancelStream();
359 sequenced_data_->Resume();
360 base::RunLoop().RunUntilIdle();
361
362 // Try to send data after Cancel(), should not get called back.
363 delegate->SendData(buf.get(), buf->size(), false);
364 base::MessageLoop::current()->RunUntilIdle();
365 EXPECT_FALSE(delegate->on_failed_called());
366
367 EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
368 EXPECT_EQ(0, delegate->on_data_read_count());
369 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
370 EXPECT_EQ(0, delegate->GetTotalSentBytes());
371 EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
372 }
373
374 } // namespace net
OLDNEW
« net/quic/bidirectional_stream_quic_impl.cc ('K') | « net/spdy/bidirectional_stream_spdy_impl.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698