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 "base/message_loop.h" |
9 #include "base/singleton.h" | 9 #include "base/singleton.h" |
10 #include "net/spdy/spdy_session.h" | 10 #include "net/spdy/spdy_session.h" |
11 | 11 |
12 namespace net { | 12 namespace net { |
13 | 13 |
14 SpdyStream::SpdyStream( | 14 SpdyStream::SpdyStream( |
15 SpdySession* session, spdy::SpdyStreamId stream_id, bool pushed) | 15 SpdySession* session, spdy::SpdyStreamId stream_id, bool pushed) |
16 : stream_id_(stream_id), | 16 : continue_buffering_data_(true), |
| 17 stream_id_(stream_id), |
17 priority_(0), | 18 priority_(0), |
18 send_window_size_(spdy::kInitialWindowSize), | 19 send_window_size_(spdy::kInitialWindowSize), |
19 pushed_(pushed), | 20 pushed_(pushed), |
20 metrics_(Singleton<BandwidthMetrics>::get()), | 21 metrics_(Singleton<BandwidthMetrics>::get()), |
21 syn_reply_received_(false), | 22 syn_reply_received_(false), |
22 session_(session), | 23 session_(session), |
23 delegate_(NULL), | 24 delegate_(NULL), |
24 request_time_(base::Time::Now()), | 25 request_time_(base::Time::Now()), |
25 response_(new spdy::SpdyHeaderBlock), | 26 response_(new spdy::SpdyHeaderBlock), |
26 response_complete_(false), | 27 response_complete_(false), |
27 io_state_(STATE_NONE), | 28 io_state_(STATE_NONE), |
28 response_status_(OK), | 29 response_status_(OK), |
29 cancelled_(false), | 30 cancelled_(false), |
30 send_bytes_(0), | 31 send_bytes_(0), |
31 recv_bytes_(0), | 32 recv_bytes_(0), |
32 histograms_recorded_(false) {} | 33 histograms_recorded_(false) {} |
33 | 34 |
34 SpdyStream::~SpdyStream() { | 35 SpdyStream::~SpdyStream() { |
35 DLOG(INFO) << "Deleting SpdyStream for stream " << stream_id_; | 36 DLOG(INFO) << "Deleting SpdyStream for stream " << stream_id_; |
36 } | 37 } |
37 | 38 |
38 void SpdyStream::SetDelegate(Delegate* delegate) { | 39 void SpdyStream::SetDelegate(Delegate* delegate) { |
39 CHECK(delegate); | 40 CHECK(delegate); |
40 delegate_ = delegate; | 41 delegate_ = delegate; |
41 | 42 |
42 if (!response_->empty()) { | 43 if (pushed_) { |
43 // The stream already got response. | 44 CHECK(!response_->empty()); |
44 delegate_->OnResponseReceived(*response_, response_time_, OK); | 45 MessageLoop::current()->PostTask( |
| 46 FROM_HERE, NewRunnableMethod(this, |
| 47 &SpdyStream::PushedStreamReplayData)); |
| 48 } else { |
| 49 continue_buffering_data_ = false; |
45 } | 50 } |
| 51 } |
46 | 52 |
| 53 void SpdyStream::PushedStreamReplayData() { |
| 54 if (cancelled_ || delegate_ == NULL) |
| 55 return; |
| 56 |
| 57 delegate_->OnResponseReceived(*response_, response_time_, OK); |
| 58 |
| 59 continue_buffering_data_ = false; |
47 std::vector<scoped_refptr<IOBufferWithSize> > buffers; | 60 std::vector<scoped_refptr<IOBufferWithSize> > buffers; |
48 buffers.swap(pending_buffers_); | 61 buffers.swap(pending_buffers_); |
49 for (size_t i = 0; i < buffers.size(); ++i) { | 62 for (size_t i = 0; i < buffers.size(); ++i) { |
50 if (delegate_) | 63 if (delegate_){ |
51 delegate_->OnDataReceived(buffers[i]->data(), buffers[i]->size()); | 64 if (buffers[i]) |
| 65 delegate_->OnDataReceived(buffers[i]->data(), buffers[i]->size()); |
| 66 else |
| 67 delegate_->OnDataReceived(NULL, 0); |
| 68 } |
52 } | 69 } |
53 } | 70 } |
54 | 71 |
55 void SpdyStream::DetachDelegate() { | 72 void SpdyStream::DetachDelegate() { |
56 delegate_ = NULL; | 73 delegate_ = NULL; |
57 if (!response_complete_) | 74 if (!response_complete_) |
58 Cancel(); | 75 Cancel(); |
59 } | 76 } |
60 | 77 |
61 const linked_ptr<spdy::SpdyHeaderBlock>& SpdyStream::spdy_headers() const { | 78 const linked_ptr<spdy::SpdyHeaderBlock>& SpdyStream::spdy_headers() const { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 DCHECK(response_->empty()); | 141 DCHECK(response_->empty()); |
125 *response_ = response; // TODO(ukai): avoid copy. | 142 *response_ = response; // TODO(ukai): avoid copy. |
126 | 143 |
127 recv_first_byte_time_ = base::TimeTicks::Now(); | 144 recv_first_byte_time_ = base::TimeTicks::Now(); |
128 response_time_ = base::Time::Now(); | 145 response_time_ = base::Time::Now(); |
129 | 146 |
130 if (io_state_ == STATE_NONE) { | 147 if (io_state_ == STATE_NONE) { |
131 CHECK(pushed_); | 148 CHECK(pushed_); |
132 io_state_ = STATE_READ_HEADERS; | 149 io_state_ = STATE_READ_HEADERS; |
133 } else if (io_state_ == STATE_READ_HEADERS_COMPLETE) { | 150 } else if (io_state_ == STATE_READ_HEADERS_COMPLETE) { |
134 // This SpdyStream could be in this state in both true and false pushed_ | 151 CHECK(!pushed_); |
135 // conditions. | |
136 // The false pushed_ condition (client request) will always go through | |
137 // this state. | |
138 // The true pushed_condition (server push) can be in this state when the | |
139 // client requests an X-Associated-Content piece of content prior | |
140 // to when the server push happens. | |
141 } else { | 152 } else { |
142 // We're not expecting a response while in this state. Error! | 153 // We're not expecting a response while in this state. Error! |
143 rv = ERR_SPDY_PROTOCOL_ERROR; | 154 rv = ERR_SPDY_PROTOCOL_ERROR; |
144 } | 155 } |
145 | 156 |
146 rv = DoLoop(rv); | 157 rv = DoLoop(rv); |
147 if (delegate_) | 158 if (delegate_) |
148 rv = delegate_->OnResponseReceived(*response_, response_time_, rv); | 159 rv = delegate_->OnResponseReceived(*response_, response_time_, rv); |
149 // if delegate_ is not yet attached, we'll return response when delegate | 160 // If delegate_ is not yet attached, we'll call OnResponseReceived after the |
150 // gets attached to the stream. | 161 // delegate gets attached to the stream. |
151 | 162 |
152 return rv; | 163 return rv; |
153 } | 164 } |
154 | 165 |
155 void SpdyStream::OnDataReceived(const char* data, int length) { | 166 void SpdyStream::OnDataReceived(const char* data, int length) { |
156 DCHECK_GE(length, 0); | 167 DCHECK_GE(length, 0); |
157 LOG(INFO) << "SpdyStream: Data (" << length << " bytes) received for " | 168 LOG(INFO) << "SpdyStream: Data (" << length << " bytes) received for " |
158 << stream_id_; | 169 << stream_id_; |
159 | 170 |
160 CHECK(!response_complete_); | 171 if (!delegate_ || continue_buffering_data_) { |
| 172 // It should be valid for this to happen in the server push case. |
| 173 // We'll return received data when delegate gets attached to the stream. |
| 174 if (length > 0) { |
| 175 IOBufferWithSize* buf = new IOBufferWithSize(length); |
| 176 memcpy(buf->data(), data, length); |
| 177 pending_buffers_.push_back(buf); |
| 178 } |
| 179 else |
| 180 pending_buffers_.push_back(NULL); |
| 181 return; |
| 182 } |
| 183 |
| 184 CHECK(!response_complete_); |
161 | 185 |
162 // If we don't have a response, then the SYN_REPLY did not come through. | 186 // If we don't have a response, then the SYN_REPLY did not come through. |
163 // We cannot pass data up to the caller unless the reply headers have been | 187 // We cannot pass data up to the caller unless the reply headers have been |
164 // received. | 188 // received. |
165 if (response_->empty()) { | 189 if (response_->empty()) { |
166 session_->CloseStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED); | 190 session_->CloseStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED); |
167 return; | 191 return; |
168 } | 192 } |
169 | 193 |
170 // A zero-length read means that the stream is being closed. | 194 // A zero-length read means that the stream is being closed. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 return result; | 265 return result; |
242 } | 266 } |
243 | 267 |
244 send_time_ = base::TimeTicks::Now(); | 268 send_time_ = base::TimeTicks::Now(); |
245 | 269 |
246 int result = OK; | 270 int result = OK; |
247 if (!pushed_) { | 271 if (!pushed_) { |
248 DCHECK_EQ(io_state_, STATE_NONE); | 272 DCHECK_EQ(io_state_, STATE_NONE); |
249 io_state_ = STATE_SEND_HEADERS; | 273 io_state_ = STATE_SEND_HEADERS; |
250 } else { | 274 } else { |
| 275 // Pushed stream should not have upload data. |
251 DCHECK(!has_upload_data); | 276 DCHECK(!has_upload_data); |
252 if (!response_->empty()) { | 277 DCHECK(!response_->empty()); |
253 // We already have response headers, so we don't need to read the header. | 278 DCHECK_EQ(io_state_, STATE_OPEN); |
254 // Pushed stream should not have upload data. | 279 return ERR_IO_PENDING; |
255 // We don't need to call DoLoop() in this state. | |
256 DCHECK_EQ(io_state_, STATE_OPEN); | |
257 return OK; | |
258 } else { | |
259 io_state_ = STATE_READ_HEADERS; | |
260 } | |
261 } | 280 } |
262 return DoLoop(result); | 281 return DoLoop(result); |
263 } | 282 } |
264 | 283 |
265 int SpdyStream::DoReadResponseHeaders() { | 284 int SpdyStream::DoReadResponseHeaders() { |
266 CHECK(!cancelled_); | 285 CHECK(!cancelled_); |
267 | 286 |
268 // The SYN_REPLY has already been received. | 287 // The SYN_REPLY has already been received. |
269 if (!response_->empty()) { | 288 if (!response_->empty()) { |
270 CHECK_EQ(STATE_OPEN, io_state_); | 289 CHECK_EQ(STATE_OPEN, io_state_); |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 UMA_HISTOGRAM_TIMES("Net.SpdyStreamDownloadTime", | 466 UMA_HISTOGRAM_TIMES("Net.SpdyStreamDownloadTime", |
448 recv_last_byte_time_ - recv_first_byte_time_); | 467 recv_last_byte_time_ - recv_first_byte_time_); |
449 UMA_HISTOGRAM_TIMES("Net.SpdyStreamTime", | 468 UMA_HISTOGRAM_TIMES("Net.SpdyStreamTime", |
450 recv_last_byte_time_ - send_time_); | 469 recv_last_byte_time_ - send_time_); |
451 | 470 |
452 UMA_HISTOGRAM_COUNTS("Net.SpdySendBytes", send_bytes_); | 471 UMA_HISTOGRAM_COUNTS("Net.SpdySendBytes", send_bytes_); |
453 UMA_HISTOGRAM_COUNTS("Net.SpdyRecvBytes", recv_bytes_); | 472 UMA_HISTOGRAM_COUNTS("Net.SpdyRecvBytes", recv_bytes_); |
454 } | 473 } |
455 | 474 |
456 } // namespace net | 475 } // namespace net |
OLD | NEW |