Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 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/quic/chromium/bidirectional_stream_quic_impl.h" | 5 #include "net/quic/chromium/bidirectional_stream_quic_impl.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/location.h" | 10 #include "base/location.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/threading/thread_task_runner_handle.h" | 12 #include "base/threading/thread_task_runner_handle.h" |
| 13 #include "base/timer/timer.h" | 13 #include "base/timer/timer.h" |
| 14 #include "net/http/bidirectional_stream_request_info.h" | 14 #include "net/http/bidirectional_stream_request_info.h" |
| 15 #include "net/quic/core/quic_connection.h" | 15 #include "net/quic/core/quic_connection.h" |
| 16 #include "net/quic/platform/api/quic_string_piece.h" | 16 #include "net/quic/platform/api/quic_string_piece.h" |
| 17 #include "net/socket/next_proto.h" | 17 #include "net/socket/next_proto.h" |
| 18 #include "net/spdy/chromium/spdy_http_utils.h" | 18 #include "net/spdy/chromium/spdy_http_utils.h" |
| 19 #include "net/spdy/core/spdy_header_block.h" | 19 #include "net/spdy/core/spdy_header_block.h" |
| 20 | 20 |
| 21 namespace net { | 21 namespace net { |
| 22 | 22 |
| 23 BidirectionalStreamQuicImpl::BidirectionalStreamQuicImpl( | 23 BidirectionalStreamQuicImpl::BidirectionalStreamQuicImpl( |
| 24 const base::WeakPtr<QuicChromiumClientSession>& session) | 24 QuicChromiumClientSession::Handle session) |
| 25 : session_(session), | 25 : session_(session), |
| 26 was_handshake_confirmed_(session->IsCryptoHandshakeConfirmed()), | |
| 27 stream_(nullptr), | 26 stream_(nullptr), |
| 28 request_info_(nullptr), | 27 request_info_(nullptr), |
| 29 delegate_(nullptr), | 28 delegate_(nullptr), |
| 30 response_status_(OK), | 29 response_status_(OK), |
| 31 negotiated_protocol_(kProtoUnknown), | 30 negotiated_protocol_(kProtoUnknown), |
| 32 read_buffer_len_(0), | 31 read_buffer_len_(0), |
| 33 headers_bytes_received_(0), | 32 headers_bytes_received_(0), |
| 34 headers_bytes_sent_(0), | 33 headers_bytes_sent_(0), |
| 35 closed_stream_received_bytes_(0), | 34 closed_stream_received_bytes_(0), |
| 36 closed_stream_sent_bytes_(0), | 35 closed_stream_sent_bytes_(0), |
| 37 closed_is_first_stream_(false), | 36 closed_is_first_stream_(false), |
| 38 has_sent_headers_(false), | 37 has_sent_headers_(false), |
| 39 has_received_headers_(false), | 38 has_received_headers_(false), |
| 40 send_request_headers_automatically_(true), | 39 send_request_headers_automatically_(true), |
| 41 weak_factory_(this) { | 40 weak_factory_(this) {} |
| 42 DCHECK(session_); | |
| 43 session_->AddObserver(this); | |
| 44 } | |
| 45 | 41 |
| 46 BidirectionalStreamQuicImpl::~BidirectionalStreamQuicImpl() { | 42 BidirectionalStreamQuicImpl::~BidirectionalStreamQuicImpl() { |
| 47 if (stream_) { | 43 if (stream_) { |
| 48 delegate_ = nullptr; | 44 delegate_ = nullptr; |
| 49 stream_->Reset(QUIC_STREAM_CANCELLED); | 45 stream_->Reset(QUIC_STREAM_CANCELLED); |
| 50 } | 46 } |
| 51 | |
| 52 if (session_) | |
| 53 session_->RemoveObserver(this); | |
| 54 } | 47 } |
| 55 | 48 |
| 56 void BidirectionalStreamQuicImpl::Start( | 49 void BidirectionalStreamQuicImpl::Start( |
| 57 const BidirectionalStreamRequestInfo* request_info, | 50 const BidirectionalStreamRequestInfo* request_info, |
| 58 const NetLogWithSource& net_log, | 51 const NetLogWithSource& net_log, |
| 59 bool send_request_headers_automatically, | 52 bool send_request_headers_automatically, |
| 60 BidirectionalStreamImpl::Delegate* delegate, | 53 BidirectionalStreamImpl::Delegate* delegate, |
| 61 std::unique_ptr<base::Timer> /* timer */) { | 54 std::unique_ptr<base::Timer> /* timer */) { |
| 62 DCHECK(!stream_); | 55 DCHECK(!stream_); |
| 63 CHECK(delegate); | 56 CHECK(delegate); |
| 64 | 57 |
| 65 send_request_headers_automatically_ = send_request_headers_automatically; | 58 send_request_headers_automatically_ = send_request_headers_automatically; |
| 66 if (!session_) { | 59 if (!session_.IsConnected()) { |
| 67 NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR | 60 NotifyError(session_.IsCryptoHandshakeConfirmed() |
| 68 : ERR_QUIC_HANDSHAKE_FAILED); | 61 ? ERR_QUIC_PROTOCOL_ERROR |
| 62 : ERR_QUIC_HANDSHAKE_FAILED); | |
| 69 return; | 63 return; |
| 70 } | 64 } |
| 71 | 65 |
| 72 delegate_ = delegate; | 66 delegate_ = delegate; |
| 73 request_info_ = request_info; | 67 request_info_ = request_info; |
| 74 | 68 |
| 75 stream_request_ = | 69 stream_request_ = |
| 76 session_->CreateStreamRequest(request_info_->method == "POST"); | 70 session_.CreateStreamRequest(request_info_->method == "POST"); |
| 77 int rv = stream_request_->StartRequest(base::Bind( | 71 int rv = stream_request_->StartRequest(base::Bind( |
|
xunjieli
2017/05/04 16:54:42
Instead of requiring BidiStream/HttpStream to know
Ryan Hamilton
2017/05/04 18:45:53
I hear ya! I spent a bunch of time thinking about
Ryan Hamilton
2017/05/05 03:50:24
Now that we decided to make the handle non-copyabl
| |
| 78 &BidirectionalStreamQuicImpl::OnStreamReady, weak_factory_.GetWeakPtr())); | 72 &BidirectionalStreamQuicImpl::OnStreamReady, weak_factory_.GetWeakPtr())); |
| 79 if (rv == ERR_IO_PENDING) | 73 if (rv == ERR_IO_PENDING) |
| 80 return; | 74 return; |
| 81 | 75 |
| 82 if (rv == OK) { | 76 if (rv == OK) { |
| 83 OnStreamReady(rv); | 77 OnStreamReady(rv); |
| 84 } else if (!was_handshake_confirmed_) { | 78 } else if (!session_.IsCryptoHandshakeConfirmed()) { |
| 85 NotifyError(ERR_QUIC_HANDSHAKE_FAILED); | 79 NotifyError(ERR_QUIC_HANDSHAKE_FAILED); |
| 86 } | 80 } |
| 87 } | 81 } |
| 88 | 82 |
| 89 void BidirectionalStreamQuicImpl::SendRequestHeaders() { | 83 void BidirectionalStreamQuicImpl::SendRequestHeaders() { |
| 90 DCHECK(!has_sent_headers_); | 84 DCHECK(!has_sent_headers_); |
| 91 if (!stream_) { | 85 if (!stream_) { |
| 92 LOG(ERROR) | 86 LOG(ERROR) |
| 93 << "Trying to send request headers after stream has been destroyed."; | 87 << "Trying to send request headers after stream has been destroyed."; |
| 94 base::ThreadTaskRunnerHandle::Get()->PostTask( | 88 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 145 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError, | 139 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError, |
| 146 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); | 140 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); |
| 147 return; | 141 return; |
| 148 } | 142 } |
| 149 | 143 |
| 150 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler; | 144 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler; |
| 151 if (!has_sent_headers_) { | 145 if (!has_sent_headers_) { |
| 152 DCHECK(!send_request_headers_automatically_); | 146 DCHECK(!send_request_headers_automatically_); |
| 153 // Creates a bundler only if there are headers to be sent along with the | 147 // Creates a bundler only if there are headers to be sent along with the |
| 154 // single data buffer. | 148 // single data buffer. |
| 155 bundler.reset(new QuicConnection::ScopedPacketBundler( | 149 bundler = session_.CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING); |
| 156 session_->connection(), QuicConnection::SEND_ACK_IF_PENDING)); | |
| 157 SendRequestHeaders(); | 150 SendRequestHeaders(); |
| 158 } | 151 } |
| 159 | 152 |
| 160 QuicStringPiece string_data(data->data(), length); | 153 QuicStringPiece string_data(data->data(), length); |
| 161 int rv = stream_->WriteStreamData( | 154 int rv = stream_->WriteStreamData( |
| 162 string_data, end_stream, | 155 string_data, end_stream, |
| 163 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, | 156 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, |
| 164 weak_factory_.GetWeakPtr())); | 157 weak_factory_.GetWeakPtr())); |
| 165 DCHECK(rv == OK || rv == ERR_IO_PENDING); | 158 DCHECK(rv == OK || rv == ERR_IO_PENDING); |
| 166 if (rv == OK) { | 159 if (rv == OK) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 177 DCHECK_EQ(buffers.size(), lengths.size()); | 170 DCHECK_EQ(buffers.size(), lengths.size()); |
| 178 | 171 |
| 179 if (!stream_) { | 172 if (!stream_) { |
| 180 LOG(ERROR) << "Trying to send data after stream has been destroyed."; | 173 LOG(ERROR) << "Trying to send data after stream has been destroyed."; |
| 181 base::ThreadTaskRunnerHandle::Get()->PostTask( | 174 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 182 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError, | 175 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError, |
| 183 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); | 176 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); |
| 184 return; | 177 return; |
| 185 } | 178 } |
| 186 | 179 |
| 187 QuicConnection::ScopedPacketBundler bundler( | 180 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler( |
| 188 session_->connection(), QuicConnection::SEND_ACK_IF_PENDING); | 181 session_.CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING)); |
| 189 if (!has_sent_headers_) { | 182 if (!has_sent_headers_) { |
| 190 DCHECK(!send_request_headers_automatically_); | 183 DCHECK(!send_request_headers_automatically_); |
| 191 SendRequestHeaders(); | 184 SendRequestHeaders(); |
| 192 } | 185 } |
| 193 | 186 |
| 194 int rv = stream_->WritevStreamData( | 187 int rv = stream_->WritevStreamData( |
|
xunjieli
2017/05/04 16:54:42
Potential crash?
With OnSessionClosed() removed, i
Ryan Hamilton
2017/05/05 03:50:24
Seems like a potential crash, but as discussed, it
| |
| 195 buffers, lengths, end_stream, | 188 buffers, lengths, end_stream, |
| 196 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, | 189 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, |
| 197 weak_factory_.GetWeakPtr())); | 190 weak_factory_.GetWeakPtr())); |
| 198 | 191 |
| 199 DCHECK(rv == OK || rv == ERR_IO_PENDING); | 192 DCHECK(rv == OK || rv == ERR_IO_PENDING); |
| 200 if (rv == OK) { | 193 if (rv == OK) { |
| 201 base::ThreadTaskRunnerHandle::Get()->PostTask( | 194 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 202 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, | 195 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, |
| 203 weak_factory_.GetWeakPtr(), OK)); | 196 weak_factory_.GetWeakPtr(), OK)); |
| 204 } | 197 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 234 return true; | 227 return true; |
| 235 } | 228 } |
| 236 | 229 |
| 237 void BidirectionalStreamQuicImpl::OnHeadersAvailable( | 230 void BidirectionalStreamQuicImpl::OnHeadersAvailable( |
| 238 const SpdyHeaderBlock& headers, | 231 const SpdyHeaderBlock& headers, |
| 239 size_t frame_len) { | 232 size_t frame_len) { |
| 240 headers_bytes_received_ += frame_len; | 233 headers_bytes_received_ += frame_len; |
| 241 negotiated_protocol_ = kProtoQUIC; | 234 negotiated_protocol_ = kProtoQUIC; |
| 242 if (!has_received_headers_) { | 235 if (!has_received_headers_) { |
| 243 has_received_headers_ = true; | 236 has_received_headers_ = true; |
| 244 connect_timing_ = session_->GetConnectTiming(); | 237 connect_timing_ = session_.GetConnectTiming(); |
| 245 if (delegate_) | 238 if (delegate_) |
| 246 delegate_->OnHeadersReceived(headers); | 239 delegate_->OnHeadersReceived(headers); |
| 247 } else { | 240 } else { |
| 248 if (delegate_) | 241 if (delegate_) |
| 249 delegate_->OnTrailersReceived(headers); | 242 delegate_->OnTrailersReceived(headers); |
| 250 // |this| can be destroyed after this point. | 243 // |this| can be destroyed after this point. |
| 251 } | 244 } |
| 252 } | 245 } |
| 253 | 246 |
| 254 void BidirectionalStreamQuicImpl::OnDataAvailable() { | 247 void BidirectionalStreamQuicImpl::OnDataAvailable() { |
| 255 // Return early if ReadData has not been called. | 248 // Return early if ReadData has not been called. |
| 256 if (!read_buffer_) | 249 if (!read_buffer_) |
| 257 return; | 250 return; |
| 258 | 251 |
| 259 int rv = ReadData(read_buffer_.get(), read_buffer_len_); | 252 int rv = ReadData(read_buffer_.get(), read_buffer_len_); |
| 260 if (rv == ERR_IO_PENDING) { | 253 if (rv == ERR_IO_PENDING) { |
| 261 // Spurrious notification. Wait for the next one. | 254 // Spurrious notification. Wait for the next one. |
| 262 return; | 255 return; |
| 263 } | 256 } |
| 264 read_buffer_ = nullptr; | 257 read_buffer_ = nullptr; |
| 265 read_buffer_len_ = 0; | 258 read_buffer_len_ = 0; |
| 266 if (delegate_) | 259 if (delegate_) |
| 267 delegate_->OnDataRead(rv); | 260 delegate_->OnDataRead(rv); |
| 268 } | 261 } |
| 269 | 262 |
| 270 void BidirectionalStreamQuicImpl::OnClose() { | 263 void BidirectionalStreamQuicImpl::OnClose() { |
| 271 DCHECK(session_); | |
| 272 DCHECK(stream_); | 264 DCHECK(stream_); |
| 273 | 265 |
| 274 if (stream_->connection_error() != QUIC_NO_ERROR || | 266 if (stream_->connection_error() != QUIC_NO_ERROR || |
| 275 stream_->stream_error() != QUIC_STREAM_NO_ERROR) { | 267 stream_->stream_error() != QUIC_STREAM_NO_ERROR) { |
| 276 NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR | 268 NotifyError(session_.IsCryptoHandshakeConfirmed() |
| 277 : ERR_QUIC_HANDSHAKE_FAILED); | 269 ? ERR_QUIC_PROTOCOL_ERROR |
| 270 : ERR_QUIC_HANDSHAKE_FAILED); | |
| 278 return; | 271 return; |
| 279 } | 272 } |
| 280 | 273 |
| 281 if (!stream_->fin_sent() || !stream_->fin_received()) { | 274 if (!stream_->fin_sent() || !stream_->fin_received()) { |
| 282 // The connection must have been closed by the peer with QUIC_NO_ERROR, | 275 // The connection must have been closed by the peer with QUIC_NO_ERROR, |
| 283 // which is improper. | 276 // which is improper. |
| 284 NotifyError(ERR_UNEXPECTED); | 277 NotifyError(ERR_UNEXPECTED); |
| 285 return; | 278 return; |
| 286 } | 279 } |
| 287 | 280 |
| 288 // The connection was closed normally so there is no need to notify | 281 // The connection was closed normally so there is no need to notify |
| 289 // the delegate. | 282 // the delegate. |
| 290 ResetStream(); | 283 ResetStream(); |
| 291 } | 284 } |
| 292 | 285 |
| 293 void BidirectionalStreamQuicImpl::OnError(int error) { | 286 void BidirectionalStreamQuicImpl::OnError(int error) { |
| 294 NotifyError(error); | 287 NotifyError(error); |
| 295 } | 288 } |
| 296 | 289 |
| 297 bool BidirectionalStreamQuicImpl::HasSendHeadersComplete() { | 290 bool BidirectionalStreamQuicImpl::HasSendHeadersComplete() { |
| 298 return has_sent_headers_; | 291 return has_sent_headers_; |
| 299 } | 292 } |
| 300 | 293 |
| 301 void BidirectionalStreamQuicImpl::OnCryptoHandshakeConfirmed() { | |
| 302 was_handshake_confirmed_ = true; | |
| 303 } | |
| 304 | |
| 305 void BidirectionalStreamQuicImpl::OnSuccessfulVersionNegotiation( | |
| 306 const QuicVersion& version) {} | |
| 307 | |
| 308 void BidirectionalStreamQuicImpl::OnSessionClosed( | |
| 309 int error, | |
| 310 bool /*port_migration_detected*/) { | |
| 311 DCHECK_NE(OK, error); | |
| 312 session_.reset(); | |
| 313 NotifyError(error); | |
| 314 } | |
| 315 | |
| 316 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) { | 294 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) { |
| 317 DCHECK_NE(ERR_IO_PENDING, rv); | 295 DCHECK_NE(ERR_IO_PENDING, rv); |
| 318 DCHECK(rv == OK || !stream_); | 296 DCHECK(rv == OK || !stream_); |
| 319 if (rv == OK) { | 297 if (rv == OK) { |
| 320 stream_ = stream_request_->ReleaseStream(); | 298 stream_ = stream_request_->ReleaseStream(); |
| 321 stream_request_.reset(); | 299 stream_request_.reset(); |
| 322 stream_->SetDelegate(this); | 300 stream_->SetDelegate(this); |
| 323 NotifyStreamReady(); | 301 NotifyStreamReady(); |
| 324 } else { | 302 } else { |
| 325 NotifyError(rv); | 303 NotifyError(rv); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 354 | 332 |
| 355 void BidirectionalStreamQuicImpl::NotifyStreamReady() { | 333 void BidirectionalStreamQuicImpl::NotifyStreamReady() { |
| 356 if (send_request_headers_automatically_) { | 334 if (send_request_headers_automatically_) { |
| 357 SendRequestHeaders(); | 335 SendRequestHeaders(); |
| 358 } | 336 } |
| 359 if (delegate_) | 337 if (delegate_) |
| 360 delegate_->OnStreamReady(has_sent_headers_); | 338 delegate_->OnStreamReady(has_sent_headers_); |
| 361 } | 339 } |
| 362 | 340 |
| 363 void BidirectionalStreamQuicImpl::ResetStream() { | 341 void BidirectionalStreamQuicImpl::ResetStream() { |
| 364 if (session_) { | |
| 365 session_->RemoveObserver(this); | |
| 366 session_ = nullptr; | |
| 367 } | |
| 368 | |
| 369 if (!stream_) | 342 if (!stream_) |
| 370 return; | 343 return; |
| 371 closed_stream_received_bytes_ = stream_->stream_bytes_read(); | 344 closed_stream_received_bytes_ = stream_->stream_bytes_read(); |
| 372 closed_stream_sent_bytes_ = stream_->stream_bytes_written(); | 345 closed_stream_sent_bytes_ = stream_->stream_bytes_written(); |
| 373 closed_is_first_stream_ = stream_->IsFirstStream(); | 346 closed_is_first_stream_ = stream_->IsFirstStream(); |
| 374 stream_->SetDelegate(nullptr); | 347 stream_->SetDelegate(nullptr); |
| 375 stream_ = nullptr; | 348 stream_ = nullptr; |
| 376 } | 349 } |
| 377 | 350 |
| 378 } // namespace net | 351 } // namespace net |
| OLD | NEW |