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

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

Issue 2915973002: Fix potential crash bug with BidirectionalStreamQuicImpl::SendRequestHeaders (Closed)
Patch Set: Async notification 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.
Ryan Hamilton 2017/06/01 17:10:14 Since this CL no longer notifies the delegate sync
xunjieli 2017/06/01 21:24:02 Acknowledged. If the upcalls (OnClose and OnError)
Ryan Hamilton 2017/06/01 21:43:48 Yeah, either a bool, or an int. TODO added.
103 auto guard = weak_factory_.GetWeakPtr();
104 size_t headers_bytes_sent = stream_->WriteHeaders( 107 size_t headers_bytes_sent = stream_->WriteHeaders(
105 std::move(headers), request_info_->end_stream_on_headers, nullptr); 108 std::move(headers), request_info_->end_stream_on_headers, nullptr);
106 if (!guard.get()) 109 if (!stream_)
107 return; 110 return false;
xunjieli 2017/06/01 21:24:02 Could you add a comment here that NotifyError() wi
Ryan Hamilton 2017/06/01 21:43:48 In both places that this method returns false, a t
111
108 headers_bytes_sent_ += headers_bytes_sent; 112 headers_bytes_sent_ += headers_bytes_sent;
109 has_sent_headers_ = true; 113 has_sent_headers_ = true;
114 return true;
110 } 115 }
111 116
112 int BidirectionalStreamQuicImpl::ReadData(IOBuffer* buffer, int buffer_len) { 117 int BidirectionalStreamQuicImpl::ReadData(IOBuffer* buffer, int buffer_len) {
113 DCHECK(buffer); 118 DCHECK(buffer);
114 DCHECK(buffer_len); 119 DCHECK(buffer_len);
115 120
116 if (!stream_) { 121 if (!stream_) {
117 // If the stream is already closed, there is no body to read. 122 // If the stream is already closed, there is no body to read.
118 return response_status_; 123 return response_status_;
119 } 124 }
(...skipping 30 matching lines...) Expand all
150 return; 155 return;
151 } 156 }
152 157
153 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler; 158 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler;
154 if (!has_sent_headers_) { 159 if (!has_sent_headers_) {
155 DCHECK(!send_request_headers_automatically_); 160 DCHECK(!send_request_headers_automatically_);
156 // Creates a bundler only if there are headers to be sent along with the 161 // Creates a bundler only if there are headers to be sent along with the
157 // single data buffer. 162 // single data buffer.
158 bundler = 163 bundler =
159 session_->CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING); 164 session_->CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING);
160 SendRequestHeaders(); 165 // Sending the request might result in the stream being closed.
166 if (!WriteHeaders())
167 return;
161 } 168 }
162 169
163 QuicStringPiece string_data(data->data(), length); 170 QuicStringPiece string_data(data->data(), length);
164 int rv = stream_->WriteStreamData( 171 int rv = stream_->WriteStreamData(
165 string_data, end_stream, 172 string_data, end_stream,
166 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, 173 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
167 weak_factory_.GetWeakPtr())); 174 weak_factory_.GetWeakPtr()));
168 DCHECK(rv == OK || rv == ERR_IO_PENDING); 175 DCHECK(rv == OK || rv == ERR_IO_PENDING);
169 if (rv == OK) { 176 if (rv == OK) {
170 base::ThreadTaskRunnerHandle::Get()->PostTask( 177 base::ThreadTaskRunnerHandle::Get()->PostTask(
(...skipping 13 matching lines...) Expand all
184 base::ThreadTaskRunnerHandle::Get()->PostTask( 191 base::ThreadTaskRunnerHandle::Get()->PostTask(
185 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError, 192 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
186 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED)); 193 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
187 return; 194 return;
188 } 195 }
189 196
190 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler( 197 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler(
191 session_->CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING)); 198 session_->CreatePacketBundler(QuicConnection::SEND_ACK_IF_PENDING));
192 if (!has_sent_headers_) { 199 if (!has_sent_headers_) {
193 DCHECK(!send_request_headers_automatically_); 200 DCHECK(!send_request_headers_automatically_);
194 SendRequestHeaders(); 201 // Sending the request might result in the stream being closed.
202 if (!WriteHeaders())
203 return;
195 } 204 }
196 205
197 int rv = stream_->WritevStreamData( 206 int rv = stream_->WritevStreamData(
198 buffers, lengths, end_stream, 207 buffers, lengths, end_stream,
199 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, 208 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
200 weak_factory_.GetWeakPtr())); 209 weak_factory_.GetWeakPtr()));
201 210
202 DCHECK(rv == OK || rv == ERR_IO_PENDING); 211 DCHECK(rv == OK || rv == ERR_IO_PENDING);
203 if (rv == OK) { 212 if (rv == OK) {
204 base::ThreadTaskRunnerHandle::Get()->PostTask( 213 base::ThreadTaskRunnerHandle::Get()->PostTask(
(...skipping 30 matching lines...) Expand all
235 load_timing_info->socket_reused = true; 244 load_timing_info->socket_reused = true;
236 } 245 }
237 return true; 246 return true;
238 } 247 }
239 248
240 void BidirectionalStreamQuicImpl::OnClose() { 249 void BidirectionalStreamQuicImpl::OnClose() {
241 DCHECK(stream_); 250 DCHECK(stream_);
242 251
243 if (stream_->connection_error() != QUIC_NO_ERROR || 252 if (stream_->connection_error() != QUIC_NO_ERROR ||
244 stream_->stream_error() != QUIC_STREAM_NO_ERROR) { 253 stream_->stream_error() != QUIC_STREAM_NO_ERROR) {
245 NotifyError(session_->IsCryptoHandshakeConfirmed() 254 OnError(session_->IsCryptoHandshakeConfirmed() ? ERR_QUIC_PROTOCOL_ERROR
246 ? ERR_QUIC_PROTOCOL_ERROR 255 : ERR_QUIC_HANDSHAKE_FAILED);
247 : ERR_QUIC_HANDSHAKE_FAILED);
248 return; 256 return;
249 } 257 }
250 258
251 if (!stream_->fin_sent() || !stream_->fin_received()) { 259 if (!stream_->fin_sent() || !stream_->fin_received()) {
252 // The connection must have been closed by the peer with QUIC_NO_ERROR, 260 // The connection must have been closed by the peer with QUIC_NO_ERROR,
253 // which is improper. 261 // which is improper.
254 NotifyError(ERR_UNEXPECTED); 262 OnError(ERR_UNEXPECTED);
255 return; 263 return;
256 } 264 }
257 265
258 // The connection was closed normally so there is no need to notify 266 // The connection was closed normally so there is no need to notify
259 // the delegate. 267 // the delegate.
260 ResetStream(); 268 ResetStream();
261 } 269 }
262 270
263 void BidirectionalStreamQuicImpl::OnError(int error) { 271 void BidirectionalStreamQuicImpl::OnError(int error) {
264 NotifyError(error); 272 // Avoid reentrancy by notifying the delegate asynchronously.
273 NotifyErrorImpl(error, /*notify_delegate_later*/ true);
265 } 274 }
266 275
267 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) { 276 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) {
268 DCHECK_NE(ERR_IO_PENDING, rv); 277 DCHECK_NE(ERR_IO_PENDING, rv);
269 DCHECK(rv == OK || !stream_); 278 DCHECK(rv == OK || !stream_);
270 if (rv != OK) { 279 if (rv != OK) {
271 NotifyError(rv); 280 NotifyError(rv);
272 return; 281 return;
273 } 282 }
274 283
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 // If the write side is closed, OnFinRead() will call 360 // If the write side is closed, OnFinRead() will call
352 // BidirectionalStreamQuicImpl::OnClose(). 361 // BidirectionalStreamQuicImpl::OnClose().
353 stream_->OnFinRead(); 362 stream_->OnFinRead();
354 } 363 }
355 364
356 if (delegate_) 365 if (delegate_)
357 delegate_->OnDataRead(rv); 366 delegate_->OnDataRead(rv);
358 } 367 }
359 368
360 void BidirectionalStreamQuicImpl::NotifyError(int error) { 369 void BidirectionalStreamQuicImpl::NotifyError(int error) {
370 NotifyErrorImpl(error, /*notify_delegate_later*/ false);
371 }
372
373 void BidirectionalStreamQuicImpl::NotifyErrorImpl(int error,
374 bool notify_delegate_later) {
361 DCHECK_NE(OK, error); 375 DCHECK_NE(OK, error);
362 DCHECK_NE(ERR_IO_PENDING, error); 376 DCHECK_NE(ERR_IO_PENDING, error);
363 377
364 ResetStream(); 378 ResetStream();
365 if (delegate_) { 379 if (delegate_) {
366 response_status_ = error; 380 response_status_ = error;
367 BidirectionalStreamImpl::Delegate* delegate = delegate_; 381 BidirectionalStreamImpl::Delegate* delegate = delegate_;
368 delegate_ = nullptr; 382 delegate_ = nullptr;
369 // Cancel any pending callback. 383 // Cancel any pending callback.
370 weak_factory_.InvalidateWeakPtrs(); 384 weak_factory_.InvalidateWeakPtrs();
371 delegate->OnFailed(error); 385 if (notify_delegate_later) {
372 // |this| might be destroyed at this point. 386 base::ThreadTaskRunnerHandle::Get()->PostTask(
387 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyFailure,
388 weak_factory_.GetWeakPtr(), delegate, error));
389 } else {
390 NotifyFailure(delegate, error);
391 // |this| might be destroyed at this point.
392 }
373 } 393 }
374 } 394 }
375 395
396 void BidirectionalStreamQuicImpl::NotifyFailure(
397 BidirectionalStreamImpl::Delegate* delegate,
398 int error) {
399 delegate->OnFailed(error);
400 // |this| might be destroyed at this point.
401 }
402
376 void BidirectionalStreamQuicImpl::NotifyStreamReady() { 403 void BidirectionalStreamQuicImpl::NotifyStreamReady() {
377 if (send_request_headers_automatically_) { 404 // Sending the request might result in the stream being closed.
378 // Sending the request might result in |this| being deleted. 405 if (send_request_headers_automatically_ && !WriteHeaders())
379 auto guard = weak_factory_.GetWeakPtr(); 406 return;
380 SendRequestHeaders(); 407
381 if (!guard.get())
382 return;
383 }
384 if (delegate_) 408 if (delegate_)
385 delegate_->OnStreamReady(has_sent_headers_); 409 delegate_->OnStreamReady(has_sent_headers_);
386 } 410 }
387 411
388 void BidirectionalStreamQuicImpl::ResetStream() { 412 void BidirectionalStreamQuicImpl::ResetStream() {
389 if (!stream_) 413 if (!stream_)
390 return; 414 return;
391 closed_stream_received_bytes_ = stream_->stream_bytes_read(); 415 closed_stream_received_bytes_ = stream_->stream_bytes_read();
392 closed_stream_sent_bytes_ = stream_->stream_bytes_written(); 416 closed_stream_sent_bytes_ = stream_->stream_bytes_written();
393 closed_is_first_stream_ = stream_->IsFirstStream(); 417 closed_is_first_stream_ = stream_->IsFirstStream();
394 stream_->ClearDelegate(); 418 stream_->ClearDelegate();
395 stream_ = nullptr; 419 stream_ = nullptr;
396 } 420 }
397 421
398 } // namespace net 422 } // 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