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.
5 #include "net/quic/quic_headers_stream.h"
7 #include "net/quic/quic_session.h"
9 using base::StringPiece
;
15 const QuicStreamId kInvalidStreamId
= 0;
19 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to
20 // the QuicDataStream, and closes the connection if any unexpected frames
22 class QuicHeadersStream::SpdyFramerVisitor
23 : public SpdyFramerVisitorInterface
,
24 public SpdyFramerDebugVisitorInterface
{
26 explicit SpdyFramerVisitor(QuicHeadersStream
* stream
) : stream_(stream
) {}
28 // SpdyFramerVisitorInterface implementation
29 void OnSynStream(SpdyStreamId stream_id
,
30 SpdyStreamId associated_stream_id
,
31 SpdyPriority priority
,
33 bool unidirectional
) override
{
34 if (!stream_
->IsConnected()) {
38 if (associated_stream_id
!= 0) {
39 CloseConnection("associated_stream_id != 0");
43 if (unidirectional
!= 0) {
44 CloseConnection("unidirectional != 0");
48 stream_
->OnSynStream(stream_id
, priority
, fin
);
51 void OnSynReply(SpdyStreamId stream_id
, bool fin
) override
{
52 if (!stream_
->IsConnected()) {
56 stream_
->OnSynReply(stream_id
, fin
);
59 bool OnControlFrameHeaderData(SpdyStreamId stream_id
,
60 const char* header_data
,
61 size_t len
) override
{
62 if (!stream_
->IsConnected()) {
65 stream_
->OnControlFrameHeaderData(stream_id
, header_data
, len
);
69 void OnStreamFrameData(SpdyStreamId stream_id
,
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.
79 CloseConnection("SPDY DATA frame received.");
82 void OnError(SpdyFramer
* framer
) override
{
83 CloseConnection("SPDY framing error.");
86 void OnDataFrameHeader(SpdyStreamId stream_id
,
89 CloseConnection("SPDY DATA frame received.");
92 void OnRstStream(SpdyStreamId stream_id
,
93 SpdyRstStreamStatus status
) override
{
94 CloseConnection("SPDY RST_STREAM frame received.");
97 void OnSetting(SpdySettingsIds id
, uint8 flags
, uint32 value
) override
{
98 CloseConnection("SPDY SETTINGS frame received.");
101 void OnSettingsAck() override
{
102 CloseConnection("SPDY SETTINGS frame received.");
105 void OnSettingsEnd() override
{
106 CloseConnection("SPDY SETTINGS frame received.");
109 void OnPing(SpdyPingId unique_id
, bool is_ack
) override
{
110 CloseConnection("SPDY PING frame received.");
113 void OnGoAway(SpdyStreamId last_accepted_stream_id
,
114 SpdyGoAwayStatus status
) override
{
115 CloseConnection("SPDY GOAWAY frame received.");
118 void OnHeaders(SpdyStreamId stream_id
, bool fin
, bool end
) override
{
119 CloseConnection("SPDY HEADERS frame received.");
122 void OnWindowUpdate(SpdyStreamId stream_id
,
123 uint32 delta_window_size
) override
{
124 CloseConnection("SPDY WINDOW_UPDATE frame received.");
127 void OnPushPromise(SpdyStreamId stream_id
,
128 SpdyStreamId promised_stream_id
,
130 LOG(DFATAL
) << "PUSH_PROMISE frame received from a SPDY/3 framer";
131 CloseConnection("SPDY PUSH_PROMISE frame received.");
134 void OnContinuation(SpdyStreamId stream_id
, bool end
) override
{
135 CloseConnection("SPDY CONTINUATION frame received.");
138 bool OnUnknownFrame(SpdyStreamId stream_id
, int frame_type
) override
{
139 CloseConnection("SPDY unknown frame received.");
143 // SpdyFramerDebugVisitorInterface implementation
144 void OnSendCompressedFrame(SpdyStreamId stream_id
,
147 size_t frame_len
) override
{}
149 void OnReceiveCompressedFrame(SpdyStreamId stream_id
,
151 size_t frame_len
) override
{
152 if (stream_
->IsConnected()) {
153 stream_
->OnCompressedFrameSize(frame_len
);
158 void CloseConnection(const string
& details
) {
159 if (stream_
->IsConnected()) {
160 stream_
->CloseConnectionWithDetails(
161 QUIC_INVALID_HEADERS_STREAM_DATA
, details
);
166 QuicHeadersStream
* stream_
;
168 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor
);
171 QuicHeadersStream::QuicHeadersStream(QuicSession
* session
)
172 : ReliableQuicStream(kHeadersStreamId
, session
),
173 stream_id_(kInvalidStreamId
),
177 spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
178 spdy_framer_
.set_visitor(spdy_framer_visitor_
.get());
179 spdy_framer_
.set_debug_visitor(spdy_framer_visitor_
.get());
180 if (version() < QUIC_VERSION_21
) {
181 // Prior to QUIC_VERSION_21 the headers stream is not subject to any flow
183 DisableFlowControl();
185 // The headers stream is exempt from connection level flow control.
186 DisableConnectionFlowControlForThisStream();
189 QuicHeadersStream::~QuicHeadersStream() {}
191 size_t QuicHeadersStream::WriteHeaders(
192 QuicStreamId stream_id
,
193 const SpdyHeaderBlock
& headers
,
195 QuicAckNotifier::DelegateInterface
* ack_notifier_delegate
) {
196 scoped_ptr
<SpdySerializedFrame
> frame
;
197 if (session()->is_server()) {
198 SpdySynReplyIR
syn_reply(stream_id
);
199 syn_reply
.set_name_value_block(headers
);
200 syn_reply
.set_fin(fin
);
201 frame
.reset(spdy_framer_
.SerializeFrame(syn_reply
));
203 SpdySynStreamIR
syn_stream(stream_id
);
204 syn_stream
.set_name_value_block(headers
);
205 syn_stream
.set_fin(fin
);
206 frame
.reset(spdy_framer_
.SerializeFrame(syn_stream
));
208 WriteOrBufferData(StringPiece(frame
->data(), frame
->size()), false,
209 ack_notifier_delegate
);
210 return frame
->size();
213 uint32
QuicHeadersStream::ProcessRawData(const char* data
,
215 return spdy_framer_
.ProcessInput(data
, data_len
);
218 QuicPriority
QuicHeadersStream::EffectivePriority() const { return 0; }
220 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id
,
221 SpdyPriority priority
,
223 if (!session()->is_server()) {
224 CloseConnectionWithDetails(
225 QUIC_INVALID_HEADERS_STREAM_DATA
,
226 "SPDY SYN_STREAM frame received at the client");
229 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
230 stream_id_
= stream_id
;
232 session()->OnStreamHeadersPriority(stream_id
, priority
);
235 void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id
, bool fin
) {
236 if (session()->is_server()) {
237 CloseConnectionWithDetails(
238 QUIC_INVALID_HEADERS_STREAM_DATA
,
239 "SPDY SYN_REPLY frame received at the server");
242 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
243 stream_id_
= stream_id
;
247 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id
,
248 const char* header_data
,
250 DCHECK_EQ(stream_id_
, stream_id
);
252 DCHECK_NE(0u, stream_id_
);
253 DCHECK_NE(0u, frame_len_
);
254 session()->OnStreamHeadersComplete(stream_id_
, fin_
, frame_len_
);
255 // Reset state for the next frame.
256 stream_id_
= kInvalidStreamId
;
260 session()->OnStreamHeaders(stream_id_
, StringPiece(header_data
, len
));
264 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len
) {
265 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
266 DCHECK_EQ(0u, frame_len_
);
267 frame_len_
= frame_len
;
270 bool QuicHeadersStream::IsConnected() {
271 return session()->connection()->connected();