| OLD | NEW |
| (Empty) |
| 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 "base/strings/stringprintf.h" | |
| 8 #include "net/quic/quic_session.h" | |
| 9 | |
| 10 using base::StringPiece; | |
| 11 using std::string; | |
| 12 | |
| 13 namespace net { | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 const QuicStreamId kInvalidStreamId = 0; | |
| 18 | |
| 19 } // namespace | |
| 20 | |
| 21 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to | |
| 22 // the QuicDataStream, and closes the connection if any unexpected frames | |
| 23 // are received. | |
| 24 class QuicHeadersStream::SpdyFramerVisitor | |
| 25 : public SpdyFramerVisitorInterface, | |
| 26 public SpdyFramerDebugVisitorInterface { | |
| 27 public: | |
| 28 SpdyFramerVisitor(SpdyMajorVersion spdy_version, QuicHeadersStream* stream) | |
| 29 : spdy_version_(spdy_version), stream_(stream) {} | |
| 30 | |
| 31 // SpdyFramerVisitorInterface implementation | |
| 32 void OnSynStream(SpdyStreamId stream_id, | |
| 33 SpdyStreamId associated_stream_id, | |
| 34 SpdyPriority priority, | |
| 35 bool fin, | |
| 36 bool unidirectional) override { | |
| 37 if (spdy_version_ != SPDY3) { | |
| 38 CloseConnection("SPDY SYN_STREAM frame received."); | |
| 39 return; | |
| 40 } | |
| 41 | |
| 42 if (!stream_->IsConnected()) { | |
| 43 return; | |
| 44 } | |
| 45 | |
| 46 if (associated_stream_id != 0) { | |
| 47 CloseConnection("associated_stream_id != 0"); | |
| 48 return; | |
| 49 } | |
| 50 | |
| 51 if (unidirectional != 0) { | |
| 52 CloseConnection("unidirectional != 0"); | |
| 53 return; | |
| 54 } | |
| 55 | |
| 56 stream_->OnSynStream(stream_id, priority, fin); | |
| 57 } | |
| 58 | |
| 59 void OnSynReply(SpdyStreamId stream_id, bool fin) override { | |
| 60 if (spdy_version_ != SPDY3) { | |
| 61 CloseConnection("SPDY SYN_REPLY frame received."); | |
| 62 return; | |
| 63 } | |
| 64 | |
| 65 if (!stream_->IsConnected()) { | |
| 66 return; | |
| 67 } | |
| 68 | |
| 69 stream_->OnSynReply(stream_id, fin); | |
| 70 } | |
| 71 | |
| 72 bool OnControlFrameHeaderData(SpdyStreamId stream_id, | |
| 73 const char* header_data, | |
| 74 size_t len) override { | |
| 75 if (!stream_->IsConnected()) { | |
| 76 return false; | |
| 77 } | |
| 78 stream_->OnControlFrameHeaderData(stream_id, header_data, len); | |
| 79 return true; | |
| 80 } | |
| 81 | |
| 82 void OnStreamFrameData(SpdyStreamId stream_id, | |
| 83 const char* data, | |
| 84 size_t len, | |
| 85 bool fin) override { | |
| 86 if (fin && len == 0) { | |
| 87 // The framer invokes OnStreamFrameData with zero-length data and | |
| 88 // fin = true after processing a SYN_STREAM or SYN_REPLY frame | |
| 89 // that had the fin bit set. | |
| 90 return; | |
| 91 } | |
| 92 CloseConnection("SPDY DATA frame received."); | |
| 93 } | |
| 94 | |
| 95 void OnError(SpdyFramer* framer) override { | |
| 96 CloseConnection(base::StringPrintf( | |
| 97 "SPDY framing error: %s", | |
| 98 SpdyFramer::ErrorCodeToString(framer->error_code()))); | |
| 99 } | |
| 100 | |
| 101 void OnDataFrameHeader(SpdyStreamId stream_id, | |
| 102 size_t length, | |
| 103 bool fin) override { | |
| 104 CloseConnection("SPDY DATA frame received."); | |
| 105 } | |
| 106 | |
| 107 void OnRstStream(SpdyStreamId stream_id, | |
| 108 SpdyRstStreamStatus status) override { | |
| 109 CloseConnection("SPDY RST_STREAM frame received."); | |
| 110 } | |
| 111 | |
| 112 void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) override { | |
| 113 CloseConnection("SPDY SETTINGS frame received."); | |
| 114 } | |
| 115 | |
| 116 void OnSettingsAck() override { | |
| 117 CloseConnection("SPDY SETTINGS frame received."); | |
| 118 } | |
| 119 | |
| 120 void OnSettingsEnd() override { | |
| 121 CloseConnection("SPDY SETTINGS frame received."); | |
| 122 } | |
| 123 | |
| 124 void OnPing(SpdyPingId unique_id, bool is_ack) override { | |
| 125 CloseConnection("SPDY PING frame received."); | |
| 126 } | |
| 127 | |
| 128 void OnGoAway(SpdyStreamId last_accepted_stream_id, | |
| 129 SpdyGoAwayStatus status) override { | |
| 130 CloseConnection("SPDY GOAWAY frame received."); | |
| 131 } | |
| 132 | |
| 133 void OnHeaders(SpdyStreamId stream_id, | |
| 134 bool has_priority, | |
| 135 SpdyPriority priority, | |
| 136 bool fin, | |
| 137 bool end) override { | |
| 138 if (spdy_version_ == SPDY3) { | |
| 139 CloseConnection("SPDY HEADERS frame received."); | |
| 140 return; | |
| 141 } | |
| 142 if (!stream_->IsConnected()) { | |
| 143 return; | |
| 144 } | |
| 145 if (has_priority) { | |
| 146 stream_->OnSynStream(stream_id, priority, fin); | |
| 147 } else { | |
| 148 stream_->OnSynReply(stream_id, fin); | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 void OnWindowUpdate(SpdyStreamId stream_id, | |
| 153 uint32 delta_window_size) override { | |
| 154 CloseConnection("SPDY WINDOW_UPDATE frame received."); | |
| 155 } | |
| 156 | |
| 157 void OnPushPromise(SpdyStreamId stream_id, | |
| 158 SpdyStreamId promised_stream_id, | |
| 159 bool end) override { | |
| 160 LOG(DFATAL) << "PUSH_PROMISE frame received from a SPDY/3 framer"; | |
| 161 CloseConnection("SPDY PUSH_PROMISE frame received."); | |
| 162 } | |
| 163 | |
| 164 void OnContinuation(SpdyStreamId stream_id, bool end) override { | |
| 165 if (spdy_version_ == SPDY3) { | |
| 166 LOG(DFATAL) << "CONTINUATION frame received from a SPDY/3 framer"; | |
| 167 CloseConnection("SPDY CONTINUATION frame received."); | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { | |
| 172 CloseConnection("Unknown frame type received."); | |
| 173 return false; | |
| 174 } | |
| 175 | |
| 176 // SpdyFramerDebugVisitorInterface implementation | |
| 177 void OnSendCompressedFrame(SpdyStreamId stream_id, | |
| 178 SpdyFrameType type, | |
| 179 size_t payload_len, | |
| 180 size_t frame_len) override {} | |
| 181 | |
| 182 void OnReceiveCompressedFrame(SpdyStreamId stream_id, | |
| 183 SpdyFrameType type, | |
| 184 size_t frame_len) override { | |
| 185 if (stream_->IsConnected()) { | |
| 186 stream_->OnCompressedFrameSize(frame_len); | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 private: | |
| 191 void CloseConnection(const string& details) { | |
| 192 if (stream_->IsConnected()) { | |
| 193 stream_->CloseConnectionWithDetails( | |
| 194 QUIC_INVALID_HEADERS_STREAM_DATA, details); | |
| 195 } | |
| 196 } | |
| 197 | |
| 198 private: | |
| 199 SpdyMajorVersion spdy_version_; | |
| 200 QuicHeadersStream* stream_; | |
| 201 | |
| 202 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor); | |
| 203 }; | |
| 204 | |
| 205 QuicHeadersStream::QuicHeadersStream(QuicSession* session) | |
| 206 : ReliableQuicStream(kHeadersStreamId, session), | |
| 207 stream_id_(kInvalidStreamId), | |
| 208 fin_(false), | |
| 209 frame_len_(0) { | |
| 210 InitializeFramer(session->connection()->version()); | |
| 211 // The headers stream is exempt from connection level flow control. | |
| 212 DisableConnectionFlowControlForThisStream(); | |
| 213 } | |
| 214 | |
| 215 QuicHeadersStream::~QuicHeadersStream() {} | |
| 216 | |
| 217 size_t QuicHeadersStream::WriteHeaders( | |
| 218 QuicStreamId stream_id, | |
| 219 const SpdyHeaderBlock& headers, | |
| 220 bool fin, | |
| 221 QuicPriority priority, | |
| 222 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) { | |
| 223 scoped_ptr<SpdySerializedFrame> frame; | |
| 224 if (spdy_framer_->protocol_version() == SPDY3) { | |
| 225 if (session()->is_server()) { | |
| 226 SpdySynReplyIR syn_reply(stream_id); | |
| 227 syn_reply.set_name_value_block(headers); | |
| 228 syn_reply.set_fin(fin); | |
| 229 frame.reset(spdy_framer_->SerializeFrame(syn_reply)); | |
| 230 } else { | |
| 231 SpdySynStreamIR syn_stream(stream_id); | |
| 232 syn_stream.set_name_value_block(headers); | |
| 233 syn_stream.set_fin(fin); | |
| 234 syn_stream.set_priority(priority); | |
| 235 frame.reset(spdy_framer_->SerializeFrame(syn_stream)); | |
| 236 } | |
| 237 } else { | |
| 238 SpdyHeadersIR headers_frame(stream_id); | |
| 239 headers_frame.set_name_value_block(headers); | |
| 240 headers_frame.set_fin(fin); | |
| 241 if (!session()->is_server()) { | |
| 242 headers_frame.set_has_priority(true); | |
| 243 headers_frame.set_priority(priority); | |
| 244 } | |
| 245 frame.reset(spdy_framer_->SerializeFrame(headers_frame)); | |
| 246 } | |
| 247 WriteOrBufferData(StringPiece(frame->data(), frame->size()), false, | |
| 248 ack_notifier_delegate); | |
| 249 return frame->size(); | |
| 250 } | |
| 251 | |
| 252 uint32 QuicHeadersStream::ProcessRawData(const char* data, | |
| 253 uint32 data_len) { | |
| 254 return spdy_framer_->ProcessInput(data, data_len); | |
| 255 } | |
| 256 | |
| 257 QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; } | |
| 258 | |
| 259 void QuicHeadersStream::OnSuccessfulVersionNegotiation(QuicVersion version) { | |
| 260 InitializeFramer(version); | |
| 261 } | |
| 262 | |
| 263 void QuicHeadersStream::InitializeFramer(QuicVersion version) { | |
| 264 SpdyMajorVersion spdy_version = version > QUIC_VERSION_23 ? SPDY4 : SPDY3; | |
| 265 if (spdy_framer_.get() != nullptr && | |
| 266 spdy_framer_->protocol_version() == spdy_version) { | |
| 267 return; | |
| 268 } | |
| 269 spdy_framer_.reset(new SpdyFramer(spdy_version)); | |
| 270 spdy_framer_visitor_.reset(new SpdyFramerVisitor(spdy_version, this)); | |
| 271 spdy_framer_->set_visitor(spdy_framer_visitor_.get()); | |
| 272 spdy_framer_->set_debug_visitor(spdy_framer_visitor_.get()); | |
| 273 } | |
| 274 | |
| 275 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id, | |
| 276 SpdyPriority priority, | |
| 277 bool fin) { | |
| 278 if (!session()->is_server()) { | |
| 279 CloseConnectionWithDetails( | |
| 280 QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 281 "SPDY SYN_STREAM frame received at the client"); | |
| 282 return; | |
| 283 } | |
| 284 DCHECK_EQ(kInvalidStreamId, stream_id_); | |
| 285 stream_id_ = stream_id; | |
| 286 fin_ = fin; | |
| 287 session()->OnStreamHeadersPriority(stream_id, priority); | |
| 288 } | |
| 289 | |
| 290 void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id, bool fin) { | |
| 291 if (session()->is_server()) { | |
| 292 CloseConnectionWithDetails( | |
| 293 QUIC_INVALID_HEADERS_STREAM_DATA, | |
| 294 "SPDY SYN_REPLY frame received at the server"); | |
| 295 return; | |
| 296 } | |
| 297 DCHECK_EQ(kInvalidStreamId, stream_id_); | |
| 298 stream_id_ = stream_id; | |
| 299 fin_ = fin; | |
| 300 } | |
| 301 | |
| 302 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id, | |
| 303 const char* header_data, | |
| 304 size_t len) { | |
| 305 DCHECK_EQ(stream_id_, stream_id); | |
| 306 if (len == 0) { | |
| 307 DCHECK_NE(0u, stream_id_); | |
| 308 DCHECK_NE(0u, frame_len_); | |
| 309 session()->OnStreamHeadersComplete(stream_id_, fin_, frame_len_); | |
| 310 // Reset state for the next frame. | |
| 311 stream_id_ = kInvalidStreamId; | |
| 312 fin_ = false; | |
| 313 frame_len_ = 0; | |
| 314 } else { | |
| 315 session()->OnStreamHeaders(stream_id_, StringPiece(header_data, len)); | |
| 316 } | |
| 317 } | |
| 318 | |
| 319 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) { | |
| 320 if (spdy_framer_->protocol_version() == SPDY3) { | |
| 321 // SPDY/3 headers always fit into a single frame, so the previous headers | |
| 322 // should be completely processed when a new frame is received. | |
| 323 DCHECK_EQ(kInvalidStreamId, stream_id_); | |
| 324 DCHECK_EQ(0u, frame_len_); | |
| 325 } | |
| 326 frame_len_ += frame_len; | |
| 327 } | |
| 328 | |
| 329 bool QuicHeadersStream::IsConnected() { | |
| 330 return session()->connection()->connected(); | |
| 331 } | |
| 332 | |
| 333 } // namespace net | |
| OLD | NEW |