| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/spdy/bidirectional_stream_spdy_impl.h" | 5 #include "net/spdy/bidirectional_stream_spdy_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/location.h" | 8 #include "base/location.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/time/time.h" | 10 #include "base/time/time.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 : spdy_session_(spdy_session), | 31 : spdy_session_(spdy_session), |
| 32 request_info_(nullptr), | 32 request_info_(nullptr), |
| 33 delegate_(nullptr), | 33 delegate_(nullptr), |
| 34 negotiated_protocol_(kProtoUnknown), | 34 negotiated_protocol_(kProtoUnknown), |
| 35 more_read_data_pending_(false), | 35 more_read_data_pending_(false), |
| 36 read_buffer_len_(0), | 36 read_buffer_len_(0), |
| 37 stream_closed_(false), | 37 stream_closed_(false), |
| 38 closed_stream_status_(ERR_FAILED), | 38 closed_stream_status_(ERR_FAILED), |
| 39 closed_stream_received_bytes_(0), | 39 closed_stream_received_bytes_(0), |
| 40 closed_stream_sent_bytes_(0), | 40 closed_stream_sent_bytes_(0), |
| 41 disable_auto_flush_(false), | |
| 42 weak_factory_(this) {} | 41 weak_factory_(this) {} |
| 43 | 42 |
| 44 BidirectionalStreamSpdyImpl::~BidirectionalStreamSpdyImpl() { | 43 BidirectionalStreamSpdyImpl::~BidirectionalStreamSpdyImpl() { |
| 45 if (stream_) { | 44 if (stream_) { |
| 46 stream_->DetachDelegate(); | 45 stream_->DetachDelegate(); |
| 47 DCHECK(!stream_); | 46 DCHECK(!stream_); |
| 48 } | 47 } |
| 49 } | 48 } |
| 50 | 49 |
| 51 void BidirectionalStreamSpdyImpl::Start( | 50 void BidirectionalStreamSpdyImpl::Start( |
| 52 const BidirectionalStreamRequestInfo* request_info, | 51 const BidirectionalStreamRequestInfo* request_info, |
| 53 const BoundNetLog& net_log, | 52 const BoundNetLog& net_log, |
| 54 bool disable_auto_flush, | 53 bool /*send_request_headers_automatically*/, |
| 55 BidirectionalStreamImpl::Delegate* delegate, | 54 BidirectionalStreamImpl::Delegate* delegate, |
| 56 std::unique_ptr<base::Timer> timer) { | 55 std::unique_ptr<base::Timer> timer) { |
| 57 DCHECK(!stream_); | 56 DCHECK(!stream_); |
| 58 DCHECK(timer); | 57 DCHECK(timer); |
| 59 | 58 |
| 60 disable_auto_flush_ = disable_auto_flush; | |
| 61 delegate_ = delegate; | 59 delegate_ = delegate; |
| 62 timer_ = std::move(timer); | 60 timer_ = std::move(timer); |
| 63 | 61 |
| 64 if (!spdy_session_) { | 62 if (!spdy_session_) { |
| 65 delegate_->OnFailed(ERR_CONNECTION_CLOSED); | 63 delegate_->OnFailed(ERR_CONNECTION_CLOSED); |
| 66 return; | 64 return; |
| 67 } | 65 } |
| 68 | 66 |
| 69 request_info_ = request_info; | 67 request_info_ = request_info; |
| 70 | 68 |
| 71 int rv = stream_request_.StartRequest( | 69 int rv = stream_request_.StartRequest( |
| 72 SPDY_BIDIRECTIONAL_STREAM, spdy_session_, request_info_->url, | 70 SPDY_BIDIRECTIONAL_STREAM, spdy_session_, request_info_->url, |
| 73 request_info_->priority, net_log, | 71 request_info_->priority, net_log, |
| 74 base::Bind(&BidirectionalStreamSpdyImpl::OnStreamInitialized, | 72 base::Bind(&BidirectionalStreamSpdyImpl::OnStreamInitialized, |
| 75 weak_factory_.GetWeakPtr())); | 73 weak_factory_.GetWeakPtr())); |
| 76 if (rv != ERR_IO_PENDING) | 74 if (rv != ERR_IO_PENDING) |
| 77 OnStreamInitialized(rv); | 75 OnStreamInitialized(rv); |
| 78 } | 76 } |
| 79 | 77 |
| 78 void BidirectionalStreamSpdyImpl::SendRequestHeaders() { |
| 79 // Request headers will be sent automatically. |
| 80 NOTREACHED(); |
| 81 } |
| 82 |
| 80 int BidirectionalStreamSpdyImpl::ReadData(IOBuffer* buf, int buf_len) { | 83 int BidirectionalStreamSpdyImpl::ReadData(IOBuffer* buf, int buf_len) { |
| 81 if (stream_) | 84 if (stream_) |
| 82 DCHECK(!stream_->IsIdle()); | 85 DCHECK(!stream_->IsIdle()); |
| 83 | 86 |
| 84 DCHECK(buf); | 87 DCHECK(buf); |
| 85 DCHECK(buf_len); | 88 DCHECK(buf_len); |
| 86 DCHECK(!timer_->IsRunning()) << "There should be only one ReadData in flight"; | 89 DCHECK(!timer_->IsRunning()) << "There should be only one ReadData in flight"; |
| 87 | 90 |
| 88 // If there is data buffered, complete the IO immediately. | 91 // If there is data buffered, complete the IO immediately. |
| 89 if (!read_data_queue_.IsEmpty()) { | 92 if (!read_data_queue_.IsEmpty()) { |
| 90 return read_data_queue_.Dequeue(buf->data(), buf_len); | 93 return read_data_queue_.Dequeue(buf->data(), buf_len); |
| 91 } else if (stream_closed_) { | 94 } else if (stream_closed_) { |
| 92 return closed_stream_status_; | 95 return closed_stream_status_; |
| 93 } | 96 } |
| 94 // Read will complete asynchronously and Delegate::OnReadCompleted will be | 97 // Read will complete asynchronously and Delegate::OnReadCompleted will be |
| 95 // called upon completion. | 98 // called upon completion. |
| 96 read_buffer_ = buf; | 99 read_buffer_ = buf; |
| 97 read_buffer_len_ = buf_len; | 100 read_buffer_len_ = buf_len; |
| 98 return ERR_IO_PENDING; | 101 return ERR_IO_PENDING; |
| 99 } | 102 } |
| 100 | 103 |
| 101 void BidirectionalStreamSpdyImpl::SendData(const scoped_refptr<IOBuffer>& data, | 104 void BidirectionalStreamSpdyImpl::SendData(const scoped_refptr<IOBuffer>& data, |
| 102 int length, | 105 int length, |
| 103 bool end_stream) { | 106 bool end_stream) { |
| 104 DCHECK(!stream_closed_); | 107 DCHECK(!stream_closed_); |
| 105 DCHECK(stream_); | 108 DCHECK(stream_); |
| 106 DCHECK(!disable_auto_flush_); | |
| 107 | 109 |
| 108 stream_->SendData(data.get(), length, | 110 stream_->SendData(data.get(), length, |
| 109 end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND); | 111 end_stream ? NO_MORE_DATA_TO_SEND : MORE_DATA_TO_SEND); |
| 110 } | 112 } |
| 111 | 113 |
| 112 void BidirectionalStreamSpdyImpl::SendvData( | 114 void BidirectionalStreamSpdyImpl::SendvData( |
| 113 const std::vector<scoped_refptr<IOBuffer>>& buffers, | 115 const std::vector<scoped_refptr<IOBuffer>>& buffers, |
| 114 const std::vector<int>& lengths, | 116 const std::vector<int>& lengths, |
| 115 bool end_stream) { | 117 bool end_stream) { |
| 116 DCHECK(!stream_closed_); | 118 DCHECK(!stream_closed_); |
| 117 DCHECK(stream_); | 119 DCHECK(stream_); |
| 118 DCHECK(disable_auto_flush_); | |
| 119 DCHECK_EQ(buffers.size(), lengths.size()); | 120 DCHECK_EQ(buffers.size(), lengths.size()); |
| 120 | 121 |
| 121 int total_len = 0; | 122 int total_len = 0; |
| 122 for (int len : lengths) { | 123 for (int len : lengths) { |
| 123 total_len += len; | 124 total_len += len; |
| 124 } | 125 } |
| 125 | 126 |
| 126 pending_combined_buffer_ = new net::IOBuffer(total_len); | 127 pending_combined_buffer_ = new net::IOBuffer(total_len); |
| 127 int len = 0; | 128 int len = 0; |
| 128 // TODO(xunjieli): Get rid of extra copy. Coalesce headers and data frames. | 129 // TODO(xunjieli): Get rid of extra copy. Coalesce headers and data frames. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 if (!stream_) | 165 if (!stream_) |
| 165 return 0; | 166 return 0; |
| 166 | 167 |
| 167 return stream_->raw_sent_bytes(); | 168 return stream_->raw_sent_bytes(); |
| 168 } | 169 } |
| 169 | 170 |
| 170 void BidirectionalStreamSpdyImpl::OnRequestHeadersSent() { | 171 void BidirectionalStreamSpdyImpl::OnRequestHeadersSent() { |
| 171 DCHECK(stream_); | 172 DCHECK(stream_); |
| 172 | 173 |
| 173 negotiated_protocol_ = stream_->GetProtocol(); | 174 negotiated_protocol_ = stream_->GetProtocol(); |
| 175 delegate_->OnStreamReady(/*request_headers_sent=*/true); |
| 174 } | 176 } |
| 175 | 177 |
| 176 SpdyResponseHeadersStatus BidirectionalStreamSpdyImpl::OnResponseHeadersUpdated( | 178 SpdyResponseHeadersStatus BidirectionalStreamSpdyImpl::OnResponseHeadersUpdated( |
| 177 const SpdyHeaderBlock& response_headers) { | 179 const SpdyHeaderBlock& response_headers) { |
| 178 DCHECK(stream_); | 180 DCHECK(stream_); |
| 179 | 181 |
| 180 delegate_->OnHeadersReceived(response_headers); | 182 delegate_->OnHeadersReceived(response_headers); |
| 181 return RESPONSE_HEADERS_ARE_COMPLETE; | 183 return RESPONSE_HEADERS_ARE_COMPLETE; |
| 182 } | 184 } |
| 183 | 185 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 198 // Handing small chunks of data to the caller creates measurable overhead. | 200 // Handing small chunks of data to the caller creates measurable overhead. |
| 199 // So buffer data in short time-spans and send a single read notification. | 201 // So buffer data in short time-spans and send a single read notification. |
| 200 ScheduleBufferedRead(); | 202 ScheduleBufferedRead(); |
| 201 } | 203 } |
| 202 } | 204 } |
| 203 | 205 |
| 204 void BidirectionalStreamSpdyImpl::OnDataSent() { | 206 void BidirectionalStreamSpdyImpl::OnDataSent() { |
| 205 DCHECK(stream_); | 207 DCHECK(stream_); |
| 206 DCHECK(!stream_closed_); | 208 DCHECK(!stream_closed_); |
| 207 | 209 |
| 208 if (disable_auto_flush_) { | 210 pending_combined_buffer_ = nullptr; |
| 209 DCHECK(pending_combined_buffer_); | |
| 210 pending_combined_buffer_ = nullptr; | |
| 211 } | |
| 212 delegate_->OnDataSent(); | 211 delegate_->OnDataSent(); |
| 213 } | 212 } |
| 214 | 213 |
| 215 void BidirectionalStreamSpdyImpl::OnTrailers(const SpdyHeaderBlock& trailers) { | 214 void BidirectionalStreamSpdyImpl::OnTrailers(const SpdyHeaderBlock& trailers) { |
| 216 DCHECK(stream_); | 215 DCHECK(stream_); |
| 217 DCHECK(!stream_closed_); | 216 DCHECK(!stream_closed_); |
| 218 | 217 |
| 219 delegate_->OnTrailersReceived(trailers); | 218 delegate_->OnTrailersReceived(trailers); |
| 220 } | 219 } |
| 221 | 220 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 232 delegate_->OnFailed(status); | 231 delegate_->OnFailed(status); |
| 233 return; | 232 return; |
| 234 } | 233 } |
| 235 // Complete any remaining read, as all data has been buffered. | 234 // Complete any remaining read, as all data has been buffered. |
| 236 // If user has not called ReadData (i.e |read_buffer_| is nullptr), this will | 235 // If user has not called ReadData (i.e |read_buffer_| is nullptr), this will |
| 237 // do nothing. | 236 // do nothing. |
| 238 timer_->Stop(); | 237 timer_->Stop(); |
| 239 DoBufferedRead(); | 238 DoBufferedRead(); |
| 240 } | 239 } |
| 241 | 240 |
| 242 void BidirectionalStreamSpdyImpl::SendRequestHeaders() { | 241 int BidirectionalStreamSpdyImpl::SendRequestHeadersHelper() { |
| 243 std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock); | 242 std::unique_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock); |
| 244 HttpRequestInfo http_request_info; | 243 HttpRequestInfo http_request_info; |
| 245 http_request_info.url = request_info_->url; | 244 http_request_info.url = request_info_->url; |
| 246 http_request_info.method = request_info_->method; | 245 http_request_info.method = request_info_->method; |
| 247 http_request_info.extra_headers = request_info_->extra_headers; | 246 http_request_info.extra_headers = request_info_->extra_headers; |
| 248 | 247 |
| 249 CreateSpdyHeadersFromHttpRequest( | 248 CreateSpdyHeadersFromHttpRequest( |
| 250 http_request_info, http_request_info.extra_headers, | 249 http_request_info, http_request_info.extra_headers, |
| 251 stream_->GetProtocolVersion(), true, headers.get()); | 250 stream_->GetProtocolVersion(), true, headers.get()); |
| 252 stream_->SendRequestHeaders(std::move(headers), | 251 return stream_->SendRequestHeaders(std::move(headers), |
| 253 request_info_->end_stream_on_headers | 252 request_info_->end_stream_on_headers |
| 254 ? NO_MORE_DATA_TO_SEND | 253 ? NO_MORE_DATA_TO_SEND |
| 255 : MORE_DATA_TO_SEND); | 254 : MORE_DATA_TO_SEND); |
| 256 } | 255 } |
| 257 | 256 |
| 258 void BidirectionalStreamSpdyImpl::OnStreamInitialized(int rv) { | 257 void BidirectionalStreamSpdyImpl::OnStreamInitialized(int rv) { |
| 259 DCHECK_NE(ERR_IO_PENDING, rv); | 258 DCHECK_NE(ERR_IO_PENDING, rv); |
| 260 if (rv == OK) { | 259 if (rv == OK) { |
| 261 stream_ = stream_request_.ReleaseStream(); | 260 stream_ = stream_request_.ReleaseStream(); |
| 262 stream_->SetDelegate(this); | 261 stream_->SetDelegate(this); |
| 263 SendRequestHeaders(); | 262 rv = SendRequestHeadersHelper(); |
| 264 delegate_->OnStreamReady(); | 263 if (rv == OK) { |
| 265 return; | 264 OnRequestHeadersSent(); |
| 265 return; |
| 266 } else if (rv == ERR_IO_PENDING) { |
| 267 return; |
| 268 } |
| 266 } | 269 } |
| 267 delegate_->OnFailed(rv); | 270 delegate_->OnFailed(rv); |
| 268 } | 271 } |
| 269 | 272 |
| 270 void BidirectionalStreamSpdyImpl::ScheduleBufferedRead() { | 273 void BidirectionalStreamSpdyImpl::ScheduleBufferedRead() { |
| 271 // If there is already a scheduled DoBufferedRead, don't issue | 274 // If there is already a scheduled DoBufferedRead, don't issue |
| 272 // another one. Mark that we have received more data and return. | 275 // another one. Mark that we have received more data and return. |
| 273 if (timer_->IsRunning()) { | 276 if (timer_->IsRunning()) { |
| 274 more_read_data_pending_ = true; | 277 more_read_data_pending_ = true; |
| 275 return; | 278 return; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 306 | 309 |
| 307 bool BidirectionalStreamSpdyImpl::ShouldWaitForMoreBufferedData() const { | 310 bool BidirectionalStreamSpdyImpl::ShouldWaitForMoreBufferedData() const { |
| 308 if (stream_closed_) | 311 if (stream_closed_) |
| 309 return false; | 312 return false; |
| 310 DCHECK_GT(read_buffer_len_, 0); | 313 DCHECK_GT(read_buffer_len_, 0); |
| 311 return read_data_queue_.GetTotalSize() < | 314 return read_data_queue_.GetTotalSize() < |
| 312 static_cast<size_t>(read_buffer_len_); | 315 static_cast<size_t>(read_buffer_len_); |
| 313 } | 316 } |
| 314 | 317 |
| 315 } // namespace net | 318 } // namespace net |
| OLD | NEW |