blob: 6e0f2a386f9bfa39b988c71f03aa78b934417fe7 [file] [log] [blame]
xunjieli707f8952016-06-06 15:22:061// 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"
xunjieli707f8952016-06-06 15:22:0618#include "net/http/http_request_info.h"
19#include "net/http/http_response_headers.h"
20#include "net/http/http_response_info.h"
21#include "net/log/net_log.h"
22#include "net/log/test_net_log.h"
23#include "net/socket/socket_test_util.h"
24#include "net/spdy/spdy_session.h"
25#include "net/spdy/spdy_test_util_common.h"
26#include "net/test/cert_test_util.h"
robpercival214763f2016-07-01 23:27:0127#include "net/test/gtest_util.h"
rsleevia69c79a2016-06-22 03:28:4328#include "net/test/test_data_directory.h"
robpercival214763f2016-07-01 23:27:0129#include "testing/gmock/include/gmock/gmock.h"
xunjieli707f8952016-06-06 15:22:0630#include "testing/gtest/include/gtest/gtest.h"
31
robpercival214763f2016-07-01 23:27:0132using net::test::IsError;
33using net::test::IsOk;
34
xunjieli707f8952016-06-06 15:22:0635namespace net {
36
37namespace {
38
39const char kBodyData[] = "Body data";
40const size_t kBodyDataSize = arraysize(kBodyData);
41// Size of the buffer to be allocated for each read.
42const size_t kReadBufferSize = 4096;
43
44class TestDelegateBase : public BidirectionalStreamImpl::Delegate {
45 public:
46 TestDelegateBase(base::WeakPtr<SpdySession> session,
47 IOBuffer* read_buf,
48 int read_buf_len)
49 : stream_(new BidirectionalStreamSpdyImpl(session)),
50 read_buf_(read_buf),
51 read_buf_len_(read_buf_len),
52 loop_(nullptr),
53 error_(OK),
54 bytes_read_(0),
55 on_data_read_count_(0),
56 on_data_sent_count_(0),
57 do_not_start_read_(false),
58 run_until_completion_(false),
59 not_expect_callback_(false),
60 on_failed_called_(false) {}
61
62 ~TestDelegateBase() override {}
63
64 void OnStreamReady(bool request_headers_sent) override {
65 CHECK(!on_failed_called_);
66 }
67
68 void OnHeadersReceived(const SpdyHeaderBlock& response_headers) override {
69 CHECK(!on_failed_called_);
70 CHECK(!not_expect_callback_);
bnc94893a72016-06-30 13:45:2571 response_headers_ = response_headers.Clone();
xunjieli707f8952016-06-06 15:22:0672 if (!do_not_start_read_)
73 StartOrContinueReading();
74 }
75
76 void OnDataRead(int bytes_read) override {
77 CHECK(!on_failed_called_);
78 CHECK(!not_expect_callback_);
79 on_data_read_count_++;
80 CHECK_GE(bytes_read, OK);
81 bytes_read_ += bytes_read;
82 data_received_.append(read_buf_->data(), bytes_read);
83 if (!do_not_start_read_)
84 StartOrContinueReading();
85 }
86
87 void OnDataSent() override {
88 CHECK(!on_failed_called_);
89 CHECK(!not_expect_callback_);
90 on_data_sent_count_++;
91 }
92
93 void OnTrailersReceived(const SpdyHeaderBlock& trailers) override {
94 CHECK(!on_failed_called_);
bnc94893a72016-06-30 13:45:2595 trailers_ = trailers.Clone();
xunjieli707f8952016-06-06 15:22:0696 if (run_until_completion_)
97 loop_->Quit();
98 }
99
100 void OnFailed(int error) override {
101 CHECK(!on_failed_called_);
102 CHECK(!not_expect_callback_);
103 CHECK_NE(OK, error);
104 error_ = error;
105 on_failed_called_ = true;
106 if (run_until_completion_)
107 loop_->Quit();
108 }
109
110 void Start(const BidirectionalStreamRequestInfo* request,
111 const BoundNetLog& net_log) {
112 stream_->Start(request, net_log,
113 /*send_request_headers_automatically=*/false, this,
114 base::WrapUnique(new base::Timer(false, false)));
115 not_expect_callback_ = false;
116 }
117
118 void SendData(IOBuffer* data, int length, bool end_of_stream) {
119 not_expect_callback_ = true;
120 stream_->SendData(data, length, end_of_stream);
121 not_expect_callback_ = false;
122 }
123
124 void SendvData(const std::vector<scoped_refptr<IOBuffer>>& data,
125 const std::vector<int>& length,
126 bool end_of_stream) {
127 not_expect_callback_ = true;
128 stream_->SendvData(data, length, end_of_stream);
129 not_expect_callback_ = false;
130 }
131
132 // Sets whether the delegate should wait until the completion of the stream.
133 void SetRunUntilCompletion(bool run_until_completion) {
134 run_until_completion_ = run_until_completion;
135 loop_.reset(new base::RunLoop);
136 }
137
138 // Starts or continues read data from |stream_| until there is no more
139 // byte can be read synchronously.
140 void StartOrContinueReading() {
141 int rv = ReadData();
142 while (rv > 0) {
143 rv = ReadData();
144 }
145 if (run_until_completion_ && rv == 0)
146 loop_->Quit();
147 }
148
149 // Calls ReadData on the |stream_| and updates internal states.
150 int ReadData() {
151 int rv = stream_->ReadData(read_buf_.get(), read_buf_len_);
152 if (rv > 0) {
153 data_received_.append(read_buf_->data(), rv);
154 bytes_read_ += rv;
155 }
156 return rv;
157 }
158
159 NextProto GetProtocol() const { return stream_->GetProtocol(); }
160
161 int64_t GetTotalReceivedBytes() const {
162 return stream_->GetTotalReceivedBytes();
163 }
164
165 int64_t GetTotalSentBytes() const { return stream_->GetTotalSentBytes(); }
166
167 // Const getters for internal states.
168 const std::string& data_received() const { return data_received_; }
169 int bytes_read() const { return bytes_read_; }
170 int error() const { return error_; }
bnc94893a72016-06-30 13:45:25171 const SpdyHeaderBlock& response_headers() const { return response_headers_; }
172 const SpdyHeaderBlock& trailers() const { return trailers_; }
xunjieli707f8952016-06-06 15:22:06173 int on_data_read_count() const { return on_data_read_count_; }
174 int on_data_sent_count() const { return on_data_sent_count_; }
175 bool on_failed_called() const { return on_failed_called_; }
176
177 // Sets whether the delegate should automatically start reading.
178 void set_do_not_start_read(bool do_not_start_read) {
179 do_not_start_read_ = do_not_start_read;
180 }
181
182 // Cancels |stream_|.
183 void CancelStream() { stream_->Cancel(); }
184
185 private:
186 std::unique_ptr<BidirectionalStreamSpdyImpl> stream_;
187 scoped_refptr<IOBuffer> read_buf_;
188 int read_buf_len_;
189 std::string data_received_;
190 std::unique_ptr<base::RunLoop> loop_;
191 SpdyHeaderBlock response_headers_;
192 SpdyHeaderBlock trailers_;
193 int error_;
194 int bytes_read_;
195 int on_data_read_count_;
196 int on_data_sent_count_;
197 bool do_not_start_read_;
198 bool run_until_completion_;
199 bool not_expect_callback_;
200 bool on_failed_called_;
201
202 DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
203};
204
205} // namespace
206
207class BidirectionalStreamSpdyImplTest : public testing::Test {
208 public:
209 BidirectionalStreamSpdyImplTest()
bncd16676a2016-07-20 16:23:01210 : default_url_(kDefaultUrl),
bnc3d9035b32016-06-30 18:18:48211 host_port_pair_(HostPortPair::FromURL(default_url_)),
212 key_(host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED),
xunjieli707f8952016-06-06 15:22:06213 ssl_data_(SSLSocketDataProvider(ASYNC, OK)) {
214 ssl_data_.SetNextProto(kProtoHTTP2);
215 ssl_data_.cert = ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
216 }
217
218 protected:
219 void TearDown() override {
220 if (sequenced_data_) {
221 EXPECT_TRUE(sequenced_data_->AllReadDataConsumed());
222 EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed());
223 }
224 }
225
226 // Initializes the session using SequencedSocketData.
227 void InitSession(MockRead* reads,
228 size_t reads_count,
229 MockWrite* writes,
bnc3d9035b32016-06-30 18:18:48230 size_t writes_count) {
xunjieli707f8952016-06-06 15:22:06231 ASSERT_TRUE(ssl_data_.cert.get());
232 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data_);
233 sequenced_data_.reset(
234 new SequencedSocketData(reads, reads_count, writes, writes_count));
235 session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get());
236 session_deps_.net_log = net_log_.bound().net_log();
237 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
238 session_ =
bnc3d9035b32016-06-30 18:18:48239 CreateSecureSpdySession(http_session_.get(), key_, net_log_.bound());
xunjieli707f8952016-06-06 15:22:06240 }
241
242 BoundTestNetLog net_log_;
243 SpdyTestUtil spdy_util_;
244 SpdySessionDependencies session_deps_;
bnc3d9035b32016-06-30 18:18:48245 const GURL default_url_;
246 const HostPortPair host_port_pair_;
247 const SpdySessionKey key_;
xunjieli707f8952016-06-06 15:22:06248 std::unique_ptr<SequencedSocketData> sequenced_data_;
249 std::unique_ptr<HttpNetworkSession> http_session_;
250 base::WeakPtr<SpdySession> session_;
251
252 private:
253 SSLSocketDataProvider ssl_data_;
254};
255
256TEST_F(BidirectionalStreamSpdyImplTest, SendDataAfterStreamFailed) {
bncdf80d44fd2016-07-15 20:27:41257 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
bnc3d9035b32016-06-30 18:18:48258 kDefaultUrl, 1, kBodyDataSize * 3, LOW, nullptr, 0));
bncdf80d44fd2016-07-15 20:27:41259 SpdySerializedFrame rst(
xunjieli707f8952016-06-06 15:22:06260 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
261
262 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:41263 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
xunjieli707f8952016-06-06 15:22:06264 };
265
266 const char* const kExtraHeaders[] = {"X-UpperCase", "yes"};
bncdf80d44fd2016-07-15 20:27:41267 SpdySerializedFrame resp(
xunjieli707f8952016-06-06 15:22:06268 spdy_util_.ConstructSpdyGetSynReply(kExtraHeaders, 1, 1));
269
270 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:41271 CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3),
xunjieli707f8952016-06-06 15:22:06272 };
273
bnc3d9035b32016-06-30 18:18:48274 InitSession(reads, arraysize(reads), writes, arraysize(writes));
xunjieli707f8952016-06-06 15:22:06275
276 BidirectionalStreamRequestInfo request_info;
277 request_info.method = "POST";
bnc3d9035b32016-06-30 18:18:48278 request_info.url = default_url_;
xunjieli707f8952016-06-06 15:22:06279 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
280 base::SizeTToString(kBodyDataSize * 3));
281
282 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
283 std::unique_ptr<TestDelegateBase> delegate(
284 new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize));
285 delegate->SetRunUntilCompletion(true);
286 delegate->Start(&request_info, net_log_.bound());
287 base::RunLoop().RunUntilIdle();
288
289 EXPECT_TRUE(delegate->on_failed_called());
290
291 // Try to send data after OnFailed(), should not get called back.
292 scoped_refptr<StringIOBuffer> buf(new StringIOBuffer("dummy"));
293 delegate->SendData(buf.get(), buf->size(), false);
294 base::RunLoop().RunUntilIdle();
295
robpercival214763f2016-07-01 23:27:01296 EXPECT_THAT(delegate->error(), IsError(ERR_SPDY_PROTOCOL_ERROR));
xunjieli707f8952016-06-06 15:22:06297 EXPECT_EQ(0, delegate->on_data_read_count());
298 EXPECT_EQ(0, delegate->on_data_sent_count());
299 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
300 // BidirectionalStreamSpdyStreamJob does not count the bytes sent for |rst|
301 // because it is sent after SpdyStream::Delegate::OnClose is called.
302 EXPECT_EQ(CountWriteBytes(writes, 1), delegate->GetTotalSentBytes());
303 EXPECT_EQ(CountReadBytes(reads, arraysize(reads)),
304 delegate->GetTotalReceivedBytes());
305}
306
307TEST_F(BidirectionalStreamSpdyImplTest, SendDataAfterCancelStream) {
bncdf80d44fd2016-07-15 20:27:41308 SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
bnc3d9035b32016-06-30 18:18:48309 kDefaultUrl, 1, kBodyDataSize * 3, LOWEST, nullptr, 0));
bncdf80d44fd2016-07-15 20:27:41310 SpdySerializedFrame data_frame(
311 spdy_util_.ConstructSpdyDataFrame(1, kBodyData, kBodyDataSize,
312 /*fin=*/false));
313 SpdySerializedFrame rst(
xunjieli707f8952016-06-06 15:22:06314 spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
315
316 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:41317 CreateMockWrite(req, 0), CreateMockWrite(data_frame, 3),
318 CreateMockWrite(rst, 5),
xunjieli707f8952016-06-06 15:22:06319 };
320
bncdf80d44fd2016-07-15 20:27:41321 SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetSynReply(nullptr, 0, 1));
322 SpdySerializedFrame response_body_frame(
323 spdy_util_.ConstructSpdyDataFrame(1, false));
xunjieli707f8952016-06-06 15:22:06324
325 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:41326 CreateMockRead(resp, 1),
xunjieli707f8952016-06-06 15:22:06327 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause.
328 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause.
329 MockRead(ASYNC, 0, 6),
330 };
331
bnc3d9035b32016-06-30 18:18:48332 InitSession(reads, arraysize(reads), writes, arraysize(writes));
xunjieli707f8952016-06-06 15:22:06333
334 BidirectionalStreamRequestInfo request_info;
335 request_info.method = "POST";
bnc3d9035b32016-06-30 18:18:48336 request_info.url = default_url_;
xunjieli707f8952016-06-06 15:22:06337 request_info.priority = LOWEST;
338 request_info.extra_headers.SetHeader(net::HttpRequestHeaders::kContentLength,
339 base::SizeTToString(kBodyDataSize * 3));
340
341 scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
342 std::unique_ptr<TestDelegateBase> delegate(
343 new TestDelegateBase(session_, read_buffer.get(), kReadBufferSize));
344 delegate->set_do_not_start_read(true);
345 delegate->Start(&request_info, net_log_.bound());
346 // Send the request and receive response headers.
347 sequenced_data_->RunUntilPaused();
348 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
349
350 // Send a DATA frame.
351 scoped_refptr<StringIOBuffer> buf(
352 new StringIOBuffer(std::string(kBodyData, kBodyDataSize)));
353 delegate->SendData(buf.get(), buf->size(), false);
354 sequenced_data_->Resume();
355 base::RunLoop().RunUntilIdle();
356 // Cancel the stream.
357 delegate->CancelStream();
358 sequenced_data_->Resume();
359 base::RunLoop().RunUntilIdle();
360
361 // Try to send data after Cancel(), should not get called back.
362 delegate->SendData(buf.get(), buf->size(), false);
fdoray92e35a72016-06-10 15:54:55363 base::RunLoop().RunUntilIdle();
xunjieli707f8952016-06-06 15:22:06364 EXPECT_FALSE(delegate->on_failed_called());
365
366 EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
367 EXPECT_EQ(0, delegate->on_data_read_count());
368 EXPECT_EQ(kProtoHTTP2, delegate->GetProtocol());
369 EXPECT_EQ(0, delegate->GetTotalSentBytes());
370 EXPECT_EQ(0, delegate->GetTotalReceivedBytes());
371}
372
373} // namespace net