OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/spdy_stream.h" | 5 #include "net/spdy/spdy_stream.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/message_loop.h" | |
8 #include "net/http/http_request_info.h" | 9 #include "net/http/http_request_info.h" |
9 #include "net/http/http_response_info.h" | 10 #include "net/http/http_response_info.h" |
10 #include "net/spdy/spdy_session.h" | 11 #include "net/spdy/spdy_session.h" |
11 | 12 |
12 namespace net { | 13 namespace net { |
13 | 14 |
14 SpdyStream::SpdyStream(SpdySession* session, spdy::SpdyStreamId stream_id, | 15 SpdyStream::SpdyStream(SpdySession* session, spdy::SpdyStreamId stream_id, |
15 bool pushed, LoadLog* log) | 16 bool pushed, LoadLog* log) |
16 : stream_id_(stream_id), | 17 : stream_id_(stream_id), |
17 priority_(0), | 18 priority_(0), |
18 pushed_(pushed), | 19 pushed_(pushed), |
19 download_finished_(false), | 20 download_finished_(false), |
20 metrics_(Singleton<BandwidthMetrics>::get()), | 21 metrics_(Singleton<BandwidthMetrics>::get()), |
21 session_(session), | 22 session_(session), |
22 response_(NULL), | 23 response_(NULL), |
23 request_body_stream_(NULL), | 24 request_body_stream_(NULL), |
24 response_complete_(false), | 25 response_complete_(false), |
25 io_state_(STATE_NONE), | 26 io_state_(STATE_NONE), |
26 response_status_(OK), | 27 response_status_(OK), |
27 user_callback_(NULL), | 28 user_callback_(NULL), |
28 user_buffer_(NULL), | 29 user_buffer_(NULL), |
29 user_buffer_len_(0), | 30 user_buffer_len_(0), |
30 cancelled_(false), | 31 cancelled_(false), |
31 load_log_(log), | 32 load_log_(log), |
32 send_bytes_(0), | 33 send_bytes_(0), |
33 recv_bytes_(0), | 34 recv_bytes_(0), |
34 histograms_recorded_(false) {} | 35 histograms_recorded_(false), |
36 buffered_read_callback_pending_(false), | |
37 more_read_data_pending_(false) {} | |
35 | 38 |
36 SpdyStream::~SpdyStream() { | 39 SpdyStream::~SpdyStream() { |
37 DLOG(INFO) << "Deleting SpdyStream for stream " << stream_id_; | 40 DLOG(INFO) << "Deleting SpdyStream for stream " << stream_id_; |
38 | 41 |
39 // TODO(willchan): We're still calling CancelStream() too many times, because | 42 // TODO(willchan): We're still calling CancelStream() too many times, because |
40 // inactive pending/pushed streams will still have stream_id_ set. | 43 // inactive pending/pushed streams will still have stream_id_ set. |
41 if (stream_id_) { | 44 if (stream_id_) { |
42 session_->CancelStream(stream_id_); | 45 session_->CancelStream(stream_id_); |
43 } else if (!response_complete_) { | 46 } else if (!response_complete_) { |
44 NOTREACHED(); | 47 NOTREACHED(); |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
194 | 197 |
195 if (user_callback_) | 198 if (user_callback_) |
196 DoCallback(rv); | 199 DoCallback(rv); |
197 } | 200 } |
198 | 201 |
199 bool SpdyStream::OnDataReceived(const char* data, int length) { | 202 bool SpdyStream::OnDataReceived(const char* data, int length) { |
200 DCHECK_GE(length, 0); | 203 DCHECK_GE(length, 0); |
201 LOG(INFO) << "SpdyStream: Data (" << length << " bytes) received for " | 204 LOG(INFO) << "SpdyStream: Data (" << length << " bytes) received for " |
202 << stream_id_; | 205 << stream_id_; |
203 | 206 |
207 CHECK(!response_complete_); | |
208 | |
204 // If we don't have a response, then the SYN_REPLY did not come through. | 209 // If we don't have a response, then the SYN_REPLY did not come through. |
205 // We cannot pass data up to the caller unless the reply headers have been | 210 // We cannot pass data up to the caller unless the reply headers have been |
206 // received. | 211 // received. |
207 if (!response_->headers) { | 212 if (!response_->headers) { |
208 OnClose(ERR_SYN_REPLY_NOT_RECEIVED); | 213 OnClose(ERR_SYN_REPLY_NOT_RECEIVED); |
209 return false; | 214 return false; |
210 } | 215 } |
211 | 216 |
212 if (length > 0) | |
213 recv_bytes_ += length; | |
214 recv_last_byte_time_ = base::TimeTicks::Now(); | |
215 | |
216 // A zero-length read means that the stream is being closed. | 217 // A zero-length read means that the stream is being closed. |
217 if (!length) { | 218 if (!length) { |
218 metrics_.StopStream(); | 219 metrics_.StopStream(); |
219 download_finished_ = true; | 220 download_finished_ = true; |
221 response_complete_ = true; | |
222 | |
223 // We need to complete any pending buffered read now. | |
224 DoBufferedReadCallback(); | |
225 | |
220 OnClose(net::OK); | 226 OnClose(net::OK); |
221 return true; | 227 return true; |
222 } | 228 } |
223 | 229 |
224 // Track our bandwidth. | 230 // Track our bandwidth. |
225 metrics_.RecordBytes(length); | 231 metrics_.RecordBytes(length); |
232 recv_bytes_ += length; | |
233 recv_last_byte_time_ = base::TimeTicks::Now(); | |
226 | 234 |
227 if (length > 0) { | 235 // Save the received data. |
228 // TODO(mbelshe): If read is pending, we should copy the data straight into | 236 IOBufferWithSize* io_buffer = new IOBufferWithSize(length); |
229 // the read buffer here. For now, we'll queue it always. | 237 memcpy(io_buffer->data(), data, length); |
230 // TODO(mbelshe): We need to have some throttling on this. We shouldn't | 238 response_body_.push_back(io_buffer); |
231 // buffer an infinite amount of data. | |
232 | |
233 IOBufferWithSize* io_buffer = new IOBufferWithSize(length); | |
234 memcpy(io_buffer->data(), data, length); | |
235 | |
236 response_body_.push_back(io_buffer); | |
237 } | |
238 | 239 |
239 // Note that data may be received for a SpdyStream prior to the user calling | 240 // Note that data may be received for a SpdyStream prior to the user calling |
wtc
2010/02/25 20:04:49
Please update this comment. It refers to the test
Mike Belshe
2010/02/25 23:30:17
Done.
| |
240 // ReadResponseBody(), therefore user_callback_ may be NULL. This may often | 241 // ReadResponseBody(), therefore user_callback_ may be NULL. This may often |
241 // happen for server initiated streams. | 242 // happen for server initiated streams. |
242 if (user_callback_) { | 243 if (user_buffer_) |
243 int rv; | 244 ScheduleBufferedReadCallback(); |
244 if (user_buffer_) { | |
245 rv = ReadResponseBody(user_buffer_, user_buffer_len_, user_callback_); | |
246 CHECK(rv != ERR_IO_PENDING); | |
247 user_buffer_ = NULL; | |
248 user_buffer_len_ = 0; | |
249 } else { | |
250 rv = OK; | |
251 } | |
252 DoCallback(rv); | |
253 } | |
254 | 245 |
255 return true; | 246 return true; |
256 } | 247 } |
257 | 248 |
258 void SpdyStream::OnWriteComplete(int status) { | 249 void SpdyStream::OnWriteComplete(int status) { |
259 // TODO(mbelshe): Check for cancellation here. If we're cancelled, we | 250 // TODO(mbelshe): Check for cancellation here. If we're cancelled, we |
260 // should discontinue the DoLoop. | 251 // should discontinue the DoLoop. |
261 | 252 |
262 if (status > 0) | 253 if (status > 0) |
263 send_bytes_ += status; | 254 send_bytes_ += status; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
335 break; | 326 break; |
336 default: | 327 default: |
337 NOTREACHED(); | 328 NOTREACHED(); |
338 break; | 329 break; |
339 } | 330 } |
340 } while (result != ERR_IO_PENDING && io_state_ != STATE_NONE); | 331 } while (result != ERR_IO_PENDING && io_state_ != STATE_NONE); |
341 | 332 |
342 return result; | 333 return result; |
343 } | 334 } |
344 | 335 |
336 void SpdyStream::ScheduleBufferedReadCallback() { | |
337 // If there is already a scheduled DoBufferedReadCallback, don't issue | |
338 // another one. Mark that we have received more data and return. | |
339 if (buffered_read_callback_pending_) { | |
340 more_read_data_pending_ = true; | |
341 return; | |
342 } | |
343 | |
344 more_read_data_pending_ = false; | |
345 buffered_read_callback_pending_ = true; | |
346 const int kBufferTimeMs = 1; | |
347 MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod( | |
348 this, &SpdyStream::DoBufferedReadCallback), kBufferTimeMs); | |
349 } | |
350 | |
351 // Checks to see if we should wait for more buffered data before notifying | |
352 // the caller. Returns true if we should wait, false otherwise. | |
353 bool SpdyStream::ShouldWaitForMoreBufferedData() { | |
willchan no longer on Chromium
2010/02/25 20:47:35
I think this member function can be const
Mike Belshe
2010/02/25 23:30:17
Done.
| |
354 // If the response is complete, there is no point in waiting. | |
355 if (response_complete_) | |
356 return false; | |
357 | |
358 int bytes_buffered = 0; | |
359 std::list<scoped_refptr<IOBufferWithSize> >::iterator it; | |
360 for (it = response_body_.begin(); | |
361 it != response_body_.end() && bytes_buffered < user_buffer_len_; | |
362 ++it) | |
363 bytes_buffered += (*it)->size(); | |
364 | |
365 return bytes_buffered < user_buffer_len_; | |
366 } | |
367 | |
368 void SpdyStream::DoBufferedReadCallback() { | |
369 buffered_read_callback_pending_ = false; | |
370 | |
371 // When more_read_data_pending_ is true, it means that more data has | |
372 // arrived since we started waiting. Wait a little longer and continue | |
373 // to buffer. | |
374 if (more_read_data_pending_ && ShouldWaitForMoreBufferedData()) { | |
375 ScheduleBufferedReadCallback(); | |
376 return; | |
377 } | |
378 | |
379 int rv = 0; | |
380 if (user_buffer_) { | |
381 rv = ReadResponseBody(user_buffer_, user_buffer_len_, user_callback_); | |
382 CHECK(rv != ERR_IO_PENDING); | |
383 user_buffer_ = NULL; | |
384 user_buffer_len_ = 0; | |
385 } | |
386 | |
387 if (user_callback_) | |
388 DoCallback(rv); | |
389 } | |
390 | |
345 void SpdyStream::DoCallback(int rv) { | 391 void SpdyStream::DoCallback(int rv) { |
346 CHECK(rv != ERR_IO_PENDING); | 392 CHECK(rv != ERR_IO_PENDING); |
347 CHECK(user_callback_); | 393 CHECK(user_callback_); |
348 | 394 |
349 // Since Run may result in being called back, clear user_callback_ in advance. | 395 // Since Run may result in being called back, clear user_callback_ in advance. |
350 CompletionCallback* c = user_callback_; | 396 CompletionCallback* c = user_callback_; |
351 user_callback_ = NULL; | 397 user_callback_ = NULL; |
352 c->Run(rv); | 398 c->Run(rv); |
353 } | 399 } |
354 | 400 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
447 UMA_HISTOGRAM_TIMES("Net.SpdyStreamDownloadTime", | 493 UMA_HISTOGRAM_TIMES("Net.SpdyStreamDownloadTime", |
448 recv_last_byte_time_ - recv_first_byte_time_); | 494 recv_last_byte_time_ - recv_first_byte_time_); |
449 UMA_HISTOGRAM_TIMES("Net.SpdyStreamTime", | 495 UMA_HISTOGRAM_TIMES("Net.SpdyStreamTime", |
450 recv_last_byte_time_ - send_time_); | 496 recv_last_byte_time_ - send_time_); |
451 | 497 |
452 UMA_HISTOGRAM_COUNTS("Net.SpdySendBytes", send_bytes_); | 498 UMA_HISTOGRAM_COUNTS("Net.SpdySendBytes", send_bytes_); |
453 UMA_HISTOGRAM_COUNTS("Net.SpdyRecvBytes", recv_bytes_); | 499 UMA_HISTOGRAM_COUNTS("Net.SpdyRecvBytes", recv_bytes_); |
454 } | 500 } |
455 | 501 |
456 } // namespace net | 502 } // namespace net |
OLD | NEW |