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