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 "base/strings/stringprintf.h"
8 #include "net/quic/quic_spdy_session.h"
10 using base::StringPiece
;
17 const QuicStreamId kInvalidStreamId
= 0;
21 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to
22 // the QuicDataStream, and closes the connection if any unexpected frames
24 class QuicHeadersStream::SpdyFramerVisitor
25 : public SpdyFramerVisitorInterface
,
26 public SpdyFramerDebugVisitorInterface
{
28 SpdyFramerVisitor(SpdyMajorVersion spdy_version
, QuicHeadersStream
* stream
)
29 : spdy_version_(spdy_version
), stream_(stream
) {}
31 // SpdyFramerVisitorInterface implementation
32 void OnSynStream(SpdyStreamId stream_id
,
33 SpdyStreamId associated_stream_id
,
34 SpdyPriority priority
,
36 bool unidirectional
) override
{
37 CloseConnection("SPDY SYN_STREAM frame received.");
40 void OnSynReply(SpdyStreamId stream_id
, bool fin
) override
{
41 CloseConnection("SPDY SYN_REPLY frame received.");
44 bool OnControlFrameHeaderData(SpdyStreamId stream_id
,
45 const char* header_data
,
46 size_t len
) override
{
47 if (!stream_
->IsConnected()) {
50 stream_
->OnControlFrameHeaderData(stream_id
, header_data
, len
);
54 void OnStreamFrameData(SpdyStreamId stream_id
,
58 if (fin
&& len
== 0) {
59 // The framer invokes OnStreamFrameData with zero-length data and
60 // fin = true after processing a SYN_STREAM or SYN_REPLY frame
61 // that had the fin bit set.
64 CloseConnection("SPDY DATA frame received.");
67 void OnStreamPadding(SpdyStreamId stream_id
, size_t len
) override
{
68 CloseConnection("SPDY frame padding received.");
71 void OnError(SpdyFramer
* framer
) override
{
72 CloseConnection(base::StringPrintf(
73 "SPDY framing error: %s",
74 SpdyFramer::ErrorCodeToString(framer
->error_code())));
77 void OnDataFrameHeader(SpdyStreamId stream_id
,
80 CloseConnection("SPDY DATA frame received.");
83 void OnRstStream(SpdyStreamId stream_id
,
84 SpdyRstStreamStatus status
) override
{
85 CloseConnection("SPDY RST_STREAM frame received.");
88 void OnSetting(SpdySettingsIds id
, uint8 flags
, uint32 value
) override
{
89 CloseConnection("SPDY SETTINGS frame received.");
92 void OnSettingsAck() override
{
93 CloseConnection("SPDY SETTINGS frame received.");
96 void OnSettingsEnd() override
{
97 CloseConnection("SPDY SETTINGS frame received.");
100 void OnPing(SpdyPingId unique_id
, bool is_ack
) override
{
101 CloseConnection("SPDY PING frame received.");
104 void OnGoAway(SpdyStreamId last_accepted_stream_id
,
105 SpdyGoAwayStatus status
) override
{
106 CloseConnection("SPDY GOAWAY frame received.");
109 void OnHeaders(SpdyStreamId stream_id
,
111 SpdyPriority priority
,
112 SpdyStreamId parent_stream_id
,
116 if (!stream_
->IsConnected()) {
120 stream_
->OnSynStream(stream_id
, priority
, fin
);
122 stream_
->OnSynReply(stream_id
, fin
);
126 void OnWindowUpdate(SpdyStreamId stream_id
,
127 uint32 delta_window_size
) override
{
128 CloseConnection("SPDY WINDOW_UPDATE frame received.");
131 void OnPushPromise(SpdyStreamId stream_id
,
132 SpdyStreamId promised_stream_id
,
134 CloseConnection("SPDY PUSH_PROMISE frame received.");
137 void OnContinuation(SpdyStreamId stream_id
, bool end
) override
{
140 bool OnUnknownFrame(SpdyStreamId stream_id
, int frame_type
) override
{
141 CloseConnection("Unknown frame type received.");
145 // SpdyFramerDebugVisitorInterface implementation
146 void OnSendCompressedFrame(SpdyStreamId stream_id
,
149 size_t frame_len
) override
{}
151 void OnReceiveCompressedFrame(SpdyStreamId stream_id
,
153 size_t frame_len
) override
{
154 if (stream_
->IsConnected()) {
155 stream_
->OnCompressedFrameSize(frame_len
);
160 void CloseConnection(const string
& details
) {
161 if (stream_
->IsConnected()) {
162 stream_
->CloseConnectionWithDetails(
163 QUIC_INVALID_HEADERS_STREAM_DATA
, details
);
168 SpdyMajorVersion spdy_version_
;
169 QuicHeadersStream
* stream_
;
171 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor
);
174 QuicHeadersStream::QuicHeadersStream(QuicSpdySession
* session
)
175 : ReliableQuicStream(kHeadersStreamId
, session
),
176 spdy_session_(session
),
177 stream_id_(kInvalidStreamId
),
181 spdy_framer_visitor_(new SpdyFramerVisitor(HTTP2
, this)) {
182 spdy_framer_
.set_visitor(spdy_framer_visitor_
.get());
183 spdy_framer_
.set_debug_visitor(spdy_framer_visitor_
.get());
184 // The headers stream is exempt from connection level flow control.
185 DisableConnectionFlowControlForThisStream();
188 QuicHeadersStream::~QuicHeadersStream() {}
190 size_t QuicHeadersStream::WriteHeaders(
191 QuicStreamId stream_id
,
192 const SpdyHeaderBlock
& headers
,
194 QuicPriority priority
,
195 QuicAckNotifier::DelegateInterface
* ack_notifier_delegate
) {
196 SpdyHeadersIR
headers_frame(stream_id
);
197 headers_frame
.set_name_value_block(headers
);
198 headers_frame
.set_fin(fin
);
199 if (session()->perspective() == Perspective::IS_CLIENT
) {
200 headers_frame
.set_has_priority(true);
201 headers_frame
.set_priority(priority
);
203 scoped_ptr
<SpdySerializedFrame
> frame(
204 spdy_framer_
.SerializeFrame(headers_frame
));
205 WriteOrBufferData(StringPiece(frame
->data(), frame
->size()), false,
206 ack_notifier_delegate
);
207 return frame
->size();
210 uint32
QuicHeadersStream::ProcessRawData(const char* data
,
212 return spdy_framer_
.ProcessInput(data
, data_len
);
215 QuicPriority
QuicHeadersStream::EffectivePriority() const { return 0; }
217 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id
,
218 SpdyPriority priority
,
220 if (session()->perspective() == Perspective::IS_CLIENT
) {
221 CloseConnectionWithDetails(
222 QUIC_INVALID_HEADERS_STREAM_DATA
,
223 "SPDY SYN_STREAM frame received at the client");
226 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
227 stream_id_
= stream_id
;
229 spdy_session_
->OnStreamHeadersPriority(stream_id
, priority
);
232 void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id
, bool fin
) {
233 if (session()->perspective() == Perspective::IS_SERVER
) {
234 CloseConnectionWithDetails(
235 QUIC_INVALID_HEADERS_STREAM_DATA
,
236 "SPDY SYN_REPLY frame received at the server");
239 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
240 stream_id_
= stream_id
;
244 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id
,
245 const char* header_data
,
247 DCHECK_EQ(stream_id_
, stream_id
);
249 DCHECK_NE(0u, stream_id_
);
250 DCHECK_NE(0u, frame_len_
);
251 spdy_session_
->OnStreamHeadersComplete(stream_id_
, fin_
, frame_len_
);
252 // Reset state for the next frame.
253 stream_id_
= kInvalidStreamId
;
257 spdy_session_
->OnStreamHeaders(stream_id_
, StringPiece(header_data
, len
));
261 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len
) {
262 frame_len_
+= frame_len
;
265 bool QuicHeadersStream::IsConnected() {
266 return session()->connection()->connected();