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