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_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 if (spdy_version_
!= SPDY3
) {
38 CloseConnection("SPDY SYN_STREAM frame received.");
42 if (!stream_
->IsConnected()) {
46 if (associated_stream_id
!= 0) {
47 CloseConnection("associated_stream_id != 0");
51 if (unidirectional
!= 0) {
52 CloseConnection("unidirectional != 0");
56 stream_
->OnSynStream(stream_id
, priority
, fin
);
59 void OnSynReply(SpdyStreamId stream_id
, bool fin
) override
{
60 if (spdy_version_
!= SPDY3
) {
61 CloseConnection("SPDY SYN_REPLY frame received.");
65 if (!stream_
->IsConnected()) {
69 stream_
->OnSynReply(stream_id
, fin
);
72 bool OnControlFrameHeaderData(SpdyStreamId stream_id
,
73 const char* header_data
,
74 size_t len
) override
{
75 if (!stream_
->IsConnected()) {
78 stream_
->OnControlFrameHeaderData(stream_id
, header_data
, len
);
82 void OnStreamFrameData(SpdyStreamId stream_id
,
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.
92 CloseConnection("SPDY DATA frame received.");
95 void OnStreamPadding(SpdyStreamId stream_id
, size_t len
) override
{
96 CloseConnection("SPDY frame padding received.");
99 void OnError(SpdyFramer
* framer
) override
{
100 CloseConnection(base::StringPrintf(
101 "SPDY framing error: %s",
102 SpdyFramer::ErrorCodeToString(framer
->error_code())));
105 void OnDataFrameHeader(SpdyStreamId stream_id
,
108 CloseConnection("SPDY DATA frame received.");
111 void OnRstStream(SpdyStreamId stream_id
,
112 SpdyRstStreamStatus status
) override
{
113 CloseConnection("SPDY RST_STREAM frame received.");
116 void OnSetting(SpdySettingsIds id
, uint8 flags
, uint32 value
) override
{
117 CloseConnection("SPDY SETTINGS frame received.");
120 void OnSettingsAck() override
{
121 CloseConnection("SPDY SETTINGS frame received.");
124 void OnSettingsEnd() override
{
125 CloseConnection("SPDY SETTINGS frame received.");
128 void OnPing(SpdyPingId unique_id
, bool is_ack
) override
{
129 CloseConnection("SPDY PING frame received.");
132 void OnGoAway(SpdyStreamId last_accepted_stream_id
,
133 SpdyGoAwayStatus status
) override
{
134 CloseConnection("SPDY GOAWAY frame received.");
137 void OnHeaders(SpdyStreamId stream_id
,
139 SpdyPriority priority
,
142 if (spdy_version_
== SPDY3
) {
143 CloseConnection("SPDY HEADERS frame received.");
146 if (!stream_
->IsConnected()) {
150 stream_
->OnSynStream(stream_id
, priority
, fin
);
152 stream_
->OnSynReply(stream_id
, fin
);
156 void OnWindowUpdate(SpdyStreamId stream_id
,
157 uint32 delta_window_size
) override
{
158 CloseConnection("SPDY WINDOW_UPDATE frame received.");
161 void OnPushPromise(SpdyStreamId stream_id
,
162 SpdyStreamId promised_stream_id
,
164 LOG(DFATAL
) << "PUSH_PROMISE frame received from a SPDY/3 framer";
165 CloseConnection("SPDY PUSH_PROMISE frame received.");
168 void OnContinuation(SpdyStreamId stream_id
, bool end
) override
{
169 if (spdy_version_
== SPDY3
) {
170 LOG(DFATAL
) << "CONTINUATION frame received from a SPDY/3 framer";
171 CloseConnection("SPDY CONTINUATION frame received.");
175 bool OnUnknownFrame(SpdyStreamId stream_id
, int frame_type
) override
{
176 CloseConnection("Unknown frame type received.");
180 // SpdyFramerDebugVisitorInterface implementation
181 void OnSendCompressedFrame(SpdyStreamId stream_id
,
184 size_t frame_len
) override
{}
186 void OnReceiveCompressedFrame(SpdyStreamId stream_id
,
188 size_t frame_len
) override
{
189 if (stream_
->IsConnected()) {
190 stream_
->OnCompressedFrameSize(frame_len
);
195 void CloseConnection(const string
& details
) {
196 if (stream_
->IsConnected()) {
197 stream_
->CloseConnectionWithDetails(
198 QUIC_INVALID_HEADERS_STREAM_DATA
, details
);
203 SpdyMajorVersion spdy_version_
;
204 QuicHeadersStream
* stream_
;
206 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor
);
209 QuicHeadersStream::QuicHeadersStream(QuicSession
* session
)
210 : ReliableQuicStream(kHeadersStreamId
, session
),
211 stream_id_(kInvalidStreamId
),
214 InitializeFramer(session
->connection()->version());
215 // The headers stream is exempt from connection level flow control.
216 DisableConnectionFlowControlForThisStream();
219 QuicHeadersStream::~QuicHeadersStream() {}
221 size_t QuicHeadersStream::WriteHeaders(
222 QuicStreamId stream_id
,
223 const SpdyHeaderBlock
& headers
,
225 QuicPriority priority
,
226 QuicAckNotifier::DelegateInterface
* ack_notifier_delegate
) {
227 scoped_ptr
<SpdySerializedFrame
> frame
;
228 if (spdy_framer_
->protocol_version() == SPDY3
) {
229 if (session()->perspective() == Perspective::IS_SERVER
) {
230 SpdySynReplyIR
syn_reply(stream_id
);
231 syn_reply
.set_name_value_block(headers
);
232 syn_reply
.set_fin(fin
);
233 frame
.reset(spdy_framer_
->SerializeFrame(syn_reply
));
235 SpdySynStreamIR
syn_stream(stream_id
);
236 syn_stream
.set_name_value_block(headers
);
237 syn_stream
.set_fin(fin
);
238 syn_stream
.set_priority(priority
);
239 frame
.reset(spdy_framer_
->SerializeFrame(syn_stream
));
242 SpdyHeadersIR
headers_frame(stream_id
);
243 headers_frame
.set_name_value_block(headers
);
244 headers_frame
.set_fin(fin
);
245 if (session()->perspective() == Perspective::IS_CLIENT
) {
246 headers_frame
.set_has_priority(true);
247 headers_frame
.set_priority(priority
);
249 frame
.reset(spdy_framer_
->SerializeFrame(headers_frame
));
251 WriteOrBufferData(StringPiece(frame
->data(), frame
->size()), false,
252 ack_notifier_delegate
);
253 return frame
->size();
256 uint32
QuicHeadersStream::ProcessRawData(const char* data
,
258 return spdy_framer_
->ProcessInput(data
, data_len
);
261 QuicPriority
QuicHeadersStream::EffectivePriority() const { return 0; }
263 void QuicHeadersStream::OnSuccessfulVersionNegotiation(QuicVersion version
) {
264 InitializeFramer(version
);
267 void QuicHeadersStream::InitializeFramer(QuicVersion version
) {
268 SpdyMajorVersion spdy_version
= version
> QUIC_VERSION_23
? SPDY4
: SPDY3
;
269 if (spdy_framer_
.get() != nullptr &&
270 spdy_framer_
->protocol_version() == spdy_version
) {
273 spdy_framer_
.reset(new SpdyFramer(spdy_version
));
274 spdy_framer_visitor_
.reset(new SpdyFramerVisitor(spdy_version
, this));
275 spdy_framer_
->set_visitor(spdy_framer_visitor_
.get());
276 spdy_framer_
->set_debug_visitor(spdy_framer_visitor_
.get());
279 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id
,
280 SpdyPriority priority
,
282 if (session()->perspective() == Perspective::IS_CLIENT
) {
283 CloseConnectionWithDetails(
284 QUIC_INVALID_HEADERS_STREAM_DATA
,
285 "SPDY SYN_STREAM frame received at the client");
288 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
289 stream_id_
= stream_id
;
291 session()->OnStreamHeadersPriority(stream_id
, priority
);
294 void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id
, bool fin
) {
295 if (session()->perspective() == Perspective::IS_SERVER
) {
296 CloseConnectionWithDetails(
297 QUIC_INVALID_HEADERS_STREAM_DATA
,
298 "SPDY SYN_REPLY frame received at the server");
301 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
302 stream_id_
= stream_id
;
306 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id
,
307 const char* header_data
,
309 DCHECK_EQ(stream_id_
, stream_id
);
311 DCHECK_NE(0u, stream_id_
);
312 DCHECK_NE(0u, frame_len_
);
313 session()->OnStreamHeadersComplete(stream_id_
, fin_
, frame_len_
);
314 // Reset state for the next frame.
315 stream_id_
= kInvalidStreamId
;
319 session()->OnStreamHeaders(stream_id_
, StringPiece(header_data
, len
));
323 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len
) {
324 if (spdy_framer_
->protocol_version() == SPDY3
) {
325 // SPDY/3 headers always fit into a single frame, so the previous headers
326 // should be completely processed when a new frame is received.
327 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
328 DCHECK_EQ(0u, frame_len_
);
330 frame_len_
+= frame_len
;
333 bool QuicHeadersStream::IsConnected() {
334 return session()->connection()->connected();