1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_stream.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/message_loop.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/values.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/spdy/spdy_session.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace net {
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace {
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass NetLogSpdyStreamWindowUpdateParameter : public NetLog::EventParameters {
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  NetLogSpdyStreamWindowUpdateParameter(spdy::SpdyStreamId stream_id,
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                        int delta,
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                        int window_size)
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      : stream_id_(stream_id), delta_(delta), window_size_(window_size) {}
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  virtual Value* ToValue() const {
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DictionaryValue* dict = new DictionaryValue();
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    dict->SetInteger("id", static_cast<int>(stream_id_));
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    dict->SetInteger("delta", delta_);
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    dict->SetInteger("window_size", window_size_);
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return dict;
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private:
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const spdy::SpdyStreamId stream_id_;
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const int delta_;
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const int window_size_;
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DISALLOW_COPY_AND_ASSIGN(NetLogSpdyStreamWindowUpdateParameter);
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
383345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickSpdyStream::SpdyStream(SpdySession* session,
393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                       spdy::SpdyStreamId stream_id,
403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                       bool pushed,
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                       const BoundNetLog& net_log)
423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    : continue_buffering_data_(true),
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      stream_id_(stream_id),
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      priority_(0),
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      stalled_by_flow_control_(false),
46201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      send_window_size_(spdy::kSpdyStreamInitialWindowSize),
47201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      recv_window_size_(spdy::kSpdyStreamInitialWindowSize),
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      pushed_(pushed),
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      response_received_(false),
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      session_(session),
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delegate_(NULL),
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      request_time_(base::Time::Now()),
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      response_(new spdy::SpdyHeaderBlock),
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      io_state_(STATE_NONE),
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      response_status_(OK),
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cancelled_(false),
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      has_upload_data_(false),
583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      net_log_(net_log),
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      send_bytes_(0),
603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      recv_bytes_(0) {
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSpdyStream::~SpdyStream() {
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  UpdateHistograms();
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyStream::SetDelegate(Delegate* delegate) {
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(delegate);
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_ = delegate;
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (pushed_) {
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CHECK(response_received());
733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    MessageLoop::current()->PostTask(
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        FROM_HERE, NewRunnableMethod(this,
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                     &SpdyStream::PushedStreamReplayData));
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else {
773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    continue_buffering_data_ = false;
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SpdyStream::PushedStreamReplayData() {
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (cancelled_ || !delegate_)
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  continue_buffering_data_ = false;
86201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
87201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int rv = delegate_->OnResponseReceived(*response_, response_time_, OK);
88201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (rv == ERR_INCOMPLETE_SPDY_HEADERS) {
89201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // We don't have complete headers.  Assume we're waiting for another
90201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // HEADERS frame.  Since we don't have headers, we had better not have
91201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // any pending data frames.
92201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    DCHECK_EQ(0U, pending_buffers_.size());
93201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return;
94201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
95201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<scoped_refptr<IOBufferWithSize> > buffers;
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  buffers.swap(pending_buffers_);
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < buffers.size(); ++i) {
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // It is always possible that a callback to the delegate results in
1003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // the delegate no longer being available.
1013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!delegate_)
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      break;
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (buffers[i]) {
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      delegate_->OnDataReceived(buffers[i]->data(), buffers[i]->size());
1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else {
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      delegate_->OnDataReceived(NULL, 0);
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      session_->CloseStream(stream_id_, net::OK);
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Note: |this| may be deleted after calling CloseStream.
1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      DCHECK_EQ(buffers.size() - 1, i);
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyStream::DetachDelegate() {
115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (delegate_)
116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delegate_->set_chunk_callback(NULL);
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_ = NULL;
1183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!closed())
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Cancel();
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst linked_ptr<spdy::SpdyHeaderBlock>& SpdyStream::spdy_headers() const {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return request_;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyStream::set_spdy_headers(
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const linked_ptr<spdy::SpdyHeaderBlock>& headers) {
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_ = headers;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SpdyStream::IncreaseSendWindowSize(int delta_window_size) {
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GE(delta_window_size, 1);
1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int new_window_size = send_window_size_ + delta_window_size;
1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // We should ignore WINDOW_UPDATEs received before or after this state,
1363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // since before means we've not written SYN_STREAM yet (i.e. it's too
1373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // early) and after means we've written a DATA frame with FIN bit.
1383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (io_state_ != STATE_SEND_BODY_COMPLETE)
1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // it's valid for send_window_size_ to become negative (via an incoming
1423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // SETTINGS), in which case incoming WINDOW_UPDATEs will eventually make
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // it positive; however, if send_window_size_ is positive and incoming
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // WINDOW_UPDATE makes it negative, we have an overflow.
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (send_window_size_ > 0 && new_window_size < 0) {
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(WARNING) << "Received WINDOW_UPDATE [delta:" << delta_window_size
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 << "] for stream " << stream_id_
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 << " overflows send_window_size_ [current:"
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 << send_window_size_ << "]";
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    session_->ResetStream(stream_id_, spdy::FLOW_CONTROL_ERROR);
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  send_window_size_ = new_window_size;
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
156513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net_log_.AddEvent(
157513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      NetLog::TYPE_SPDY_STREAM_SEND_WINDOW_UPDATE,
158513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      make_scoped_refptr(new NetLogSpdyStreamWindowUpdateParameter(
159513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          stream_id_, delta_window_size, send_window_size_)));
1603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (stalled_by_flow_control_) {
1613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    stalled_by_flow_control_ = false;
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    io_state_ = STATE_SEND_BODY;
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DoLoop(OK);
1643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SpdyStream::DecreaseSendWindowSize(int delta_window_size) {
1683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // we only call this method when sending a frame, therefore
1693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // |delta_window_size| should be within the valid frame size range.
1703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_GE(delta_window_size, 1);
1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_LE(delta_window_size, kMaxSpdyFrameChunkSize);
1723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // |send_window_size_| should have been at least |delta_window_size| for
1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // this call to happen.
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_GE(send_window_size_, delta_window_size);
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  send_window_size_ -= delta_window_size;
1783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
179513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net_log_.AddEvent(
180513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      NetLog::TYPE_SPDY_STREAM_SEND_WINDOW_UPDATE,
181513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      make_scoped_refptr(new NetLogSpdyStreamWindowUpdateParameter(
182513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          stream_id_, -delta_window_size, send_window_size_)));
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SpdyStream::IncreaseRecvWindowSize(int delta_window_size) {
1863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_GE(delta_window_size, 1);
1873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // By the time a read is isued, stream may become inactive.
1883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!session_->IsStreamActive(stream_id_))
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
1903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int new_window_size = recv_window_size_ + delta_window_size;
1913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (recv_window_size_ > 0)
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(new_window_size > 0);
1933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  recv_window_size_ = new_window_size;
195513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net_log_.AddEvent(
196513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      NetLog::TYPE_SPDY_STREAM_RECV_WINDOW_UPDATE,
197513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      make_scoped_refptr(new NetLogSpdyStreamWindowUpdateParameter(
198513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          stream_id_, delta_window_size, recv_window_size_)));
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  session_->SendWindowUpdate(stream_id_, delta_window_size);
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SpdyStream::DecreaseRecvWindowSize(int delta_window_size) {
2033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_GE(delta_window_size, 1);
2043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  recv_window_size_ -= delta_window_size;
206513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  net_log_.AddEvent(
207513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      NetLog::TYPE_SPDY_STREAM_RECV_WINDOW_UPDATE,
208513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      make_scoped_refptr(new NetLogSpdyStreamWindowUpdateParameter(
209513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          stream_id_, -delta_window_size, recv_window_size_)));
2103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Since we never decrease the initial window size, we should never hit
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // a negative |recv_window_size_|, if we do, it's a flow-control violation.
2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (recv_window_size_ < 0)
2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    session_->ResetStream(stream_id_, spdy::FLOW_CONTROL_ERROR);
2153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
217731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickint SpdyStream::GetPeerAddress(AddressList* address) const {
218731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return session_->GetPeerAddress(address);
219731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
220731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint SpdyStream::GetLocalAddress(IPEndPoint* address) const {
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return session_->GetLocalAddress(address);
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
225731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool SpdyStream::WasEverUsed() const {
226731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return session_->WasEverUsed();
227731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbase::Time SpdyStream::GetRequestTime() const {
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return request_time_;
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyStream::SetRequestTime(base::Time t) {
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  request_time_ = t;
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyStream::OnResponseReceived(const spdy::SpdyHeaderBlock& response) {
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int rv = OK;
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  metrics_.StartStream();
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(response_->empty());
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  *response_ = response;  // TODO(ukai): avoid copy.
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  recv_first_byte_time_ = base::TimeTicks::Now();
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_time_ = base::Time::Now();
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If we receive a response before we are in STATE_WAITING_FOR_RESPONSE, then
2493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // the server has sent the SYN_REPLY too early.
2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!pushed_ && io_state_ != STATE_WAITING_FOR_RESPONSE)
2513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return ERR_SPDY_PROTOCOL_ERROR;
2523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (pushed_)
2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    CHECK(io_state_ == STATE_NONE);
2543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  io_state_ = STATE_OPEN;
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (delegate_)
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    rv = delegate_->OnResponseReceived(*response_, response_time_, rv);
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // If delegate_ is not yet attached, we'll call OnResponseReceived after the
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // delegate gets attached to the stream.
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return rv;
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
264201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochint SpdyStream::OnHeaders(const spdy::SpdyHeaderBlock& headers) {
265201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK(!response_->empty());
266201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
267201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // Append all the headers into the response header block.
268201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  for (spdy::SpdyHeaderBlock::const_iterator it = headers.begin();
269201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      it != headers.end(); ++it) {
270201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // Disallow duplicate headers.  This is just to be conservative.
271201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if ((*response_).find(it->first) != (*response_).end()) {
272201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      LOG(WARNING) << "HEADERS duplicate header";
273201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      response_status_ = ERR_SPDY_PROTOCOL_ERROR;
274201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      return ERR_SPDY_PROTOCOL_ERROR;
275201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
276201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
277201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    (*response_)[it->first] = it->second;
278201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
279201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
280201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  int rv = OK;
281201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (delegate_) {
282201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    rv = delegate_->OnResponseReceived(*response_, response_time_, rv);
283201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // ERR_INCOMPLETE_SPDY_HEADERS means that we are waiting for more
284201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // headers before the response header block is complete.
285201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (rv == ERR_INCOMPLETE_SPDY_HEADERS)
286201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      rv = OK;
287201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
288201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return rv;
289201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
290201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyStream::OnDataReceived(const char* data, int length) {
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_GE(length, 0);
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
294201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // If we don't have a response, then the SYN_REPLY did not come through.
295201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // We cannot pass data up to the caller unless the reply headers have been
296201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // received.
297201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!response_received()) {
298201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    session_->CloseStream(stream_id_, ERR_SYN_REPLY_NOT_RECEIVED);
299201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return;
300201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
301201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
3023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!delegate_ || continue_buffering_data_) {
3033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // It should be valid for this to happen in the server push case.
3043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // We'll return received data when delegate gets attached to the stream.
3053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (length > 0) {
3063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      IOBufferWithSize* buf = new IOBufferWithSize(length);
3073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      memcpy(buf->data(), data, length);
308513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      pending_buffers_.push_back(make_scoped_refptr(buf));
3093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    } else {
3103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      pending_buffers_.push_back(NULL);
3113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      metrics_.StopStream();
3123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Note: we leave the stream open in the session until the stream
3133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      //       is claimed.
3143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
3153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
3163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
3173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
318201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  CHECK(!closed());
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // A zero-length read means that the stream is being closed.
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!length) {
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    metrics_.StopStream();
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    session_->CloseStream(stream_id_, net::OK);
3243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Note: |this| may be deleted after calling CloseStream.
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (session_->flow_control())
3293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DecreaseRecvWindowSize(length);
3303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Track our bandwidth.
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  metrics_.RecordBytes(length);
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  recv_bytes_ += length;
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  recv_last_byte_time_ = base::TimeTicks::Now();
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!delegate_) {
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // It should be valid for this to happen in the server push case.
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We'll return received data when delegate gets attached to the stream.
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    IOBufferWithSize* buf = new IOBufferWithSize(length);
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    memcpy(buf->data(), data, length);
341513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    pending_buffers_.push_back(make_scoped_refptr(buf));
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_->OnDataReceived(data, length);
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// This function is only called when an entire frame is written.
3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid SpdyStream::OnWriteComplete(int bytes) {
3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_LE(0, bytes);
3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  send_bytes_ += bytes;
3523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (cancelled() || closed())
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
3543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DoLoop(bytes);
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
357dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SpdyStream::OnChunkAvailable() {
358dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(io_state_ == STATE_SEND_HEADERS || io_state_ == STATE_SEND_BODY ||
359dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen         io_state_ == STATE_SEND_BODY_COMPLETE);
360dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (io_state_ == STATE_SEND_BODY)
361dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    OnWriteComplete(0);
362dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
363dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyStream::OnClose(int status) {
3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  io_state_ = STATE_DONE;
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  response_status_ = status;
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Delegate* delegate = delegate_;
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delegate_ = NULL;
369dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (delegate) {
370dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delegate->set_chunk_callback(NULL);
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delegate->OnClose(status);
372dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyStream::Cancel() {
3763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (cancelled())
3773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  cancelled_ = true;
3803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (session_->IsStreamActive(stream_id_))
3813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    session_->ResetStream(stream_id_, spdy::CANCEL);
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickint SpdyStream::SendRequest(bool has_upload_data) {
385dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (delegate_)
386dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    delegate_->set_chunk_callback(this);
387dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
3883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Pushed streams do not send any data, and should always be in STATE_OPEN or
3893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // STATE_DONE. However, we still want to return IO_PENDING to mimic non-push
3903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // behavior.
3913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  has_upload_data_ = has_upload_data;
3923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (pushed_) {
3933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    send_time_ = base::TimeTicks::Now();
3943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(!has_upload_data_);
3953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(response_received());
3963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return ERR_IO_PENDING;
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
3983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CHECK_EQ(STATE_NONE, io_state_);
3993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  io_state_ = STATE_SEND_HEADERS;
4003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return DoLoop(OK);
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyStream::WriteStreamData(IOBuffer* data, int length,
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                spdy::SpdyDataFlags flags) {
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return session_->WriteStreamData(stream_id_, data, length, flags);
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SpdyStream::GetSSLInfo(SSLInfo* ssl_info, bool* was_npn_negotiated) {
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return session_->GetSSLInfo(ssl_info, was_npn_negotiated);
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickbool SpdyStream::GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) {
4133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return session_->GetSSLCertRequestInfo(cert_request_info);
4143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
4153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
416201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochbool SpdyStream::HasUrl() const {
417201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (pushed_)
418201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return response_received();
419201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return request_.get() != NULL;
420201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
421201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
422201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochGURL SpdyStream::GetUrl() const {
423201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DCHECK(HasUrl());
424201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
425201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (pushed_) {
426201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    // assemble from the response
427201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    std::string url;
428201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    spdy::SpdyHeaderBlock::const_iterator it;
429201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    it = response_->find("url");
430201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (it != (*response_).end())
431201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      url = it->second;
432201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return GURL(url);
433201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
434201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
435201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  // assemble from the request
436201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::string scheme;
437201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::string host_port;
438201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::string path;
439201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  spdy::SpdyHeaderBlock::const_iterator it;
440201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  it = request_->find("scheme");
441201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (it != (*request_).end())
442201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    scheme = it->second;
443201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  it = request_->find("host");
444201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (it != (*request_).end())
445201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    host_port = it->second;
446201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  it = request_->find("path");
447201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (it != (*request_).end())
448201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    path = it->second;
449201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  std::string url = scheme + "://" + host_port + path;
450201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return GURL(url);
451201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
452201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyStream::DoLoop(int result) {
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  do {
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    State state = io_state_;
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    io_state_ = STATE_NONE;
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (state) {
4583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // State machine 1: Send headers and body.
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_SEND_HEADERS:
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        CHECK_EQ(OK, result);
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        result = DoSendHeaders();
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_SEND_HEADERS_COMPLETE:
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        result = DoSendHeadersComplete(result);
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_SEND_BODY:
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        CHECK_EQ(OK, result);
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        result = DoSendBody();
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_SEND_BODY_COMPLETE:
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        result = DoSendBodyComplete(result);
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
4733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // This is an intermediary waiting state. This state is reached when all
4743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // data has been sent, but no data has been received.
4753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      case STATE_WAITING_FOR_RESPONSE:
4763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        io_state_ = STATE_WAITING_FOR_RESPONSE;
4773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        result = ERR_IO_PENDING;
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // State machine 2: connection is established.
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // In STATE_OPEN, OnResponseReceived has already been called.
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // OnDataReceived, OnClose and OnWriteCompelte can be called.
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Only OnWriteCompletee calls DoLoop(().
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      //
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // For HTTP streams, no data is sent from the client while in the OPEN
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // state, so OnWriteComplete is never called here.  The HTTP body is
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // handled in the OnDataReceived callback, which does not call into
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // DoLoop.
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      //
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // For WebSocket streams, which are bi-directional, we'll send and
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // receive data once the connection is established.  Received data is
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // handled in OnDataReceived.  Sent data is handled in OnWriteComplete,
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // which calls DoOpen().
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_OPEN:
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        result = DoOpen(result);
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case STATE_DONE:
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK(result != ERR_IO_PENDING);
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NOTREACHED() << io_state_;
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } while (result != ERR_IO_PENDING && io_state_ != STATE_NONE &&
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch           io_state_ != STATE_OPEN);
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyStream::DoSendHeaders() {
5113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CHECK(!cancelled_);
5123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  spdy::SpdyControlFlags flags = spdy::CONTROL_FLAG_NONE;
5143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!has_upload_data_)
5153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    flags = spdy::CONTROL_FLAG_FIN;
5163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  CHECK(request_.get());
5183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int result = session_->WriteSynStream(
5193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      stream_id_, static_cast<RequestPriority>(priority_), flags,
5203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      request_);
5213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (result != ERR_IO_PENDING)
5223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return result;
5233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
5243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  send_time_ = base::TimeTicks::Now();
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  io_state_ = STATE_SEND_HEADERS_COMPLETE;
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return ERR_IO_PENDING;
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyStream::DoSendHeadersComplete(int result) {
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result < 0)
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK_GT(result, 0);
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!delegate_)
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_UNEXPECTED;
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // There is no body, skip that state.
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (delegate_->OnSendHeadersComplete(result)) {
5403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    io_state_ = STATE_WAITING_FOR_RESPONSE;
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return OK;
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  io_state_ = STATE_SEND_BODY;
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return OK;
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DoSendBody is called to send the optional body for the request.  This call
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// will also be called as each write of a chunk of the body completes.
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyStream::DoSendBody() {
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we're already in the STATE_SENDING_BODY state, then we've already
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // sent a portion of the body.  In that case, we need to first consume
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the bytes written in the body stream.  Note that the bytes written is
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // the number of bytes in the frame that were written, only consume the
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // data portion, of course.
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  io_state_ = STATE_SEND_BODY_COMPLETE;
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!delegate_)
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_UNEXPECTED;
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return delegate_->OnSendBody();
560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyStream::DoSendBodyComplete(int result) {
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (result < 0)
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return result;
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!delegate_)
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return ERR_UNEXPECTED;
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
569dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  bool eof = false;
570dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  result = delegate_->OnSendBodyComplete(result, &eof);
571dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!eof)
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    io_state_ = STATE_SEND_BODY;
573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
5743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    io_state_ = STATE_WAITING_FOR_RESPONSE;
575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
576dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return result;
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint SpdyStream::DoOpen(int result) {
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (delegate_)
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delegate_->OnDataSent(result);
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  io_state_ = STATE_OPEN;
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SpdyStream::UpdateHistograms() {
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We need all timers to be filled in, otherwise metrics can be bogus.
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (send_time_.is_null() || recv_first_byte_time_.is_null() ||
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      recv_last_byte_time_.is_null())
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_TIMES("Net.SpdyStreamTimeToFirstByte",
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      recv_first_byte_time_ - send_time_);
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_TIMES("Net.SpdyStreamDownloadTime",
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      recv_last_byte_time_ - recv_first_byte_time_);
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_TIMES("Net.SpdyStreamTime",
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      recv_last_byte_time_ - send_time_);
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS("Net.SpdySendBytes", send_bytes_);
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_COUNTS("Net.SpdyRecvBytes", recv_bytes_);
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace net
604