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

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

Issue 2032733002: Do not crash on null stream in writing to bidirectional streams (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@fix_crash
Patch Set: Address Andrei's comments round 2 Created 4 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
« no previous file with comments | « net/net.gypi ('k') | net/quic/bidirectional_stream_quic_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/bidirectional_stream_quic_impl.h" 5 #include "net/quic/bidirectional_stream_quic_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/timer/timer.h" 10 #include "base/timer/timer.h"
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 session_->RemoveObserver(this); 44 session_->RemoveObserver(this);
45 } 45 }
46 46
47 void BidirectionalStreamQuicImpl::Start( 47 void BidirectionalStreamQuicImpl::Start(
48 const BidirectionalStreamRequestInfo* request_info, 48 const BidirectionalStreamRequestInfo* request_info,
49 const BoundNetLog& net_log, 49 const BoundNetLog& net_log,
50 bool send_request_headers_automatically, 50 bool send_request_headers_automatically,
51 BidirectionalStreamImpl::Delegate* delegate, 51 BidirectionalStreamImpl::Delegate* delegate,
52 std::unique_ptr<base::Timer> /* timer */) { 52 std::unique_ptr<base::Timer> /* timer */) {
53 DCHECK(!stream_); 53 DCHECK(!stream_);
54 CHECK(delegate);
54 55
55 send_request_headers_automatically_ = send_request_headers_automatically; 56 send_request_headers_automatically_ = send_request_headers_automatically;
56 if (!session_) { 57 if (!session_) {
57 NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR 58 NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR
58 : ERR_QUIC_HANDSHAKE_FAILED); 59 : ERR_QUIC_HANDSHAKE_FAILED);
59 return; 60 return;
60 } 61 }
61 62
62 delegate_ = delegate; 63 delegate_ = delegate;
63 request_info_ = request_info; 64 request_info_ = request_info;
64 65
65 int rv = stream_request_.StartRequest( 66 int rv = stream_request_.StartRequest(
66 session_, &stream_, 67 session_, &stream_,
67 base::Bind(&BidirectionalStreamQuicImpl::OnStreamReady, 68 base::Bind(&BidirectionalStreamQuicImpl::OnStreamReady,
68 weak_factory_.GetWeakPtr())); 69 weak_factory_.GetWeakPtr()));
69 if (rv == OK) { 70 if (rv == OK) {
70 OnStreamReady(rv); 71 OnStreamReady(rv);
71 } else if (!was_handshake_confirmed_) { 72 } else if (!was_handshake_confirmed_) {
72 NotifyError(ERR_QUIC_HANDSHAKE_FAILED); 73 NotifyError(ERR_QUIC_HANDSHAKE_FAILED);
73 } 74 }
74 } 75 }
75 76
76 void BidirectionalStreamQuicImpl::SendRequestHeaders() { 77 void BidirectionalStreamQuicImpl::SendRequestHeaders() {
77 DCHECK(!has_sent_headers_); 78 DCHECK(!has_sent_headers_);
78 DCHECK(stream_); 79 if (!stream_) {
80 LOG(ERROR)
81 << "Trying to send request headers after stream has been destroyed.";
82 base::ThreadTaskRunnerHandle::Get()->PostTask(
83 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
84 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
85 return;
86 }
79 87
80 SpdyHeaderBlock headers; 88 SpdyHeaderBlock headers;
81 HttpRequestInfo http_request_info; 89 HttpRequestInfo http_request_info;
82 http_request_info.url = request_info_->url; 90 http_request_info.url = request_info_->url;
83 http_request_info.method = request_info_->method; 91 http_request_info.method = request_info_->method;
84 http_request_info.extra_headers = request_info_->extra_headers; 92 http_request_info.extra_headers = request_info_->extra_headers;
85 93
86 CreateSpdyHeadersFromHttpRequest(http_request_info, 94 CreateSpdyHeadersFromHttpRequest(http_request_info,
87 http_request_info.extra_headers, HTTP2, true, 95 http_request_info.extra_headers, HTTP2, true,
88 &headers); 96 &headers);
(...skipping 23 matching lines...) Expand all
112 // Read will complete asynchronously and Delegate::OnReadCompleted will be 120 // Read will complete asynchronously and Delegate::OnReadCompleted will be
113 // called upon completion. 121 // called upon completion.
114 read_buffer_ = buffer; 122 read_buffer_ = buffer;
115 read_buffer_len_ = buffer_len; 123 read_buffer_len_ = buffer_len;
116 return ERR_IO_PENDING; 124 return ERR_IO_PENDING;
117 } 125 }
118 126
119 void BidirectionalStreamQuicImpl::SendData(const scoped_refptr<IOBuffer>& data, 127 void BidirectionalStreamQuicImpl::SendData(const scoped_refptr<IOBuffer>& data,
120 int length, 128 int length,
121 bool end_stream) { 129 bool end_stream) {
122 DCHECK(stream_);
123 DCHECK(length > 0 || (length == 0 && end_stream)); 130 DCHECK(length > 0 || (length == 0 && end_stream));
131 if (!stream_) {
132 LOG(ERROR) << "Trying to send data after stream has been destroyed.";
133 base::ThreadTaskRunnerHandle::Get()->PostTask(
134 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
135 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
136 return;
137 }
124 138
125 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler; 139 std::unique_ptr<QuicConnection::ScopedPacketBundler> bundler;
126 if (!has_sent_headers_) { 140 if (!has_sent_headers_) {
127 DCHECK(!send_request_headers_automatically_); 141 DCHECK(!send_request_headers_automatically_);
128 // Creates a bundler only if there are headers to be sent along with the 142 // Creates a bundler only if there are headers to be sent along with the
129 // single data buffer. 143 // single data buffer.
130 bundler.reset(new QuicConnection::ScopedPacketBundler( 144 bundler.reset(new QuicConnection::ScopedPacketBundler(
131 session_->connection(), QuicConnection::SEND_ACK_IF_PENDING)); 145 session_->connection(), QuicConnection::SEND_ACK_IF_PENDING));
132 SendRequestHeaders(); 146 SendRequestHeaders();
133 } 147 }
134 148
135 base::StringPiece string_data(data->data(), length); 149 base::StringPiece string_data(data->data(), length);
136 int rv = stream_->WriteStreamData( 150 int rv = stream_->WriteStreamData(
137 string_data, end_stream, 151 string_data, end_stream,
138 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, 152 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
139 weak_factory_.GetWeakPtr())); 153 weak_factory_.GetWeakPtr()));
140 DCHECK(rv == OK || rv == ERR_IO_PENDING); 154 DCHECK(rv == OK || rv == ERR_IO_PENDING);
141 if (rv == OK) { 155 if (rv == OK) {
142 base::ThreadTaskRunnerHandle::Get()->PostTask( 156 base::ThreadTaskRunnerHandle::Get()->PostTask(
143 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, 157 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
144 weak_factory_.GetWeakPtr(), OK)); 158 weak_factory_.GetWeakPtr(), OK));
145 } 159 }
146 } 160 }
147 161
148 void BidirectionalStreamQuicImpl::SendvData( 162 void BidirectionalStreamQuicImpl::SendvData(
149 const std::vector<scoped_refptr<IOBuffer>>& buffers, 163 const std::vector<scoped_refptr<IOBuffer>>& buffers,
150 const std::vector<int>& lengths, 164 const std::vector<int>& lengths,
151 bool end_stream) { 165 bool end_stream) {
152 DCHECK(stream_);
153 DCHECK_EQ(buffers.size(), lengths.size()); 166 DCHECK_EQ(buffers.size(), lengths.size());
154 167
168 if (!stream_) {
169 LOG(ERROR) << "Trying to send data after stream has been destroyed.";
170 base::ThreadTaskRunnerHandle::Get()->PostTask(
171 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::NotifyError,
172 weak_factory_.GetWeakPtr(), ERR_UNEXPECTED));
173 return;
174 }
175
155 QuicConnection::ScopedPacketBundler bundler( 176 QuicConnection::ScopedPacketBundler bundler(
156 session_->connection(), QuicConnection::SEND_ACK_IF_PENDING); 177 session_->connection(), QuicConnection::SEND_ACK_IF_PENDING);
157 if (!has_sent_headers_) { 178 if (!has_sent_headers_) {
158 DCHECK(!send_request_headers_automatically_); 179 DCHECK(!send_request_headers_automatically_);
159 SendRequestHeaders(); 180 SendRequestHeaders();
160 } 181 }
161 182
162 int rv = stream_->WritevStreamData( 183 int rv = stream_->WritevStreamData(
163 buffers, lengths, end_stream, 184 buffers, lengths, end_stream,
164 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, 185 base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
165 weak_factory_.GetWeakPtr())); 186 weak_factory_.GetWeakPtr()));
166 187
167 DCHECK(rv == OK || rv == ERR_IO_PENDING); 188 DCHECK(rv == OK || rv == ERR_IO_PENDING);
168 if (rv == OK) { 189 if (rv == OK) {
169 base::ThreadTaskRunnerHandle::Get()->PostTask( 190 base::ThreadTaskRunnerHandle::Get()->PostTask(
170 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete, 191 FROM_HERE, base::Bind(&BidirectionalStreamQuicImpl::OnSendDataComplete,
171 weak_factory_.GetWeakPtr(), OK)); 192 weak_factory_.GetWeakPtr(), OK));
172 } 193 }
173 } 194 }
174 195
175 void BidirectionalStreamQuicImpl::Cancel() { 196 void BidirectionalStreamQuicImpl::Cancel() {
197 if (delegate_) {
198 delegate_ = nullptr;
199 // Cancel any pending callbacks.
200 weak_factory_.InvalidateWeakPtrs();
201 }
176 if (stream_) { 202 if (stream_) {
177 stream_->SetDelegate(nullptr);
178 stream_->Reset(QUIC_STREAM_CANCELLED); 203 stream_->Reset(QUIC_STREAM_CANCELLED);
179 ResetStream(); 204 ResetStream();
180 } 205 }
181 } 206 }
182 207
183 NextProto BidirectionalStreamQuicImpl::GetProtocol() const { 208 NextProto BidirectionalStreamQuicImpl::GetProtocol() const {
184 return negotiated_protocol_; 209 return negotiated_protocol_;
185 } 210 }
186 211
187 int64_t BidirectionalStreamQuicImpl::GetTotalReceivedBytes() const { 212 int64_t BidirectionalStreamQuicImpl::GetTotalReceivedBytes() const {
188 if (stream_) 213 if (stream_)
189 return headers_bytes_received_ + stream_->stream_bytes_read(); 214 return headers_bytes_received_ + stream_->stream_bytes_read();
190 return headers_bytes_received_ + closed_stream_received_bytes_; 215 return headers_bytes_received_ + closed_stream_received_bytes_;
191 } 216 }
192 217
193 int64_t BidirectionalStreamQuicImpl::GetTotalSentBytes() const { 218 int64_t BidirectionalStreamQuicImpl::GetTotalSentBytes() const {
194 if (stream_) 219 if (stream_)
195 return headers_bytes_sent_ + stream_->stream_bytes_written(); 220 return headers_bytes_sent_ + stream_->stream_bytes_written();
196 return headers_bytes_sent_ + closed_stream_sent_bytes_; 221 return headers_bytes_sent_ + closed_stream_sent_bytes_;
197 } 222 }
198 223
199 void BidirectionalStreamQuicImpl::OnHeadersAvailable( 224 void BidirectionalStreamQuicImpl::OnHeadersAvailable(
200 const SpdyHeaderBlock& headers, 225 const SpdyHeaderBlock& headers,
201 size_t frame_len) { 226 size_t frame_len) {
202 headers_bytes_received_ += frame_len; 227 headers_bytes_received_ += frame_len;
203 negotiated_protocol_ = kProtoQUIC1SPDY3; 228 negotiated_protocol_ = kProtoQUIC1SPDY3;
204 if (!has_received_headers_) { 229 if (!has_received_headers_) {
205 has_received_headers_ = true; 230 has_received_headers_ = true;
206 delegate_->OnHeadersReceived(headers); 231 if (delegate_)
232 delegate_->OnHeadersReceived(headers);
207 } else { 233 } else {
208 if (stream_->IsDoneReading()) { 234 if (stream_->IsDoneReading()) {
209 // If the write side is closed, OnFinRead() will call 235 // If the write side is closed, OnFinRead() will call
210 // BidirectionalStreamQuicImpl::OnClose(). 236 // BidirectionalStreamQuicImpl::OnClose().
211 stream_->OnFinRead(); 237 stream_->OnFinRead();
212 } 238 }
213 delegate_->OnTrailersReceived(headers); 239 if (delegate_)
240 delegate_->OnTrailersReceived(headers);
214 } 241 }
215 } 242 }
216 243
217 void BidirectionalStreamQuicImpl::OnDataAvailable() { 244 void BidirectionalStreamQuicImpl::OnDataAvailable() {
218 // Return early if ReadData has not been called. 245 // Return early if ReadData has not been called.
219 if (!read_buffer_) 246 if (!read_buffer_)
220 return; 247 return;
221 248
222 CHECK(read_buffer_); 249 CHECK(read_buffer_);
223 CHECK_NE(0, read_buffer_len_); 250 CHECK_NE(0, read_buffer_len_);
224 int rv = ReadData(read_buffer_.get(), read_buffer_len_); 251 int rv = ReadData(read_buffer_.get(), read_buffer_len_);
225 if (rv == ERR_IO_PENDING) { 252 if (rv == ERR_IO_PENDING) {
226 // Spurrious notification. Wait for the next one. 253 // Spurrious notification. Wait for the next one.
227 return; 254 return;
228 } 255 }
229 read_buffer_ = nullptr; 256 read_buffer_ = nullptr;
230 read_buffer_len_ = 0; 257 read_buffer_len_ = 0;
231 delegate_->OnDataRead(rv); 258 if (delegate_)
259 delegate_->OnDataRead(rv);
232 } 260 }
233 261
234 void BidirectionalStreamQuicImpl::OnClose(QuicErrorCode error) { 262 void BidirectionalStreamQuicImpl::OnClose(QuicErrorCode error) {
235 DCHECK(stream_); 263 DCHECK(stream_);
264
236 if (error == QUIC_NO_ERROR && 265 if (error == QUIC_NO_ERROR &&
237 stream_->stream_error() == QUIC_STREAM_NO_ERROR) { 266 stream_->stream_error() == QUIC_STREAM_NO_ERROR) {
238 ResetStream(); 267 ResetStream();
239 return; 268 return;
240 } 269 }
241 ResetStream();
242 NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR 270 NotifyError(was_handshake_confirmed_ ? ERR_QUIC_PROTOCOL_ERROR
243 : ERR_QUIC_HANDSHAKE_FAILED); 271 : ERR_QUIC_HANDSHAKE_FAILED);
244 } 272 }
245 273
246 void BidirectionalStreamQuicImpl::OnError(int error) { 274 void BidirectionalStreamQuicImpl::OnError(int error) {
247 NotifyError(error); 275 NotifyError(error);
248 } 276 }
249 277
250 bool BidirectionalStreamQuicImpl::HasSendHeadersComplete() { 278 bool BidirectionalStreamQuicImpl::HasSendHeadersComplete() {
251 return has_sent_headers_; 279 return has_sent_headers_;
(...skipping 12 matching lines...) Expand all
264 } 292 }
265 293
266 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) { 294 void BidirectionalStreamQuicImpl::OnStreamReady(int rv) {
267 DCHECK_NE(ERR_IO_PENDING, rv); 295 DCHECK_NE(ERR_IO_PENDING, rv);
268 DCHECK(rv == OK || !stream_); 296 DCHECK(rv == OK || !stream_);
269 if (rv == OK) { 297 if (rv == OK) {
270 stream_->SetDelegate(this); 298 stream_->SetDelegate(this);
271 if (send_request_headers_automatically_) { 299 if (send_request_headers_automatically_) {
272 SendRequestHeaders(); 300 SendRequestHeaders();
273 } 301 }
274 delegate_->OnStreamReady(has_sent_headers_); 302 if (delegate_)
303 delegate_->OnStreamReady(has_sent_headers_);
275 } else { 304 } else {
276 NotifyError(rv); 305 NotifyError(rv);
277 } 306 }
278 } 307 }
279 308
280 void BidirectionalStreamQuicImpl::OnSendDataComplete(int rv) { 309 void BidirectionalStreamQuicImpl::OnSendDataComplete(int rv) {
281 DCHECK(rv == OK || !stream_); 310 DCHECK(rv == OK || !stream_);
282 if (rv == OK) { 311 if (rv == OK) {
283 delegate_->OnDataSent(); 312 if (delegate_)
313 delegate_->OnDataSent();
284 } else { 314 } else {
285 NotifyError(rv); 315 NotifyError(rv);
286 } 316 }
287 } 317 }
288 318
289 void BidirectionalStreamQuicImpl::NotifyError(int error) { 319 void BidirectionalStreamQuicImpl::NotifyError(int error) {
290 DCHECK_NE(OK, error); 320 DCHECK_NE(OK, error);
291 DCHECK_NE(ERR_IO_PENDING, error); 321 DCHECK_NE(ERR_IO_PENDING, error);
292 322
293 response_status_ = error;
294 ResetStream(); 323 ResetStream();
295 delegate_->OnFailed(error); 324 if (delegate_) {
325 response_status_ = error;
326 BidirectionalStreamImpl::Delegate* delegate = delegate_;
327 delegate_ = nullptr;
328 // Cancel any pending callback.
329 weak_factory_.InvalidateWeakPtrs();
330 delegate->OnFailed(error);
331 // |this| might be destroyed at this point.
332 }
296 } 333 }
297 334
298 void BidirectionalStreamQuicImpl::ResetStream() { 335 void BidirectionalStreamQuicImpl::ResetStream() {
299 if (!stream_) 336 if (!stream_)
300 return; 337 return;
301 closed_stream_received_bytes_ = stream_->stream_bytes_read(); 338 closed_stream_received_bytes_ = stream_->stream_bytes_read();
302 closed_stream_sent_bytes_ = stream_->stream_bytes_written(); 339 closed_stream_sent_bytes_ = stream_->stream_bytes_written();
303 stream_->SetDelegate(nullptr); 340 stream_->SetDelegate(nullptr);
304 stream_ = nullptr; 341 stream_ = nullptr;
305 } 342 }
306 343
307 } // namespace net 344 } // namespace net
OLDNEW
« no previous file with comments | « net/net.gypi ('k') | net/quic/bidirectional_stream_quic_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698