1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "net/quic/quic_headers_stream.h" 6 7#include "net/quic/quic_session.h" 8 9using base::StringPiece; 10 11namespace net { 12 13namespace { 14 15const QuicStreamId kInvalidStreamId = 0; 16 17} // namespace 18 19// A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to 20// the QuicDataStream, and closes the connection if any unexpected frames 21// are received. 22class QuicHeadersStream::SpdyFramerVisitor 23 : public SpdyFramerVisitorInterface, 24 public SpdyFramerDebugVisitorInterface { 25 public: 26 explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {} 27 28 // SpdyFramerVisitorInterface implementation 29 virtual void OnSynStream(SpdyStreamId stream_id, 30 SpdyStreamId associated_stream_id, 31 SpdyPriority priority, 32 bool fin, 33 bool unidirectional) OVERRIDE { 34 if (!stream_->IsConnected()) { 35 return; 36 } 37 38 if (associated_stream_id != 0) { 39 CloseConnection("associated_stream_id != 0"); 40 return; 41 } 42 43 if (unidirectional != 0) { 44 CloseConnection("unidirectional != 0"); 45 return; 46 } 47 48 stream_->OnSynStream(stream_id, priority, fin); 49 } 50 51 virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE { 52 if (!stream_->IsConnected()) { 53 return; 54 } 55 56 stream_->OnSynReply(stream_id, fin); 57 } 58 59 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id, 60 const char* header_data, 61 size_t len) OVERRIDE { 62 if (!stream_->IsConnected()) { 63 return false; 64 } 65 stream_->OnControlFrameHeaderData(stream_id, header_data, len); 66 return true; 67 } 68 69 virtual void OnStreamFrameData(SpdyStreamId stream_id, 70 const char* data, 71 size_t len, 72 bool fin) OVERRIDE { 73 if (fin && len == 0) { 74 // The framer invokes OnStreamFrameData with zero-length data and 75 // fin = true after processing a SYN_STREAM or SYN_REPLY frame 76 // that had the fin bit set. 77 return; 78 } 79 CloseConnection("SPDY DATA frame received."); 80 } 81 82 virtual void OnError(SpdyFramer* framer) OVERRIDE { 83 CloseConnection("SPDY framing error."); 84 } 85 86 virtual void OnDataFrameHeader(SpdyStreamId stream_id, 87 size_t length, 88 bool fin) OVERRIDE { 89 CloseConnection("SPDY DATA frame received."); 90 } 91 92 virtual void OnRstStream(SpdyStreamId stream_id, 93 SpdyRstStreamStatus status) OVERRIDE { 94 CloseConnection("SPDY RST_STREAM frame received."); 95 } 96 97 virtual void OnSetting(SpdySettingsIds id, 98 uint8 flags, 99 uint32 value) OVERRIDE { 100 CloseConnection("SPDY SETTINGS frame received."); 101 } 102 103 virtual void OnSettingsAck() OVERRIDE { 104 CloseConnection("SPDY SETTINGS frame received."); 105 } 106 107 virtual void OnSettingsEnd() OVERRIDE { 108 CloseConnection("SPDY SETTINGS frame received."); 109 } 110 111 virtual void OnPing(SpdyPingId unique_id, bool is_ack) OVERRIDE { 112 CloseConnection("SPDY PING frame received."); 113 } 114 115 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id, 116 SpdyGoAwayStatus status) OVERRIDE { 117 CloseConnection("SPDY GOAWAY frame received."); 118 } 119 120 virtual void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) OVERRIDE { 121 CloseConnection("SPDY HEADERS frame received."); 122 } 123 124 virtual void OnWindowUpdate(SpdyStreamId stream_id, 125 uint32 delta_window_size) OVERRIDE { 126 CloseConnection("SPDY WINDOW_UPDATE frame received."); 127 } 128 129 virtual void OnPushPromise(SpdyStreamId stream_id, 130 SpdyStreamId promised_stream_id, 131 bool end) OVERRIDE { 132 LOG(DFATAL) << "PUSH_PROMISE frame received from a SPDY/3 framer"; 133 CloseConnection("SPDY PUSH_PROMISE frame received."); 134 } 135 136 virtual void OnContinuation(SpdyStreamId stream_id, bool end) OVERRIDE { 137 CloseConnection("SPDY CONTINUATION frame received."); 138 } 139 140 // SpdyFramerDebugVisitorInterface implementation 141 virtual void OnSendCompressedFrame(SpdyStreamId stream_id, 142 SpdyFrameType type, 143 size_t payload_len, 144 size_t frame_len) OVERRIDE {} 145 146 virtual void OnReceiveCompressedFrame(SpdyStreamId stream_id, 147 SpdyFrameType type, 148 size_t frame_len) OVERRIDE { 149 if (stream_->IsConnected()) { 150 stream_->OnCompressedFrameSize(frame_len); 151 } 152 } 153 154 private: 155 void CloseConnection(const string& details) { 156 if (stream_->IsConnected()) { 157 stream_->CloseConnectionWithDetails( 158 QUIC_INVALID_HEADERS_STREAM_DATA, details); 159 } 160 } 161 162 private: 163 QuicHeadersStream* stream_; 164 165 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor); 166}; 167 168QuicHeadersStream::QuicHeadersStream(QuicSession* session) 169 : ReliableQuicStream(kHeadersStreamId, session), 170 stream_id_(kInvalidStreamId), 171 fin_(false), 172 frame_len_(0), 173 spdy_framer_(SPDY3), 174 spdy_framer_visitor_(new SpdyFramerVisitor(this)) { 175 spdy_framer_.set_visitor(spdy_framer_visitor_.get()); 176 spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get()); 177 // TODO(jri): Set headers to be always FEC protected. 178 DisableFlowControl(); 179} 180 181QuicHeadersStream::~QuicHeadersStream() {} 182 183size_t QuicHeadersStream::WriteHeaders( 184 QuicStreamId stream_id, 185 const SpdyHeaderBlock& headers, 186 bool fin, 187 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) { 188 scoped_ptr<SpdySerializedFrame> frame; 189 if (session()->is_server()) { 190 SpdySynReplyIR syn_reply(stream_id); 191 syn_reply.set_name_value_block(headers); 192 syn_reply.set_fin(fin); 193 frame.reset(spdy_framer_.SerializeFrame(syn_reply)); 194 } else { 195 SpdySynStreamIR syn_stream(stream_id); 196 syn_stream.set_name_value_block(headers); 197 syn_stream.set_fin(fin); 198 frame.reset(spdy_framer_.SerializeFrame(syn_stream)); 199 } 200 WriteOrBufferData(StringPiece(frame->data(), frame->size()), false, 201 ack_notifier_delegate); 202 return frame->size(); 203} 204 205uint32 QuicHeadersStream::ProcessRawData(const char* data, 206 uint32 data_len) { 207 return spdy_framer_.ProcessInput(data, data_len); 208} 209 210QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; } 211 212void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id, 213 SpdyPriority priority, 214 bool fin) { 215 if (!session()->is_server()) { 216 CloseConnectionWithDetails( 217 QUIC_INVALID_HEADERS_STREAM_DATA, 218 "SPDY SYN_STREAM frame received at the client"); 219 return; 220 } 221 DCHECK_EQ(kInvalidStreamId, stream_id_); 222 stream_id_ = stream_id; 223 fin_ = fin; 224 session()->OnStreamHeadersPriority(stream_id, priority); 225} 226 227void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id, bool fin) { 228 if (session()->is_server()) { 229 CloseConnectionWithDetails( 230 QUIC_INVALID_HEADERS_STREAM_DATA, 231 "SPDY SYN_REPLY frame received at the server"); 232 return; 233 } 234 DCHECK_EQ(kInvalidStreamId, stream_id_); 235 stream_id_ = stream_id; 236 fin_ = fin; 237} 238 239void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id, 240 const char* header_data, 241 size_t len) { 242 DCHECK_EQ(stream_id_, stream_id); 243 if (len == 0) { 244 DCHECK_NE(0u, stream_id_); 245 DCHECK_NE(0u, frame_len_); 246 session()->OnStreamHeadersComplete(stream_id_, fin_, frame_len_); 247 // Reset state for the next frame. 248 stream_id_ = kInvalidStreamId; 249 fin_ = false; 250 frame_len_ = 0; 251 } else { 252 session()->OnStreamHeaders(stream_id_, StringPiece(header_data, len)); 253 } 254} 255 256void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) { 257 DCHECK_EQ(kInvalidStreamId, stream_id_); 258 DCHECK_EQ(0u, frame_len_); 259 frame_len_ = frame_len; 260} 261 262bool QuicHeadersStream::IsConnected() { 263 return session()->connection()->connected(); 264} 265 266} // namespace net 267