blob: 5382f6cf4424aac98bde7aaafe5166e55261f353 [file] [log] [blame]
[email protected]95d88ffe2010-02-04 21:25:331// Copyright (c) 2010 The Chromium Authors. All rights reserved.
[email protected]cd314c822009-10-29 03:13:062// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]dab9c7d2010-02-06 21:44:325#include "net/spdy/spdy_stream.h"
[email protected]cd314c822009-10-29 03:13:066
[email protected]a677f2b2009-11-22 00:43:007#include "base/logging.h"
[email protected]79d84222010-02-26 00:01:448#include "base/message_loop.h"
[email protected]a677f2b2009-11-22 00:43:009#include "net/http/http_request_info.h"
[email protected]cd314c822009-10-29 03:13:0610#include "net/http/http_response_info.h"
[email protected]dab9c7d2010-02-06 21:44:3211#include "net/spdy/spdy_session.h"
[email protected]cd314c822009-10-29 03:13:0612
13namespace net {
14
[email protected]955fc2e72010-02-08 20:37:3015SpdyStream::SpdyStream(SpdySession* session, spdy::SpdyStreamId stream_id,
[email protected]9e743cd2010-03-16 07:03:5316 bool pushed, const BoundNetLog& log)
[email protected]a677f2b2009-11-22 00:43:0017 : stream_id_(stream_id),
18 priority_(0),
19 pushed_(pushed),
20 download_finished_(false),
21 metrics_(Singleton<BandwidthMetrics>::get()),
22 session_(session),
[email protected]3f662f12010-03-25 19:56:1223 request_time_(base::Time::Now()),
[email protected]a677f2b2009-11-22 00:43:0024 response_(NULL),
25 request_body_stream_(NULL),
26 response_complete_(false),
27 io_state_(STATE_NONE),
28 response_status_(OK),
29 user_callback_(NULL),
30 user_buffer_(NULL),
31 user_buffer_len_(0),
[email protected]dac358042009-12-18 02:07:4832 cancelled_(false),
[email protected]9e743cd2010-03-16 07:03:5333 net_log_(log),
[email protected]e7f6a5a02009-12-28 01:08:2234 send_bytes_(0),
35 recv_bytes_(0),
[email protected]79d84222010-02-26 00:01:4436 histograms_recorded_(false),
37 buffered_read_callback_pending_(false),
38 more_read_data_pending_(false) {}
[email protected]cd314c822009-10-29 03:13:0639
[email protected]955fc2e72010-02-08 20:37:3040SpdyStream::~SpdyStream() {
41 DLOG(INFO) << "Deleting SpdyStream for stream " << stream_id_;
[email protected]cd314c822009-10-29 03:13:0642
[email protected]a677f2b2009-11-22 00:43:0043 // TODO(willchan): We're still calling CancelStream() too many times, because
44 // inactive pending/pushed streams will still have stream_id_ set.
45 if (stream_id_) {
46 session_->CancelStream(stream_id_);
47 } else if (!response_complete_) {
48 NOTREACHED();
[email protected]cd314c822009-10-29 03:13:0649 }
[email protected]cd314c822009-10-29 03:13:0650}
51
[email protected]955fc2e72010-02-08 20:37:3052uint64 SpdyStream::GetUploadProgress() const {
[email protected]a677f2b2009-11-22 00:43:0053 if (!request_body_stream_.get())
54 return 0;
[email protected]cd314c822009-10-29 03:13:0655
[email protected]a677f2b2009-11-22 00:43:0056 return request_body_stream_->position();
57}
[email protected]cd314c822009-10-29 03:13:0658
[email protected]955fc2e72010-02-08 20:37:3059const HttpResponseInfo* SpdyStream::GetResponseInfo() const {
[email protected]a7e41312009-12-16 23:18:1460 return response_;
[email protected]a677f2b2009-11-22 00:43:0061}
62
[email protected]3f662f12010-03-25 19:56:1263const HttpRequestInfo* SpdyStream::GetRequestInfo() const {
64 return &request_;
65}
66
67void SpdyStream::SetRequestInfo(const HttpRequestInfo& request) {
68 request_ = request;
69}
70
71base::Time SpdyStream::GetRequestTime() const {
72 return request_time_;
73}
74
75void SpdyStream::SetRequestTime(base::Time t) {
76 request_time_ = t;
77
78 // This should only get called in the case of a request occuring
79 // during server push that has already begun but hasn't finished,
80 // so we set the response's request time to be the actual one
81 if (response_)
82 response_->request_time = request_time_;
83}
84
[email protected]955fc2e72010-02-08 20:37:3085int SpdyStream::ReadResponseHeaders(CompletionCallback* callback) {
86 // Note: The SpdyStream may have already received the response headers, so
[email protected]a677f2b2009-11-22 00:43:0087 // this call may complete synchronously.
88 CHECK(callback);
[email protected]b1f031dd2010-03-02 23:19:3389 CHECK_EQ(STATE_NONE, io_state_);
[email protected]a677f2b2009-11-22 00:43:0090 CHECK(!cancelled_);
91
92 // The SYN_REPLY has already been received.
[email protected]a7e41312009-12-16 23:18:1493 if (response_->headers)
[email protected]a677f2b2009-11-22 00:43:0094 return OK;
95
96 io_state_ = STATE_READ_HEADERS;
97 CHECK(!user_callback_);
98 user_callback_ = callback;
99 return ERR_IO_PENDING;
100}
101
[email protected]955fc2e72010-02-08 20:37:30102int SpdyStream::ReadResponseBody(
[email protected]a677f2b2009-11-22 00:43:00103 IOBuffer* buf, int buf_len, CompletionCallback* callback) {
104 DCHECK_EQ(io_state_, STATE_NONE);
105 CHECK(buf);
106 CHECK(buf_len);
107 CHECK(callback);
108 CHECK(!cancelled_);
109
110 // If we have data buffered, complete the IO immediately.
111 if (response_body_.size()) {
112 int bytes_read = 0;
113 while (response_body_.size() && buf_len > 0) {
114 scoped_refptr<IOBufferWithSize> data = response_body_.front();
115 const int bytes_to_copy = std::min(buf_len, data->size());
116 memcpy(&(buf->data()[bytes_read]), data->data(), bytes_to_copy);
117 buf_len -= bytes_to_copy;
118 if (bytes_to_copy == data->size()) {
119 response_body_.pop_front();
120 } else {
121 const int bytes_remaining = data->size() - bytes_to_copy;
122 IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining);
123 memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]),
124 bytes_remaining);
125 response_body_.pop_front();
126 response_body_.push_front(new_buffer);
127 }
128 bytes_read += bytes_to_copy;
129 }
[email protected]e7f6a5a02009-12-28 01:08:22130 if (bytes_read > 0)
131 recv_bytes_ += bytes_read;
[email protected]a677f2b2009-11-22 00:43:00132 return bytes_read;
133 } else if (response_complete_) {
134 return response_status_;
135 }
136
137 CHECK(!user_callback_);
138 CHECK(!user_buffer_);
[email protected]b1f031dd2010-03-02 23:19:33139 CHECK_EQ(0, user_buffer_len_);
[email protected]a677f2b2009-11-22 00:43:00140
141 user_callback_ = callback;
142 user_buffer_ = buf;
143 user_buffer_len_ = buf_len;
144 return ERR_IO_PENDING;
145}
146
[email protected]955fc2e72010-02-08 20:37:30147int SpdyStream::SendRequest(UploadDataStream* upload_data,
[email protected]a7e41312009-12-16 23:18:14148 HttpResponseInfo* response,
[email protected]a677f2b2009-11-22 00:43:00149 CompletionCallback* callback) {
150 CHECK(callback);
151 CHECK(!cancelled_);
[email protected]a7e41312009-12-16 23:18:14152 CHECK(response);
153
[email protected]c8b16742010-02-05 20:49:53154 if (response_) {
155 *response = *response_;
156 delete response_;
157 }
[email protected]a7e41312009-12-16 23:18:14158 response_ = response;
[email protected]a677f2b2009-11-22 00:43:00159
[email protected]0a7bd21a2009-11-24 20:04:01160 if (upload_data) {
161 if (upload_data->size())
162 request_body_stream_.reset(upload_data);
163 else
164 delete upload_data;
165 }
[email protected]a677f2b2009-11-22 00:43:00166
[email protected]e7f6a5a02009-12-28 01:08:22167 send_time_ = base::TimeTicks::Now();
168
[email protected]a677f2b2009-11-22 00:43:00169 DCHECK_EQ(io_state_, STATE_NONE);
170 if (!pushed_)
171 io_state_ = STATE_SEND_HEADERS;
[email protected]c8b16742010-02-05 20:49:53172 else {
173 if (response_->headers) {
174 io_state_ = STATE_READ_BODY;
175 } else {
176 io_state_ = STATE_READ_HEADERS;
177 }
178 }
[email protected]a677f2b2009-11-22 00:43:00179 int result = DoLoop(OK);
180 if (result == ERR_IO_PENDING) {
181 CHECK(!user_callback_);
182 user_callback_ = callback;
183 }
184 return result;
185}
186
[email protected]955fc2e72010-02-08 20:37:30187void SpdyStream::Cancel() {
[email protected]a677f2b2009-11-22 00:43:00188 cancelled_ = true;
189 user_callback_ = NULL;
190
[email protected]92683b52009-12-21 21:01:12191 session_->CancelStream(stream_id_);
[email protected]a677f2b2009-11-22 00:43:00192}
193
[email protected]955fc2e72010-02-08 20:37:30194void SpdyStream::OnResponseReceived(const HttpResponseInfo& response) {
[email protected]cd314c822009-10-29 03:13:06195 metrics_.StartStream();
196
[email protected]a7e41312009-12-16 23:18:14197 CHECK(!response_->headers);
[email protected]cd314c822009-10-29 03:13:06198
[email protected]a677f2b2009-11-22 00:43:00199 *response_ = response; // TODO(mbelshe): avoid copy.
[email protected]a7e41312009-12-16 23:18:14200 DCHECK(response_->headers);
[email protected]a677f2b2009-11-22 00:43:00201
[email protected]e7f6a5a02009-12-28 01:08:22202 recv_first_byte_time_ = base::TimeTicks::Now();
203
[email protected]a677f2b2009-11-22 00:43:00204 if (io_state_ == STATE_NONE) {
205 CHECK(pushed_);
[email protected]c8b16742010-02-05 20:49:53206 io_state_ = STATE_READ_HEADERS;
[email protected]a677f2b2009-11-22 00:43:00207 } else if (io_state_ == STATE_READ_HEADERS_COMPLETE) {
[email protected]955fc2e72010-02-08 20:37:30208 // This SpdyStream could be in this state in both true and false pushed_
[email protected]c8b16742010-02-05 20:49:53209 // conditions.
210 // The false pushed_ condition (client request) will always go through
211 // this state.
212 // The true pushed_condition (server push) can be in this state when the
213 // client requests an X-Associated-Content piece of content prior
214 // to when the server push happens.
[email protected]a677f2b2009-11-22 00:43:00215 } else {
216 NOTREACHED();
[email protected]cd314c822009-10-29 03:13:06217 }
218
[email protected]a677f2b2009-11-22 00:43:00219 int rv = DoLoop(OK);
[email protected]cd314c822009-10-29 03:13:06220
[email protected]a677f2b2009-11-22 00:43:00221 if (user_callback_)
222 DoCallback(rv);
[email protected]cd314c822009-10-29 03:13:06223}
224
[email protected]955fc2e72010-02-08 20:37:30225bool SpdyStream::OnDataReceived(const char* data, int length) {
[email protected]a677f2b2009-11-22 00:43:00226 DCHECK_GE(length, 0);
[email protected]955fc2e72010-02-08 20:37:30227 LOG(INFO) << "SpdyStream: Data (" << length << " bytes) received for "
[email protected]cd314c822009-10-29 03:13:06228 << stream_id_;
229
[email protected]79d84222010-02-26 00:01:44230 CHECK(!response_complete_);
231
[email protected]cd314c822009-10-29 03:13:06232 // If we don't have a response, then the SYN_REPLY did not come through.
233 // We cannot pass data up to the caller unless the reply headers have been
234 // received.
[email protected]a7e41312009-12-16 23:18:14235 if (!response_->headers) {
[email protected]a677f2b2009-11-22 00:43:00236 OnClose(ERR_SYN_REPLY_NOT_RECEIVED);
237 return false;
[email protected]cd314c822009-10-29 03:13:06238 }
239
240 // A zero-length read means that the stream is being closed.
241 if (!length) {
242 metrics_.StopStream();
243 download_finished_ = true;
[email protected]79d84222010-02-26 00:01:44244 response_complete_ = true;
245
246 // We need to complete any pending buffered read now.
247 DoBufferedReadCallback();
248
[email protected]a677f2b2009-11-22 00:43:00249 OnClose(net::OK);
250 return true;
[email protected]cd314c822009-10-29 03:13:06251 }
252
253 // Track our bandwidth.
254 metrics_.RecordBytes(length);
[email protected]79d84222010-02-26 00:01:44255 recv_bytes_ += length;
256 recv_last_byte_time_ = base::TimeTicks::Now();
[email protected]cd314c822009-10-29 03:13:06257
[email protected]79d84222010-02-26 00:01:44258 // Save the received data.
259 IOBufferWithSize* io_buffer = new IOBufferWithSize(length);
260 memcpy(io_buffer->data(), data, length);
261 response_body_.push_back(io_buffer);
[email protected]a677f2b2009-11-22 00:43:00262
[email protected]955fc2e72010-02-08 20:37:30263 // Note that data may be received for a SpdyStream prior to the user calling
[email protected]79d84222010-02-26 00:01:44264 // ReadResponseBody(), therefore user_buffer_ may be NULL. This may often
[email protected]a677f2b2009-11-22 00:43:00265 // happen for server initiated streams.
[email protected]79d84222010-02-26 00:01:44266 if (user_buffer_) {
267 // Handing small chunks of data to the caller creates measurable overhead.
268 // We buffer data in short time-spans and send a single read notification.
269 ScheduleBufferedReadCallback();
[email protected]a677f2b2009-11-22 00:43:00270 }
271
272 return true;
[email protected]cd314c822009-10-29 03:13:06273}
274
[email protected]955fc2e72010-02-08 20:37:30275void SpdyStream::OnWriteComplete(int status) {
[email protected]92683b52009-12-21 21:01:12276 // TODO(mbelshe): Check for cancellation here. If we're cancelled, we
277 // should discontinue the DoLoop.
[email protected]e7f6a5a02009-12-28 01:08:22278
279 if (status > 0)
280 send_bytes_ += status;
281
[email protected]a677f2b2009-11-22 00:43:00282 DoLoop(status);
[email protected]cd314c822009-10-29 03:13:06283}
284
[email protected]955fc2e72010-02-08 20:37:30285void SpdyStream::OnClose(int status) {
[email protected]a677f2b2009-11-22 00:43:00286 response_complete_ = true;
287 response_status_ = status;
288 stream_id_ = 0;
[email protected]ff57bb82009-11-12 06:52:14289
[email protected]a677f2b2009-11-22 00:43:00290 if (user_callback_)
291 DoCallback(status);
[email protected]e7f6a5a02009-12-28 01:08:22292
293 UpdateHistograms();
[email protected]a677f2b2009-11-22 00:43:00294}
[email protected]ff57bb82009-11-12 06:52:14295
[email protected]955fc2e72010-02-08 20:37:30296int SpdyStream::DoLoop(int result) {
[email protected]a677f2b2009-11-22 00:43:00297 do {
298 State state = io_state_;
299 io_state_ = STATE_NONE;
300 switch (state) {
301 // State machine 1: Send headers and wait for response headers.
302 case STATE_SEND_HEADERS:
[email protected]b1f031dd2010-03-02 23:19:33303 CHECK_EQ(OK, result);
[email protected]9e743cd2010-03-16 07:03:53304 net_log_.BeginEvent(NetLog::TYPE_SPDY_STREAM_SEND_HEADERS);
[email protected]a677f2b2009-11-22 00:43:00305 result = DoSendHeaders();
306 break;
307 case STATE_SEND_HEADERS_COMPLETE:
[email protected]9e743cd2010-03-16 07:03:53308 net_log_.EndEvent(NetLog::TYPE_SPDY_STREAM_SEND_HEADERS);
[email protected]a677f2b2009-11-22 00:43:00309 result = DoSendHeadersComplete(result);
310 break;
311 case STATE_SEND_BODY:
[email protected]b1f031dd2010-03-02 23:19:33312 CHECK_EQ(OK, result);
[email protected]9e743cd2010-03-16 07:03:53313 net_log_.BeginEvent(NetLog::TYPE_SPDY_STREAM_SEND_BODY);
[email protected]a677f2b2009-11-22 00:43:00314 result = DoSendBody();
315 break;
316 case STATE_SEND_BODY_COMPLETE:
[email protected]9e743cd2010-03-16 07:03:53317 net_log_.EndEvent(NetLog::TYPE_SPDY_STREAM_SEND_BODY);
[email protected]a677f2b2009-11-22 00:43:00318 result = DoSendBodyComplete(result);
319 break;
320 case STATE_READ_HEADERS:
[email protected]b1f031dd2010-03-02 23:19:33321 CHECK_EQ(OK, result);
[email protected]9e743cd2010-03-16 07:03:53322 net_log_.BeginEvent(NetLog::TYPE_SPDY_STREAM_READ_HEADERS);
[email protected]a677f2b2009-11-22 00:43:00323 result = DoReadHeaders();
324 break;
325 case STATE_READ_HEADERS_COMPLETE:
[email protected]9e743cd2010-03-16 07:03:53326 net_log_.EndEvent(NetLog::TYPE_SPDY_STREAM_READ_HEADERS);
[email protected]a677f2b2009-11-22 00:43:00327 result = DoReadHeadersComplete(result);
328 break;
329
330 // State machine 2: Read body.
331 // NOTE(willchan): Currently unused. Currently we handle this stuff in
332 // the OnDataReceived()/OnClose()/ReadResponseHeaders()/etc. Only reason
333 // to do this is for consistency with the Http code.
334 case STATE_READ_BODY:
[email protected]9e743cd2010-03-16 07:03:53335 net_log_.BeginEvent(NetLog::TYPE_SPDY_STREAM_READ_BODY);
[email protected]a677f2b2009-11-22 00:43:00336 result = DoReadBody();
337 break;
338 case STATE_READ_BODY_COMPLETE:
[email protected]9e743cd2010-03-16 07:03:53339 net_log_.EndEvent(NetLog::TYPE_SPDY_STREAM_READ_BODY);
[email protected]a677f2b2009-11-22 00:43:00340 result = DoReadBodyComplete(result);
341 break;
342 case STATE_DONE:
343 DCHECK(result != ERR_IO_PENDING);
344 break;
345 default:
346 NOTREACHED();
347 break;
348 }
349 } while (result != ERR_IO_PENDING && io_state_ != STATE_NONE);
350
351 return result;
352}
353
[email protected]79d84222010-02-26 00:01:44354void SpdyStream::ScheduleBufferedReadCallback() {
355 // If there is already a scheduled DoBufferedReadCallback, don't issue
356 // another one. Mark that we have received more data and return.
357 if (buffered_read_callback_pending_) {
358 more_read_data_pending_ = true;
359 return;
360 }
361
362 more_read_data_pending_ = false;
363 buffered_read_callback_pending_ = true;
364 const int kBufferTimeMs = 1;
365 MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(
366 this, &SpdyStream::DoBufferedReadCallback), kBufferTimeMs);
367}
368
369// Checks to see if we should wait for more buffered data before notifying
370// the caller. Returns true if we should wait, false otherwise.
371bool SpdyStream::ShouldWaitForMoreBufferedData() const {
372 // If the response is complete, there is no point in waiting.
373 if (response_complete_)
374 return false;
375
376 int bytes_buffered = 0;
377 std::list<scoped_refptr<IOBufferWithSize> >::const_iterator it;
378 for (it = response_body_.begin();
379 it != response_body_.end() && bytes_buffered < user_buffer_len_;
380 ++it)
381 bytes_buffered += (*it)->size();
382
383 return bytes_buffered < user_buffer_len_;
384}
385
386void SpdyStream::DoBufferedReadCallback() {
387 buffered_read_callback_pending_ = false;
388
[email protected]1ed7b3dc2010-03-04 05:41:45389 // If the transaction is cancelled or errored out, we don't need to complete
390 // the read.
391 if (response_status_ != OK || cancelled_)
[email protected]8918d282010-03-02 00:57:55392 return;
393
[email protected]79d84222010-02-26 00:01:44394 // When more_read_data_pending_ is true, it means that more data has
395 // arrived since we started waiting. Wait a little longer and continue
396 // to buffer.
397 if (more_read_data_pending_ && ShouldWaitForMoreBufferedData()) {
398 ScheduleBufferedReadCallback();
399 return;
400 }
401
402 int rv = 0;
403 if (user_buffer_) {
404 rv = ReadResponseBody(user_buffer_, user_buffer_len_, user_callback_);
[email protected]b1f031dd2010-03-02 23:19:33405 CHECK_NE(rv, ERR_IO_PENDING);
[email protected]79d84222010-02-26 00:01:44406 user_buffer_ = NULL;
407 user_buffer_len_ = 0;
[email protected]79d84222010-02-26 00:01:44408 DoCallback(rv);
[email protected]8918d282010-03-02 00:57:55409 }
[email protected]79d84222010-02-26 00:01:44410}
411
[email protected]955fc2e72010-02-08 20:37:30412void SpdyStream::DoCallback(int rv) {
[email protected]b1f031dd2010-03-02 23:19:33413 CHECK_NE(rv, ERR_IO_PENDING);
[email protected]a677f2b2009-11-22 00:43:00414 CHECK(user_callback_);
415
416 // Since Run may result in being called back, clear user_callback_ in advance.
417 CompletionCallback* c = user_callback_;
418 user_callback_ = NULL;
419 c->Run(rv);
420}
421
[email protected]955fc2e72010-02-08 20:37:30422int SpdyStream::DoSendHeaders() {
423 // The SpdySession will always call us back when the send is complete.
[email protected]a677f2b2009-11-22 00:43:00424 // TODO(willchan): This code makes the assumption that for the non-push stream
425 // case, the client code calls SendRequest() after creating the stream and
426 // before yielding back to the MessageLoop. This is true in the current code,
427 // but is not obvious from the headers. We should make the code handle
428 // SendRequest() being called after the SYN_REPLY has been received.
429 io_state_ = STATE_SEND_HEADERS_COMPLETE;
430 return ERR_IO_PENDING;
431}
432
[email protected]955fc2e72010-02-08 20:37:30433int SpdyStream::DoSendHeadersComplete(int result) {
[email protected]a677f2b2009-11-22 00:43:00434 if (result < 0)
435 return result;
436
[email protected]b1f031dd2010-03-02 23:19:33437 CHECK_GT(result, 0);
[email protected]a677f2b2009-11-22 00:43:00438
439 // There is no body, skip that state.
440 if (!request_body_stream_.get()) {
441 io_state_ = STATE_READ_HEADERS;
442 return OK;
443 }
444
445 io_state_ = STATE_SEND_BODY;
[email protected]ff57bb82009-11-12 06:52:14446 return OK;
447}
448
[email protected]a677f2b2009-11-22 00:43:00449// DoSendBody is called to send the optional body for the request. This call
450// will also be called as each write of a chunk of the body completes.
[email protected]955fc2e72010-02-08 20:37:30451int SpdyStream::DoSendBody() {
[email protected]a677f2b2009-11-22 00:43:00452 // If we're already in the STATE_SENDING_BODY state, then we've already
453 // sent a portion of the body. In that case, we need to first consume
454 // the bytes written in the body stream. Note that the bytes written is
455 // the number of bytes in the frame that were written, only consume the
456 // data portion, of course.
457 io_state_ = STATE_SEND_BODY_COMPLETE;
458 int buf_len = static_cast<int>(request_body_stream_->buf_len());
459 return session_->WriteStreamData(stream_id_,
460 request_body_stream_->buf(),
461 buf_len);
462}
[email protected]cd314c822009-10-29 03:13:06463
[email protected]955fc2e72010-02-08 20:37:30464int SpdyStream::DoSendBodyComplete(int result) {
[email protected]a677f2b2009-11-22 00:43:00465 if (result < 0)
466 return result;
467
[email protected]b1f031dd2010-03-02 23:19:33468 CHECK_NE(result, 0);
[email protected]a677f2b2009-11-22 00:43:00469
470 request_body_stream_->DidConsume(result);
471
[email protected]95d88ffe2010-02-04 21:25:33472 if (!request_body_stream_->eof())
[email protected]a677f2b2009-11-22 00:43:00473 io_state_ = STATE_SEND_BODY;
474 else
475 io_state_ = STATE_READ_HEADERS;
476
477 return OK;
478}
479
[email protected]955fc2e72010-02-08 20:37:30480int SpdyStream::DoReadHeaders() {
[email protected]a677f2b2009-11-22 00:43:00481 io_state_ = STATE_READ_HEADERS_COMPLETE;
[email protected]a7e41312009-12-16 23:18:14482 return response_->headers ? OK : ERR_IO_PENDING;
[email protected]a677f2b2009-11-22 00:43:00483}
484
[email protected]955fc2e72010-02-08 20:37:30485int SpdyStream::DoReadHeadersComplete(int result) {
[email protected]a677f2b2009-11-22 00:43:00486 return result;
487}
488
[email protected]955fc2e72010-02-08 20:37:30489int SpdyStream::DoReadBody() {
490 // TODO(mbelshe): merge SpdyStreamParser with SpdyStream and then this
[email protected]a677f2b2009-11-22 00:43:00491 // makes sense.
492 return ERR_IO_PENDING;
493}
494
[email protected]955fc2e72010-02-08 20:37:30495int SpdyStream::DoReadBodyComplete(int result) {
496 // TODO(mbelshe): merge SpdyStreamParser with SpdyStream and then this
[email protected]a677f2b2009-11-22 00:43:00497 // makes sense.
498 return ERR_IO_PENDING;
499}
500
[email protected]955fc2e72010-02-08 20:37:30501void SpdyStream::UpdateHistograms() {
[email protected]e7f6a5a02009-12-28 01:08:22502 if (histograms_recorded_)
503 return;
504
505 histograms_recorded_ = true;
506
507 // We need all timers to be filled in, otherwise metrics can be bogus.
508 if (send_time_.is_null() || recv_first_byte_time_.is_null() ||
509 recv_last_byte_time_.is_null())
510 return;
511
512 UMA_HISTOGRAM_TIMES("Net.SpdyStreamTimeToFirstByte",
513 recv_first_byte_time_ - send_time_);
514 UMA_HISTOGRAM_TIMES("Net.SpdyStreamDownloadTime",
515 recv_last_byte_time_ - recv_first_byte_time_);
516 UMA_HISTOGRAM_TIMES("Net.SpdyStreamTime",
517 recv_last_byte_time_ - send_time_);
518
519 UMA_HISTOGRAM_COUNTS("Net.SpdySendBytes", send_bytes_);
520 UMA_HISTOGRAM_COUNTS("Net.SpdyRecvBytes", recv_bytes_);
521}
522
[email protected]a677f2b2009-11-22 00:43:00523} // namespace net