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

Side by Side Diff: net/quic/chromium/bidirectional_stream_quic_impl.cc

Issue 2915973002: Fix potential crash bug with BidirectionalStreamQuicImpl::SendRequestHeaders (Closed)
Patch Set: More comments Created 3 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
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"
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 session_->IsCryptoHandshakeConfirmed() 74 session_->IsCryptoHandshakeConfirmed()
75 ? rv 75 ? rv
76 : ERR_QUIC_HANDSHAKE_FAILED)); 76 : ERR_QUIC_HANDSHAKE_FAILED));
77 return; 77 return;
78 } 78 }
79 79
80 OnStreamReady(rv); 80 OnStreamReady(rv);
81 } 81 }
82 82
83 void BidirectionalStreamQuicImpl::SendRequestHeaders() { 83 void BidirectionalStreamQuicImpl::SendRequestHeaders() {
84 WriteHeaders();
85 }
86
87 bool BidirectionalStreamQuicImpl::WriteHeaders() {
84 DCHECK(!has_sent_headers_); 88 DCHECK(!has_sent_headers_);
85 if (!stream_) { 89 if (!stream_) {
86 LOG(ERROR) 90 LOG(ERROR)
87 << "Trying to send request headers after stream has been destroyed."; 91 << "Trying to send request headers after stream has been destroyed.";
88 base::ThreadTaskRunnerHandle::Get()->PostTask( 92 base::ThreadTaskRunnerHandle::Get()->PostTask(
89 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError, 93 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
90 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); 94 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
91 return; 95 return false;
92 } 96 }
93 97
94 SpdyHeaderBlock headers; 98 SpdyHeaderBlock headers;
95 HttpRequestInfo http_request_info; 99 HttpRequestInfo http_request_info;
96 http_request_info.url = request_info_->url; 100 http_request_info.url = request_info_->url;
97 http_request_info.method = request_info_->method; 101 http_request_info.method = request_info_->method;
98 http_request_info.extra_headers = request_info_->extra_headers; 102 http_request_info.extra_headers = request_info_->extra_headers;
99 103
100 CreateSpdyHeadersFromHttpRequest( 104 CreateSpdyHeadersFromHttpRequest(
101 http_request_info, http_request_info.extra_headers, true, &headers); 105 http_request_info, http_request_info.extra_headers, true, &headers);
102 // Sending the request might result in |this| being deleted. 106 // Sending the request might result in the stream being closed via OnClose
103 auto guard = weak_factory_.GetWeakPtr(); 107 // which will post a task to notify the delegate asynchronously.
108 // TODO(rch): Clean up this interface when OnClose and OnError are removed.
104 size_t headers_bytes_sent = stream_->WriteHeaders( 109 size_t headers_bytes_sent = stream_->WriteHeaders(
105 std::move(headers), request_info_->end_stream_on_headers, nullptr); 110 std::move(headers), request_info_->end_stream_on_headers, nullptr);
106 if (!guard.get()) 111 if (!stream_)
107 return; 112 return false;
113
108 headers_bytes_sent_ += headers_bytes_sent; 114 headers_bytes_sent_ += headers_bytes_sent;
109 has_sent_headers_ = true; 115 has_sent_headers_ = true;
116 return true;
110 } 117 }
111 118
112 int BidirectionalStreamQuicImpl::ReadData(IOBuffer* buffer, int buffer_len) { 119 int BidirectionalStreamQuicImpl::ReadData(IOBuffer* buffer, int buffer_len) {
113 DCHECK(buffer); 120 DCHECK(buffer);
114 DCHECK(buffer_len); 121 DCHECK(buffer_len);
115 122
116 if (!stream_) { 123 if (!stream_) {
117 // If the stream is already closed, there is no body to read. 124 // If the stream is already closed, there is no body to read.
118 return response_status_; 125 return response_status_;
119 } 126 }
(...skipping 30 matching lines...) Expand all
150 return; 157 return;
151 } 158 }
152 159
153 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler; 160 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler;
154 if (!has_sent_headers_) { 161 if (!has_sent_headers_) {
155 DCHECK(!send_request_headers_automatically_); 162 DCHECK(!send_request_headers_automatically_);
156 // Creates a bundler only if there are headers to be sent along with the 163 // Creates a bundler only if there are headers to be sent along with the
157 // single data buffer. 164 // single data buffer.
158 bundler = 165 bundler =
159 session_->CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING); 166 session_->CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING);
160 SendRequestHeaders(); 167 // Sending the request might result in the stream being closed.
168 if (!WriteHeaders())
169 return;
161 } 170 }
162 171
163 QuicStringPiece string_data(data->data(), length); 172 QuicStringPiece string_data(data->data(), length);
164 int rv = stream_->WriteStreamData( 173 int rv = stream_->WriteStreamData(
165 string_data, end_stream, 174 string_data, end_stream,
166 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, 175 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
167 weak_factory_.GetWeakPtr())); 176 weak_factory_.GetWeakPtr()));
168 DCHECK(rv == OK || rv == ERR_IO_PENDING); 177 DCHECK(rv == OK || rv == ERR_IO_PENDING);
169 if (rv == OK) { 178 if (rv == OK) {
170 base::ThreadTaskRunnerHandle::Get()->PostTask( 179 base::ThreadTaskRunnerHandle::Get()->PostTask(
(...skipping 13 matching lines...) Expand all
184 base::ThreadTaskRunnerHandle::Get()->PostTask( 193 base::ThreadTaskRunnerHandle::Get()->PostTask(
185 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError, 194 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
186 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); 195 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
187 return; 196 return;
188 } 197 }
189 198
190 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler( 199 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler(
191 session_->CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING)); 200 session_->CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING));
192 if (!has_sent_headers_) { 201 if (!has_sent_headers_) {
193 DCHECK(!send_request_headers_automatically_); 202 DCHECK(!send_request_headers_automatically_);
194 SendRequestHeaders(); 203 // Sending the request might result in the stream being closed.
204 if (!WriteHeaders())
205 return;
195 } 206 }
196 207
197 int rv = stream_->WritevStreamData( 208 int rv = stream_->WritevStreamData(
198 buffers, lengths, end_stream, 209 buffers, lengths, end_stream,
199 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, 210 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
200 weak_factory_.GetWeakPtr())); 211 weak_factory_.GetWeakPtr()));
201 212
202 DCHECK(rv == OK || rv == ERR_IO_PENDING); 213 DCHECK(rv == OK || rv == ERR_IO_PENDING);
203 if (rv == OK) { 214 if (rv == OK) {
204 base::ThreadTaskRunnerHandle::Get()->PostTask( 215 base::ThreadTaskRunnerHandle::Get()->PostTask(
(...skipping 30 matching lines...) Expand all
235 load_timing_info->socket_reused = true; 246 load_timing_info->socket_reused = true;
236 } 247 }
237 return true; 248 return true;
238 } 249 }
239 250
240 void BidirectionalStreamQuicImpl::OnClose() { 251 void BidirectionalStreamQuicImpl::OnClose() {
241 DCHECK(stream_); 252 DCHECK(stream_);
242 253
243 if (stream_->connection_error() != QUIC_NO_ERROR || 254 if (stream_->connection_error() != QUIC_NO_ERROR ||
244 stream_->stream_error() != QUIC_STREAM_NO_ERROR) { 255 stream_->stream_error() != QUIC_STREAM_NO_ERROR) {
245 NotifyError(session_->IsCryptoHandshakeConfirmed() 256 OnError(session_->IsCryptoHandshakeConfirmed() ? ERR_QUIC_PROTOCOL_ERROR
246 ? ERR_QUIC_PROTOCOL_ERROR 257 : ERR_QUIC_HANDSHAKE_FAILED);
247 : ERR_QUIC_HANDSHAKE_FAILED);
248 return; 258 return;
249 } 259 }
250 260
251 if (!stream_->fin_sent() || !stream_->fin_received()) { 261 if (!stream_->fin_sent() || !stream_->fin_received()) {
252 // The connection must have been closed by the peer with QUIC_NO_ERROR, 262 // The connection must have been closed by the peer with QUIC_NO_ERROR,
253 // which is improper. 263 // which is improper.
254 NotifyError(ERR_UNEXPECTED); 264 OnError(ERR_UNEXPECTED);
255 return; 265 return;
256 } 266 }
257 267
258 // The connection was closed normally so there is no need to notify 268 // The connection was closed normally so there is no need to notify
259 // the delegate. 269 // the delegate.
260 ResetStream(); 270 ResetStream();
261 } 271 }
262 272
263 void BidirectionalStreamQuicImpl::OnError(int error) { 273 void BidirectionalStreamQuicImpl::OnError(int error) {
264 NotifyError(error); 274 // Avoid reentrancy by notifying the delegate asynchronously.
275 NotifyErrorImpl(error, /*notify_delegate_later*/ true);
265 } 276 }
266 277
267 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) { 278 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) {
268 DCHECK_NE(ERR_IO_PENDING, rv); 279 DCHECK_NE(ERR_IO_PENDING, rv);
269 DCHECK(rv == OK || !stream_); 280 DCHECK(rv == OK || !stream_);
270 if (rv != OK) { 281 if (rv != OK) {
271 NotifyError(rv); 282 NotifyError(rv);
272 return; 283 return;
273 } 284 }
274 285
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 // If the write side is closed, OnFinRead() will call 362 // If the write side is closed, OnFinRead() will call
352 // BidirectionalStreamQuicImpl::OnClose(). 363 // BidirectionalStreamQuicImpl::OnClose().
353 stream_->OnFinRead(); 364 stream_->OnFinRead();
354 } 365 }
355 366
356 if (delegate_) 367 if (delegate_)
357 delegate_->OnDataRead(rv); 368 delegate_->OnDataRead(rv);
358 } 369 }
359 370
360 void BidirectionalStreamQuicImpl::NotifyError(int error) { 371 void BidirectionalStreamQuicImpl::NotifyError(int error) {
372 NotifyErrorImpl(error, /*notify_delegate_later*/ false);
373 }
374
375 void BidirectionalStreamQuicImpl::NotifyErrorImpl(int error,
376 bool notify_delegate_later) {
361 DCHECK_NE(OK, error); 377 DCHECK_NE(OK, error);
362 DCHECK_NE(ERR_IO_PENDING, error); 378 DCHECK_NE(ERR_IO_PENDING, error);
363 379
364 ResetStream(); 380 ResetStream();
365 if (delegate_) { 381 if (delegate_) {
366 response_status_ = error; 382 response_status_ = error;
367 BidirectionalStreamImpl::Delegate* delegate = delegate_; 383 BidirectionalStreamImpl::Delegate* delegate = delegate_;
368 delegate_ = nullptr; 384 delegate_ = nullptr;
369 // Cancel any pending callback. 385 // Cancel any pending callback.
370 weak_factory_.InvalidateWeakPtrs(); 386 weak_factory_.InvalidateWeakPtrs();
371 delegate->OnFailed(error); 387 if (notify_delegate_later) {
372 // |this| might be destroyed at this point. 388 base::ThreadTaskRunnerHandle::Get()->PostTask(
389 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyFailure,
390 weak_factory_.GetWeakPtr(), delegate, error));
391 } else {
392 NotifyFailure(delegate, error);
393 // |this| might be destroyed at this point.
394 }
373 } 395 }
374 } 396 }
375 397
398 void BidirectionalStreamQuicImpl::NotifyFailure(
399 BidirectionalStreamImpl::Delegate* delegate,
400 int error) {
401 delegate->OnFailed(error);
402 // |this| might be destroyed at this point.
403 }
404
376 void BidirectionalStreamQuicImpl::NotifyStreamReady() { 405 void BidirectionalStreamQuicImpl::NotifyStreamReady() {
377 if (send_request_headers_automatically_) { 406 // Sending the request might result in the stream being closed.
378 // Sending the request might result in |this| being deleted. 407 if (send_request_headers_automatically_ && !WriteHeaders())
379 auto guard = weak_factory_.GetWeakPtr(); 408 return;
380 SendRequestHeaders(); 409
381 if (!guard.get())
382 return;
383 }
384 if (delegate_) 410 if (delegate_)
385 delegate_->OnStreamReady(has_sent_headers_); 411 delegate_->OnStreamReady(has_sent_headers_);
386 } 412 }
387 413
388 void BidirectionalStreamQuicImpl::ResetStream() { 414 void BidirectionalStreamQuicImpl::ResetStream() {
389 if (!stream_) 415 if (!stream_)
390 return; 416 return;
391 closed_stream_received_bytes_ = stream_->stream_bytes_read(); 417 closed_stream_received_bytes_ = stream_->stream_bytes_read();
392 closed_stream_sent_bytes_ = stream_->stream_bytes_written(); 418 closed_stream_sent_bytes_ = stream_->stream_bytes_written();
393 closed_is_first_stream_ = stream_->IsFirstStream(); 419 closed_is_first_stream_ = stream_->IsFirstStream();
394 stream_->ClearDelegate(); 420 stream_->ClearDelegate();
395 stream_ = nullptr; 421 stream_ = nullptr;
396 } 422 }
397 423
398 } // namespace net 424 } // namespace net
OLDNEW
« no previous file with comments | « net/quic/chromium/bidirectional_stream_quic_impl.h ('k') | net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698