| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/quic_headers_stream.h" | 5 #include "net/quic/quic_headers_stream.h" |
| 6 | 6 |
| 7 #include "base/macros.h" | 7 #include "base/macros.h" |
| 8 #include "base/metrics/histogram_macros.h" | 8 #include "base/metrics/histogram_macros.h" |
| 9 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
| 10 #include "net/quic/quic_bug_tracker.h" | 10 #include "net/quic/quic_bug_tracker.h" |
| 11 #include "net/quic/quic_flags.h" | 11 #include "net/quic/quic_flags.h" |
| 12 #include "net/quic/quic_headers_stream.h" | 12 #include "net/quic/quic_headers_stream.h" |
| 13 #include "net/quic/quic_spdy_session.h" | 13 #include "net/quic/quic_spdy_session.h" |
| 14 #include "net/quic/quic_time.h" | 14 #include "net/quic/quic_time.h" |
| 15 | 15 |
| 16 using base::StringPiece; | 16 using base::StringPiece; |
| 17 using net::HTTP2; | 17 using net::HTTP2; |
| 18 using net::SpdyFrameType; | 18 using net::SpdyFrameType; |
| 19 using std::string; | 19 using std::string; |
| 20 | 20 |
| 21 namespace net { | 21 namespace net { |
| 22 | 22 |
| 23 namespace { | |
| 24 | |
| 25 const QuicStreamId kInvalidStreamId = 0; | |
| 26 | |
| 27 } // namespace | |
| 28 | |
| 29 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to | 23 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to |
| 30 // the QuicSpdyStream, and closes the connection if any unexpected frames | 24 // the QuicSpdyStream, and closes the connection if any unexpected frames |
| 31 // are received. | 25 // are received. |
| 32 class QuicHeadersStream::SpdyFramerVisitor | 26 class QuicHeadersStream::SpdyFramerVisitor |
| 33 : public SpdyFramerVisitorInterface, | 27 : public SpdyFramerVisitorInterface, |
| 34 public SpdyFramerDebugVisitorInterface { | 28 public SpdyFramerDebugVisitorInterface { |
| 35 public: | 29 public: |
| 36 explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {} | 30 explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {} |
| 37 | 31 |
| 38 // SpdyFramerVisitorInterface implementation | 32 // SpdyFramerVisitorInterface implementation |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 137 stream_->OnHeaders(stream_id, has_priority, priority, fin); | 131 stream_->OnHeaders(stream_id, has_priority, priority, fin); |
| 138 } | 132 } |
| 139 | 133 |
| 140 void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override { | 134 void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override { |
| 141 CloseConnection("SPDY WINDOW_UPDATE frame received."); | 135 CloseConnection("SPDY WINDOW_UPDATE frame received."); |
| 142 } | 136 } |
| 143 | 137 |
| 144 void OnPushPromise(SpdyStreamId stream_id, | 138 void OnPushPromise(SpdyStreamId stream_id, |
| 145 SpdyStreamId promised_stream_id, | 139 SpdyStreamId promised_stream_id, |
| 146 bool end) override { | 140 bool end) override { |
| 147 CloseConnection("SPDY PUSH_PROMISE frame received."); | 141 if (!stream_->supports_push_promise()) { |
| 142 CloseConnection("PUSH_PROMISE not supported."); |
| 143 return; |
| 144 } |
| 145 if (!stream_->IsConnected()) { |
| 146 return; |
| 147 } |
| 148 stream_->OnPushPromise(stream_id, promised_stream_id, end); |
| 148 } | 149 } |
| 149 | 150 |
| 150 void OnContinuation(SpdyStreamId stream_id, bool end) override {} | 151 void OnContinuation(SpdyStreamId stream_id, bool end) override {} |
| 151 | 152 |
| 152 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { | 153 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { |
| 153 CloseConnection("Unknown frame type received."); | 154 CloseConnection("Unknown frame type received."); |
| 154 return false; | 155 return false; |
| 155 } | 156 } |
| 156 | 157 |
| 157 // SpdyFramerDebugVisitorInterface implementation | 158 // SpdyFramerDebugVisitorInterface implementation |
| (...skipping 21 matching lines...) Expand all Loading... |
| 179 private: | 180 private: |
| 180 QuicHeadersStream* stream_; | 181 QuicHeadersStream* stream_; |
| 181 | 182 |
| 182 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor); | 183 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor); |
| 183 }; | 184 }; |
| 184 | 185 |
| 185 QuicHeadersStream::QuicHeadersStream(QuicSpdySession* session) | 186 QuicHeadersStream::QuicHeadersStream(QuicSpdySession* session) |
| 186 : ReliableQuicStream(kHeadersStreamId, session), | 187 : ReliableQuicStream(kHeadersStreamId, session), |
| 187 spdy_session_(session), | 188 spdy_session_(session), |
| 188 stream_id_(kInvalidStreamId), | 189 stream_id_(kInvalidStreamId), |
| 190 promised_stream_id_(kInvalidStreamId), |
| 189 fin_(false), | 191 fin_(false), |
| 190 frame_len_(0), | 192 frame_len_(0), |
| 191 measure_headers_hol_blocking_time_( | 193 measure_headers_hol_blocking_time_( |
| 192 FLAGS_quic_measure_headers_hol_blocking_time), | 194 FLAGS_quic_measure_headers_hol_blocking_time), |
| 195 supports_push_promise_( |
| 196 session->perspective() == Perspective::IS_CLIENT && |
| 197 FLAGS_quic_supports_push_promise), |
| 193 cur_max_timestamp_(QuicTime::Zero()), | 198 cur_max_timestamp_(QuicTime::Zero()), |
| 194 prev_max_timestamp_(QuicTime::Zero()), | 199 prev_max_timestamp_(QuicTime::Zero()), |
| 195 spdy_framer_(HTTP2), | 200 spdy_framer_(HTTP2), |
| 196 spdy_framer_visitor_(new SpdyFramerVisitor(this)) { | 201 spdy_framer_visitor_(new SpdyFramerVisitor(this)) { |
| 197 spdy_framer_.set_visitor(spdy_framer_visitor_.get()); | 202 spdy_framer_.set_visitor(spdy_framer_visitor_.get()); |
| 198 spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get()); | 203 spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get()); |
| 199 // The headers stream is exempt from connection level flow control. | 204 // The headers stream is exempt from connection level flow control. |
| 200 DisableConnectionFlowControlForThisStream(); | 205 DisableConnectionFlowControlForThisStream(); |
| 201 } | 206 } |
| 202 | 207 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 289 } | 294 } |
| 290 spdy_session_->OnStreamHeadersPriority(stream_id, priority); | 295 spdy_session_->OnStreamHeadersPriority(stream_id, priority); |
| 291 } else { | 296 } else { |
| 292 if (session()->perspective() == Perspective::IS_SERVER) { | 297 if (session()->perspective() == Perspective::IS_SERVER) { |
| 293 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, | 298 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, |
| 294 "Client must send priorities."); | 299 "Client must send priorities."); |
| 295 return; | 300 return; |
| 296 } | 301 } |
| 297 } | 302 } |
| 298 DCHECK_EQ(kInvalidStreamId, stream_id_); | 303 DCHECK_EQ(kInvalidStreamId, stream_id_); |
| 304 DCHECK_EQ(kInvalidStreamId, promised_stream_id_); |
| 299 stream_id_ = stream_id; | 305 stream_id_ = stream_id; |
| 300 fin_ = fin; | 306 fin_ = fin; |
| 301 } | 307 } |
| 302 | 308 |
| 309 void QuicHeadersStream::OnPushPromise(SpdyStreamId stream_id, |
| 310 SpdyStreamId promised_stream_id, |
| 311 bool end) { |
| 312 if (!supports_push_promise_) { |
| 313 CloseConnectionWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, |
| 314 "SPDY PUSH_PROMISE not supported."); |
| 315 return; |
| 316 } |
| 317 DCHECK_EQ(kInvalidStreamId, stream_id_); |
| 318 DCHECK_EQ(kInvalidStreamId, promised_stream_id_); |
| 319 stream_id_ = stream_id; |
| 320 promised_stream_id_ = promised_stream_id; |
| 321 } |
| 322 |
| 303 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id, | 323 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id, |
| 304 const char* header_data, | 324 const char* header_data, |
| 305 size_t len) { | 325 size_t len) { |
| 306 DCHECK_EQ(stream_id_, stream_id); | 326 DCHECK_EQ(stream_id_, stream_id); |
| 307 if (len == 0) { | 327 if (len == 0) { |
| 308 DCHECK_NE(0u, stream_id_); | 328 DCHECK_NE(0u, stream_id_); |
| 309 DCHECK_NE(0u, frame_len_); | 329 DCHECK_NE(0u, frame_len_); |
| 310 if (measure_headers_hol_blocking_time_) { | 330 if (measure_headers_hol_blocking_time_) { |
| 311 if (prev_max_timestamp_ > cur_max_timestamp_) { | 331 if (prev_max_timestamp_ > cur_max_timestamp_) { |
| 312 // prev_max_timestamp_ > cur_max_timestamp_ implies that | 332 // prev_max_timestamp_ > cur_max_timestamp_ implies that |
| 313 // headers from lower numbered streams actually came off the | 333 // headers from lower numbered streams actually came off the |
| 314 // wire after headers for the current stream, hence there was | 334 // wire after headers for the current stream, hence there was |
| 315 // HOL blocking. | 335 // HOL blocking. |
| 316 QuicTime::Delta delta(prev_max_timestamp_.Subtract(cur_max_timestamp_)); | 336 QuicTime::Delta delta(prev_max_timestamp_.Subtract(cur_max_timestamp_)); |
| 317 DVLOG(1) << "stream " << stream_id | 337 DVLOG(1) << "stream " << stream_id |
| 318 << ": Net.QuicSession.HeadersHOLBlockedTime " | 338 << ": Net.QuicSession.HeadersHOLBlockedTime " |
| 319 << delta.ToMilliseconds(); | 339 << delta.ToMilliseconds(); |
| 320 spdy_session_->OnHeadersHeadOfLineBlocking(delta); | 340 spdy_session_->OnHeadersHeadOfLineBlocking(delta); |
| 321 } | 341 } |
| 322 prev_max_timestamp_ = std::max(prev_max_timestamp_, cur_max_timestamp_); | 342 prev_max_timestamp_ = std::max(prev_max_timestamp_, cur_max_timestamp_); |
| 323 cur_max_timestamp_ = QuicTime::Zero(); | 343 cur_max_timestamp_ = QuicTime::Zero(); |
| 324 } | 344 } |
| 325 spdy_session_->OnStreamHeadersComplete(stream_id_, fin_, frame_len_); | 345 if (promised_stream_id_ == kInvalidStreamId) { |
| 346 spdy_session_->OnStreamHeadersComplete(stream_id_, fin_, frame_len_); |
| 347 } else { |
| 348 spdy_session_->OnPromiseHeadersComplete(stream_id_, promised_stream_id_, |
| 349 frame_len_); |
| 350 } |
| 326 // Reset state for the next frame. | 351 // Reset state for the next frame. |
| 352 promised_stream_id_ = kInvalidStreamId; |
| 327 stream_id_ = kInvalidStreamId; | 353 stream_id_ = kInvalidStreamId; |
| 328 fin_ = false; | 354 fin_ = false; |
| 329 frame_len_ = 0; | 355 frame_len_ = 0; |
| 330 } else { | 356 } else { |
| 331 spdy_session_->OnStreamHeaders(stream_id_, StringPiece(header_data, len)); | 357 if (promised_stream_id_ == kInvalidStreamId) { |
| 358 spdy_session_->OnStreamHeaders(stream_id_, StringPiece(header_data, len)); |
| 359 } else { |
| 360 spdy_session_->OnPromiseHeaders(stream_id_, |
| 361 StringPiece(header_data, len)); |
| 362 } |
| 332 } | 363 } |
| 333 } | 364 } |
| 334 | 365 |
| 335 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) { | 366 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) { |
| 336 frame_len_ += frame_len; | 367 frame_len_ += frame_len; |
| 337 } | 368 } |
| 338 | 369 |
| 339 bool QuicHeadersStream::IsConnected() { | 370 bool QuicHeadersStream::IsConnected() { |
| 340 return session()->connection()->connected(); | 371 return session()->connection()->connected(); |
| 341 } | 372 } |
| 342 | 373 |
| 343 } // namespace net | 374 } // namespace net |
| OLD | NEW |