Index: net/quic/quic_headers_stream.cc |
diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc |
index 369a34898846432c2883db6d1162e8187d8d5c79..b40142db16605874f568b555e1d94f0dfe3643b9 100644 |
--- a/net/quic/quic_headers_stream.cc |
+++ b/net/quic/quic_headers_stream.cc |
@@ -25,7 +25,8 @@ class QuicHeadersStream::SpdyFramerVisitor |
: public SpdyFramerVisitorInterface, |
public SpdyFramerDebugVisitorInterface { |
public: |
- explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {} |
+ SpdyFramerVisitor(SpdyMajorVersion spdy_version, QuicHeadersStream* stream) |
+ : spdy_version_(spdy_version), stream_(stream) {} |
// SpdyFramerVisitorInterface implementation |
void OnSynStream(SpdyStreamId stream_id, |
@@ -33,6 +34,11 @@ class QuicHeadersStream::SpdyFramerVisitor |
SpdyPriority priority, |
bool fin, |
bool unidirectional) override { |
+ if (spdy_version_ != SPDY3) { |
+ CloseConnection("SPDY SYN_STREAM frame received."); |
+ return; |
+ } |
+ |
if (!stream_->IsConnected()) { |
return; |
} |
@@ -51,6 +57,11 @@ class QuicHeadersStream::SpdyFramerVisitor |
} |
void OnSynReply(SpdyStreamId stream_id, bool fin) override { |
+ if (spdy_version_ != SPDY3) { |
+ CloseConnection("SPDY SYN_REPLY frame received."); |
+ return; |
+ } |
+ |
if (!stream_->IsConnected()) { |
return; |
} |
@@ -124,7 +135,18 @@ class QuicHeadersStream::SpdyFramerVisitor |
SpdyPriority priority, |
bool fin, |
bool end) override { |
- CloseConnection("SPDY HEADERS frame received."); |
+ if (spdy_version_ == SPDY3) { |
+ CloseConnection("SPDY HEADERS frame received."); |
+ return; |
+ } |
+ if (!stream_->IsConnected()) { |
+ return; |
+ } |
+ if (has_priority) { |
+ stream_->OnSynStream(stream_id, priority, fin); |
+ } else { |
+ stream_->OnSynReply(stream_id, fin); |
+ } |
} |
void OnWindowUpdate(SpdyStreamId stream_id, |
@@ -140,7 +162,10 @@ class QuicHeadersStream::SpdyFramerVisitor |
} |
void OnContinuation(SpdyStreamId stream_id, bool end) override { |
- CloseConnection("SPDY CONTINUATION frame received."); |
+ if (spdy_version_ == SPDY3) { |
+ LOG(DFATAL) << "CONTINUATION frame received from a SPDY/3 framer"; |
+ CloseConnection("SPDY CONTINUATION frame received."); |
+ } |
} |
bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { |
@@ -171,6 +196,7 @@ class QuicHeadersStream::SpdyFramerVisitor |
} |
private: |
+ SpdyMajorVersion spdy_version_; |
QuicHeadersStream* stream_; |
DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor); |
@@ -180,11 +206,8 @@ QuicHeadersStream::QuicHeadersStream(QuicSession* session) |
: ReliableQuicStream(kHeadersStreamId, session), |
stream_id_(kInvalidStreamId), |
fin_(false), |
- frame_len_(0), |
- spdy_framer_(SPDY3), |
- spdy_framer_visitor_(new SpdyFramerVisitor(this)) { |
- spdy_framer_.set_visitor(spdy_framer_visitor_.get()); |
- spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get()); |
+ frame_len_(0) { |
+ InitializeFramer(session->connection()->version()); |
// The headers stream is exempt from connection level flow control. |
DisableConnectionFlowControlForThisStream(); |
} |
@@ -195,18 +218,31 @@ size_t QuicHeadersStream::WriteHeaders( |
QuicStreamId stream_id, |
const SpdyHeaderBlock& headers, |
bool fin, |
+ QuicPriority priority, |
QuicAckNotifier::DelegateInterface* ack_notifier_delegate) { |
scoped_ptr<SpdySerializedFrame> frame; |
- if (session()->is_server()) { |
- SpdySynReplyIR syn_reply(stream_id); |
- syn_reply.set_name_value_block(headers); |
- syn_reply.set_fin(fin); |
- frame.reset(spdy_framer_.SerializeFrame(syn_reply)); |
+ if (spdy_framer_->protocol_version() == SPDY3) { |
+ if (session()->is_server()) { |
+ SpdySynReplyIR syn_reply(stream_id); |
+ syn_reply.set_name_value_block(headers); |
+ syn_reply.set_fin(fin); |
+ frame.reset(spdy_framer_->SerializeFrame(syn_reply)); |
+ } else { |
+ SpdySynStreamIR syn_stream(stream_id); |
+ syn_stream.set_name_value_block(headers); |
+ syn_stream.set_fin(fin); |
+ syn_stream.set_priority(priority); |
+ frame.reset(spdy_framer_->SerializeFrame(syn_stream)); |
+ } |
} else { |
- SpdySynStreamIR syn_stream(stream_id); |
- syn_stream.set_name_value_block(headers); |
- syn_stream.set_fin(fin); |
- frame.reset(spdy_framer_.SerializeFrame(syn_stream)); |
+ SpdyHeadersIR headers_frame(stream_id); |
+ headers_frame.set_name_value_block(headers); |
+ headers_frame.set_fin(fin); |
+ if (!session()->is_server()) { |
+ headers_frame.set_has_priority(true); |
+ headers_frame.set_priority(priority); |
+ } |
+ frame.reset(spdy_framer_->SerializeFrame(headers_frame)); |
} |
WriteOrBufferData(StringPiece(frame->data(), frame->size()), false, |
ack_notifier_delegate); |
@@ -215,11 +251,27 @@ size_t QuicHeadersStream::WriteHeaders( |
uint32 QuicHeadersStream::ProcessRawData(const char* data, |
uint32 data_len) { |
- return spdy_framer_.ProcessInput(data, data_len); |
+ return spdy_framer_->ProcessInput(data, data_len); |
} |
QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; } |
+void QuicHeadersStream::OnSuccessfulVersionNegotiation(QuicVersion version) { |
+ InitializeFramer(version); |
+} |
+ |
+void QuicHeadersStream::InitializeFramer(QuicVersion version) { |
+ SpdyMajorVersion spdy_version = version > QUIC_VERSION_23 ? SPDY4 : SPDY3; |
+ if (spdy_framer_.get() != nullptr && |
+ spdy_framer_->protocol_version() == spdy_version) { |
+ return; |
+ } |
+ spdy_framer_.reset(new SpdyFramer(spdy_version)); |
+ spdy_framer_visitor_.reset(new SpdyFramerVisitor(spdy_version, this)); |
+ spdy_framer_->set_visitor(spdy_framer_visitor_.get()); |
+ spdy_framer_->set_debug_visitor(spdy_framer_visitor_.get()); |
+} |
+ |
void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id, |
SpdyPriority priority, |
bool fin) { |
@@ -265,9 +317,13 @@ void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id, |
} |
void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) { |
- DCHECK_EQ(kInvalidStreamId, stream_id_); |
- DCHECK_EQ(0u, frame_len_); |
- frame_len_ = frame_len; |
+ if (spdy_framer_->protocol_version() == SPDY3) { |
+ // SPDY/3 headers always fit into a single frame, so the previous headers |
+ // should be completely processed when a new frame is received. |
+ DCHECK_EQ(kInvalidStreamId, stream_id_); |
+ DCHECK_EQ(0u, frame_len_); |
+ } |
+ frame_len_ += frame_len; |
} |
bool QuicHeadersStream::IsConnected() { |