blob: 66933a629629f503cf262cf965103b3f75f39a37 [file] [log] [blame]
xunjieli11834f02015-12-22 04:27:081// 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
xunjieli5749218c2016-03-22 16:43:065#include "net/spdy/bidirectional_stream_spdy_impl.h"
xunjieli11834f02015-12-22 04:27:086
7#include "base/bind.h"
8#include "base/location.h"
9#include "base/logging.h"
10#include "base/time/time.h"
11#include "base/timer/timer.h"
12#include "net/http/bidirectional_stream_request_info.h"
13#include "net/spdy/spdy_buffer.h"
14#include "net/spdy/spdy_header_block.h"
15#include "net/spdy/spdy_http_utils.h"
16#include "net/spdy/spdy_stream.h"
17
18namespace net {
19
20namespace {
21
22// Time to wait in millisecond to notify |delegate_| of data received.
23// Handing small chunks of data to the caller creates measurable overhead.
24// So buffer data in short time-spans and send a single read notification.
mefe666e9a2015-12-30 23:41:3025const int kBufferTimeMs = 1;
xunjieli11834f02015-12-22 04:27:0826
27} // namespace
28
xunjieli5749218c2016-03-22 16:43:0629BidirectionalStreamSpdyImpl::BidirectionalStreamSpdyImpl(
xunjieli11834f02015-12-22 04:27:0830 const base::WeakPtr<SpdySession>& spdy_session)
31 : spdy_session_(spdy_session),
32 request_info_(nullptr),
33 delegate_(nullptr),
34 negotiated_protocol_(kProtoUnknown),
35 more_read_data_pending_(false),
36 read_buffer_len_(0),
37 stream_closed_(false),
38 closed_stream_status_(ERR_FAILED),
39 closed_stream_received_bytes_(0),
40 closed_stream_sent_bytes_(0),
41 weak_factory_(this) {}
42
xunjieli5749218c2016-03-22 16:43:0643BidirectionalStreamSpdyImpl::~BidirectionalStreamSpdyImpl() {
xunjieli9ff75c562016-08-10 20:26:1644 // Sends a RST to the remote if the stream is destroyed before it completes.
45 ResetStream();
xunjieli11834f02015-12-22 04:27:0846}
47
xunjieli5749218c2016-03-22 16:43:0648void BidirectionalStreamSpdyImpl::Start(
xunjieli11834f02015-12-22 04:27:0849 const BidirectionalStreamRequestInfo* request_info,
50 const BoundNetLog& net_log,
xunjielibcb0f86e2016-06-03 00:49:2951 bool /*send_request_headers_automatically*/,
xunjieli5749218c2016-03-22 16:43:0652 BidirectionalStreamImpl::Delegate* delegate,
danakjaee3e1ec2016-04-16 00:23:1853 std::unique_ptr<base::Timer> timer) {
xunjieli11834f02015-12-22 04:27:0854 DCHECK(!stream_);
55 DCHECK(timer);
56
57 delegate_ = delegate;
58 timer_ = std::move(timer);
59
60 if (!spdy_session_) {
xunjieli707f8952016-06-06 15:22:0661 base::ThreadTaskRunnerHandle::Get()->PostTask(
62 FROM_HERE,
63 base::Bind(&BidirectionalStreamSpdyImpl::NotifyError,
64 weak_factory_.GetWeakPtr(), ERR_CONNECTION_CLOSED));
xunjieli11834f02015-12-22 04:27:0865 return;
66 }
67
68 request_info_ = request_info;
69
70 int rv = stream_request_.StartRequest(
71 SPDY_BIDIRECTIONAL_STREAM, spdy_session_, request_info_->url,
72 request_info_->priority, net_log,
xunjieli5749218c2016-03-22 16:43:0673 base::Bind(&BidirectionalStreamSpdyImpl::OnStreamInitialized,
xunjieli11834f02015-12-22 04:27:0874 weak_factory_.GetWeakPtr()));
75 if (rv != ERR_IO_PENDING)
76 OnStreamInitialized(rv);
77}
78
xunjielibcb0f86e2016-06-03 00:49:2979void BidirectionalStreamSpdyImpl::SendRequestHeaders() {
80 // Request headers will be sent automatically.
81 NOTREACHED();
82}
83
xunjieli5749218c2016-03-22 16:43:0684int BidirectionalStreamSpdyImpl::ReadData(IOBuffer* buf, int buf_len) {
xunjieli11834f02015-12-22 04:27:0885 if (stream_)
86 DCHECK(!stream_->IsIdle());
87
88 DCHECK(buf);
89 DCHECK(buf_len);
90 DCHECK(!timer_->IsRunning()) << "There should be only one ReadData in flight";
91
92 // If there is data buffered, complete the IO immediately.
93 if (!read_data_queue_.IsEmpty()) {
94 return read_data_queue_.Dequeue(buf->data(), buf_len);
95 } else if (stream_closed_) {
96 return closed_stream_status_;
97 }
98 // Read will complete asynchronously and Delegate::OnReadCompleted will be
99 // called upon completion.
100 read_buffer_ = buf;
101 read_buffer_len_ = buf_len;
102 return ERR_IO_PENDING;
103}
104
xunjieli2328a2682016-05-16 19:38:25105void BidirectionalStreamSpdyImpl::SendData(const scoped_refptr<IOBuffer>& data,
xunjieli5749218c2016-03-22 16:43:06106 int length,
107 bool end_stream) {
xunjieli707f8952016-06-06 15:22:06108 DCHECK(length > 0 || (length == 0 && end_stream));
xunjieli11834f02015-12-22 04:27:08109
xunjieli707f8952016-06-06 15:22:06110 if (!stream_) {
111 LOG(ERROR) << "Trying to send data after stream has been destroyed.";
112 base::ThreadTaskRunnerHandle::Get()->PostTask(
113 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError,
114 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
115 return;
116 }
117
118 DCHECK(!stream_closed_);
xunjieli2328a2682016-05-16 19:38:25119 stream_->SendData(data.get(), length,
xunjieli11834f02015-12-22 04:27:08120 end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND);
121}
122
xunjieli07a42ce2016-04-26 20:05:31123void BidirectionalStreamSpdyImpl::SendvData(
xunjieli2328a2682016-05-16 19:38:25124 const std::vector<scoped_refptr<IOBuffer>>& buffers,
xunjieli07a42ce2016-04-26 20:05:31125 const std::vector<int>& lengths,
126 bool end_stream) {
xunjieli07a42ce2016-04-26 20:05:31127 DCHECK_EQ(buffers.size(), lengths.size());
128
xunjieli707f8952016-06-06 15:22:06129 if (!stream_) {
130 LOG(ERROR) << "Trying to send data after stream has been destroyed.";
131 base::ThreadTaskRunnerHandle::Get()->PostTask(
132 FROM_HERE, base::Bind(&BidirectionalStreamSpdyImpl::NotifyError,
133 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
134 return;
135 }
136
137 DCHECK(!stream_closed_);
xunjieli07a42ce2016-04-26 20:05:31138 int total_len = 0;
139 for (int len : lengths) {
140 total_len += len;
141 }
142
143 pending_combined_buffer_ = new net::IOBuffer(total_len);
144 int len = 0;
145 // TODO(xunjieli): Get rid of extra copy. Coalesce headers and data frames.
146 for (size_t i = 0; i < buffers.size(); ++i) {
147 memcpy(pending_combined_buffer_->data() + len, buffers[i]->data(),
148 lengths[i]);
149 len += lengths[i];
150 }
151 stream_->SendData(pending_combined_buffer_.get(), total_len,
152 end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND);
153}
154
xunjieli5749218c2016-03-22 16:43:06155NextProto BidirectionalStreamSpdyImpl::GetProtocol() const {
xunjieli11834f02015-12-22 04:27:08156 return negotiated_protocol_;
157}
158
xunjieli5749218c2016-03-22 16:43:06159int64_t BidirectionalStreamSpdyImpl::GetTotalReceivedBytes() const {
xunjieli11834f02015-12-22 04:27:08160 if (stream_closed_)
161 return closed_stream_received_bytes_;
162
163 if (!stream_)
164 return 0;
165
166 return stream_->raw_received_bytes();
167}
168
xunjieli5749218c2016-03-22 16:43:06169int64_t BidirectionalStreamSpdyImpl::GetTotalSentBytes() const {
xunjieli11834f02015-12-22 04:27:08170 if (stream_closed_)
171 return closed_stream_sent_bytes_;
172
173 if (!stream_)
174 return 0;
175
176 return stream_->raw_sent_bytes();
177}
178
xunjieliba8de4322016-09-20 21:57:54179bool BidirectionalStreamSpdyImpl::GetLoadTimingInfo(
180 LoadTimingInfo* load_timing_info) const {
181 // TODO(xunjieli): Implement this crbug.com/648346
182 return true;
183}
184
xunjieli5749218c2016-03-22 16:43:06185void BidirectionalStreamSpdyImpl::OnRequestHeadersSent() {
xunjieli11834f02015-12-22 04:27:08186 DCHECK(stream_);
187
bncbca843ba2016-07-14 13:05:48188 negotiated_protocol_ = kProtoHTTP2;
xunjieli707f8952016-06-06 15:22:06189 if (delegate_)
190 delegate_->OnStreamReady(/*request_headers_sent=*/true);
xunjieli11834f02015-12-22 04:27:08191}
192
xunjieli5749218c2016-03-22 16:43:06193SpdyResponseHeadersStatus BidirectionalStreamSpdyImpl::OnResponseHeadersUpdated(
xunjieli11834f02015-12-22 04:27:08194 const SpdyHeaderBlock& response_headers) {
195 DCHECK(stream_);
196
xunjieli707f8952016-06-06 15:22:06197 if (delegate_)
198 delegate_->OnHeadersReceived(response_headers);
199
xunjieli11834f02015-12-22 04:27:08200 return RESPONSE_HEADERS_ARE_COMPLETE;
201}
202
xunjieli5749218c2016-03-22 16:43:06203void BidirectionalStreamSpdyImpl::OnDataReceived(
danakjaee3e1ec2016-04-16 00:23:18204 std::unique_ptr<SpdyBuffer> buffer) {
xunjieli11834f02015-12-22 04:27:08205 DCHECK(stream_);
206 DCHECK(!stream_closed_);
207
xunjieli5749218c2016-03-22 16:43:06208 // If |buffer| is null, BidirectionalStreamSpdyImpl::OnClose will be invoked
209 // by SpdyStream to indicate the end of stream.
xunjieli11834f02015-12-22 04:27:08210 if (!buffer)
211 return;
212
213 // When buffer is consumed, SpdyStream::OnReadBufferConsumed will adjust
214 // recv window size accordingly.
215 read_data_queue_.Enqueue(std::move(buffer));
216 if (read_buffer_) {
217 // Handing small chunks of data to the caller creates measurable overhead.
218 // So buffer data in short time-spans and send a single read notification.
219 ScheduleBufferedRead();
220 }
221}
222
xunjieli5749218c2016-03-22 16:43:06223void BidirectionalStreamSpdyImpl::OnDataSent() {
xunjieli11834f02015-12-22 04:27:08224 DCHECK(stream_);
225 DCHECK(!stream_closed_);
226
xunjielibcb0f86e2016-06-03 00:49:29227 pending_combined_buffer_ = nullptr;
xunjieli707f8952016-06-06 15:22:06228 if (delegate_)
229 delegate_->OnDataSent();
xunjieli11834f02015-12-22 04:27:08230}
231
xunjieli5749218c2016-03-22 16:43:06232void BidirectionalStreamSpdyImpl::OnTrailers(const SpdyHeaderBlock& trailers) {
xunjieli11834f02015-12-22 04:27:08233 DCHECK(stream_);
234 DCHECK(!stream_closed_);
235
xunjieli707f8952016-06-06 15:22:06236 if (delegate_)
237 delegate_->OnTrailersReceived(trailers);
xunjieli11834f02015-12-22 04:27:08238}
239
xunjieli5749218c2016-03-22 16:43:06240void BidirectionalStreamSpdyImpl::OnClose(int status) {
xunjieli11834f02015-12-22 04:27:08241 DCHECK(stream_);
242
243 stream_closed_ = true;
244 closed_stream_status_ = status;
245 closed_stream_received_bytes_ = stream_->raw_received_bytes();
246 closed_stream_sent_bytes_ = stream_->raw_sent_bytes();
xunjieli11834f02015-12-22 04:27:08247
248 if (status != OK) {
xunjieli707f8952016-06-06 15:22:06249 NotifyError(status);
xunjieli11834f02015-12-22 04:27:08250 return;
251 }
xunjieli707f8952016-06-06 15:22:06252 ResetStream();
xunjieli11834f02015-12-22 04:27:08253 // Complete any remaining read, as all data has been buffered.
254 // If user has not called ReadData (i.e |read_buffer_| is nullptr), this will
255 // do nothing.
256 timer_->Stop();
257 DoBufferedRead();
258}
259
xunjielibcb0f86e2016-06-03 00:49:29260int BidirectionalStreamSpdyImpl::SendRequestHeadersHelper() {
bnc1d1d86462016-07-20 16:51:55261 SpdyHeaderBlock headers;
xunjieli11834f02015-12-22 04:27:08262 HttpRequestInfo http_request_info;
263 http_request_info.url = request_info_->url;
264 http_request_info.method = request_info_->method;
265 http_request_info.extra_headers = request_info_->extra_headers;
266
267 CreateSpdyHeadersFromHttpRequest(
bnc1d1d86462016-07-20 16:51:55268 http_request_info, http_request_info.extra_headers, true, &headers);
xunjielibcb0f86e2016-06-03 00:49:29269 return stream_->SendRequestHeaders(std::move(headers),
270 request_info_->end_stream_on_headers
271 ? NO_MORE_DATA_TO_SEND
272 : MORE_DATA_TO_SEND);
xunjieli11834f02015-12-22 04:27:08273}
274
xunjieli5749218c2016-03-22 16:43:06275void BidirectionalStreamSpdyImpl::OnStreamInitialized(int rv) {
xunjieli11834f02015-12-22 04:27:08276 DCHECK_NE(ERR_IO_PENDING, rv);
277 if (rv == OK) {
278 stream_ = stream_request_.ReleaseStream();
279 stream_->SetDelegate(this);
xunjielibcb0f86e2016-06-03 00:49:29280 rv = SendRequestHeadersHelper();
281 if (rv == OK) {
282 OnRequestHeadersSent();
283 return;
284 } else if (rv == ERR_IO_PENDING) {
285 return;
286 }
xunjieli11834f02015-12-22 04:27:08287 }
xunjieli707f8952016-06-06 15:22:06288 NotifyError(rv);
289}
290
291void BidirectionalStreamSpdyImpl::NotifyError(int rv) {
292 ResetStream();
293 if (delegate_) {
294 BidirectionalStreamImpl::Delegate* delegate = delegate_;
295 delegate_ = nullptr;
296 // Cancel any pending callback.
297 weak_factory_.InvalidateWeakPtrs();
298 delegate->OnFailed(rv);
299 // |this| can be null when returned from delegate.
300 }
301}
302
303void BidirectionalStreamSpdyImpl::ResetStream() {
304 if (!stream_)
305 return;
306 if (!stream_->IsClosed()) {
307 // This sends a RST to the remote.
308 stream_->DetachDelegate();
309 DCHECK(!stream_);
310 } else {
311 // Stream is already closed, so it is not legal to call DetachDelegate.
312 stream_.reset();
313 }
xunjieli11834f02015-12-22 04:27:08314}
315
xunjieli5749218c2016-03-22 16:43:06316void BidirectionalStreamSpdyImpl::ScheduleBufferedRead() {
xunjieli11834f02015-12-22 04:27:08317 // If there is already a scheduled DoBufferedRead, don't issue
318 // another one. Mark that we have received more data and return.
319 if (timer_->IsRunning()) {
320 more_read_data_pending_ = true;
321 return;
322 }
323
324 more_read_data_pending_ = false;
325 timer_->Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kBufferTimeMs),
xunjieli5749218c2016-03-22 16:43:06326 base::Bind(&BidirectionalStreamSpdyImpl::DoBufferedRead,
xunjieli11834f02015-12-22 04:27:08327 weak_factory_.GetWeakPtr()));
328}
329
xunjieli5749218c2016-03-22 16:43:06330void BidirectionalStreamSpdyImpl::DoBufferedRead() {
xunjieli11834f02015-12-22 04:27:08331 DCHECK(!timer_->IsRunning());
332 // Check to see that the stream has not errored out.
333 DCHECK(stream_ || stream_closed_);
334 DCHECK(!stream_closed_ || closed_stream_status_ == OK);
335
336 // When |more_read_data_pending_| is true, it means that more data has arrived
337 // since started waiting. Wait a little longer and continue to buffer.
338 if (more_read_data_pending_ && ShouldWaitForMoreBufferedData()) {
339 ScheduleBufferedRead();
340 return;
341 }
342
343 int rv = 0;
344 if (read_buffer_) {
345 rv = ReadData(read_buffer_.get(), read_buffer_len_);
346 DCHECK_NE(ERR_IO_PENDING, rv);
347 read_buffer_ = nullptr;
348 read_buffer_len_ = 0;
xunjieli707f8952016-06-06 15:22:06349 if (delegate_)
350 delegate_->OnDataRead(rv);
xunjieli11834f02015-12-22 04:27:08351 }
352}
353
xunjieli5749218c2016-03-22 16:43:06354bool BidirectionalStreamSpdyImpl::ShouldWaitForMoreBufferedData() const {
xunjieli11834f02015-12-22 04:27:08355 if (stream_closed_)
356 return false;
357 DCHECK_GT(read_buffer_len_, 0);
358 return read_data_queue_.GetTotalSize() <
359 static_cast<size_t>(read_buffer_len_);
360}
361
362} // namespace net