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 OnError(SpdyFramer
* framer
) override
{
96 CloseConnection(base::StringPrintf(
97 "SPDY framing error: %s",
98 SpdyFramer::ErrorCodeToString(framer
->error_code())));
101 void OnDataFrameHeader(SpdyStreamId stream_id
,
104 CloseConnection("SPDY DATA frame received.");
107 void OnRstStream(SpdyStreamId stream_id
,
108 SpdyRstStreamStatus status
) override
{
109 CloseConnection("SPDY RST_STREAM frame received.");
112 void OnSetting(SpdySettingsIds id
, uint8 flags
, uint32 value
) override
{
113 CloseConnection("SPDY SETTINGS frame received.");
116 void OnSettingsAck() override
{
117 CloseConnection("SPDY SETTINGS frame received.");
120 void OnSettingsEnd() override
{
121 CloseConnection("SPDY SETTINGS frame received.");
124 void OnPing(SpdyPingId unique_id
, bool is_ack
) override
{
125 CloseConnection("SPDY PING frame received.");
128 void OnGoAway(SpdyStreamId last_accepted_stream_id
,
129 SpdyGoAwayStatus status
) override
{
130 CloseConnection("SPDY GOAWAY frame received.");
133 void OnHeaders(SpdyStreamId stream_id
,
135 SpdyPriority priority
,
138 if (spdy_version_
== SPDY3
) {
139 CloseConnection("SPDY HEADERS frame received.");
142 if (!stream_
->IsConnected()) {
146 stream_
->OnSynStream(stream_id
, priority
, fin
);
148 stream_
->OnSynReply(stream_id
, fin
);
152 void OnWindowUpdate(SpdyStreamId stream_id
,
153 uint32 delta_window_size
) override
{
154 CloseConnection("SPDY WINDOW_UPDATE frame received.");
157 void OnPushPromise(SpdyStreamId stream_id
,
158 SpdyStreamId promised_stream_id
,
160 LOG(DFATAL
) << "PUSH_PROMISE frame received from a SPDY/3 framer";
161 CloseConnection("SPDY PUSH_PROMISE frame received.");
164 void OnContinuation(SpdyStreamId stream_id
, bool end
) override
{
165 if (spdy_version_
== SPDY3
) {
166 LOG(DFATAL
) << "CONTINUATION frame received from a SPDY/3 framer";
167 CloseConnection("SPDY CONTINUATION frame received.");
171 bool OnUnknownFrame(SpdyStreamId stream_id
, int frame_type
) override
{
172 CloseConnection("Unknown frame type received.");
176 // SpdyFramerDebugVisitorInterface implementation
177 void OnSendCompressedFrame(SpdyStreamId stream_id
,
180 size_t frame_len
) override
{}
182 void OnReceiveCompressedFrame(SpdyStreamId stream_id
,
184 size_t frame_len
) override
{
185 if (stream_
->IsConnected()) {
186 stream_
->OnCompressedFrameSize(frame_len
);
191 void CloseConnection(const string
& details
) {
192 if (stream_
->IsConnected()) {
193 stream_
->CloseConnectionWithDetails(
194 QUIC_INVALID_HEADERS_STREAM_DATA
, details
);
199 SpdyMajorVersion spdy_version_
;
200 QuicHeadersStream
* stream_
;
202 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor
);
205 QuicHeadersStream::QuicHeadersStream(QuicSession
* session
)
206 : ReliableQuicStream(kHeadersStreamId
, session
),
207 stream_id_(kInvalidStreamId
),
210 InitializeFramer(session
->connection()->version());
211 // The headers stream is exempt from connection level flow control.
212 DisableConnectionFlowControlForThisStream();
215 QuicHeadersStream::~QuicHeadersStream() {}
217 size_t QuicHeadersStream::WriteHeaders(
218 QuicStreamId stream_id
,
219 const SpdyHeaderBlock
& headers
,
221 QuicPriority priority
,
222 QuicAckNotifier::DelegateInterface
* ack_notifier_delegate
) {
223 scoped_ptr
<SpdySerializedFrame
> frame
;
224 if (spdy_framer_
->protocol_version() == SPDY3
) {
225 if (session()->is_server()) {
226 SpdySynReplyIR
syn_reply(stream_id
);
227 syn_reply
.set_name_value_block(headers
);
228 syn_reply
.set_fin(fin
);
229 frame
.reset(spdy_framer_
->SerializeFrame(syn_reply
));
231 SpdySynStreamIR
syn_stream(stream_id
);
232 syn_stream
.set_name_value_block(headers
);
233 syn_stream
.set_fin(fin
);
234 syn_stream
.set_priority(priority
);
235 frame
.reset(spdy_framer_
->SerializeFrame(syn_stream
));
238 SpdyHeadersIR
headers_frame(stream_id
);
239 headers_frame
.set_name_value_block(headers
);
240 headers_frame
.set_fin(fin
);
241 if (!session()->is_server()) {
242 headers_frame
.set_has_priority(true);
243 headers_frame
.set_priority(priority
);
245 frame
.reset(spdy_framer_
->SerializeFrame(headers_frame
));
247 WriteOrBufferData(StringPiece(frame
->data(), frame
->size()), false,
248 ack_notifier_delegate
);
249 return frame
->size();
252 uint32
QuicHeadersStream::ProcessRawData(const char* data
,
254 return spdy_framer_
->ProcessInput(data
, data_len
);
257 QuicPriority
QuicHeadersStream::EffectivePriority() const { return 0; }
259 void QuicHeadersStream::OnSuccessfulVersionNegotiation(QuicVersion version
) {
260 InitializeFramer(version
);
263 void QuicHeadersStream::InitializeFramer(QuicVersion version
) {
264 SpdyMajorVersion spdy_version
= version
> QUIC_VERSION_23
? SPDY4
: SPDY3
;
265 if (spdy_framer_
.get() != nullptr &&
266 spdy_framer_
->protocol_version() == spdy_version
) {
269 spdy_framer_
.reset(new SpdyFramer(spdy_version
));
270 spdy_framer_visitor_
.reset(new SpdyFramerVisitor(spdy_version
, this));
271 spdy_framer_
->set_visitor(spdy_framer_visitor_
.get());
272 spdy_framer_
->set_debug_visitor(spdy_framer_visitor_
.get());
275 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id
,
276 SpdyPriority priority
,
278 if (!session()->is_server()) {
279 CloseConnectionWithDetails(
280 QUIC_INVALID_HEADERS_STREAM_DATA
,
281 "SPDY SYN_STREAM frame received at the client");
284 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
285 stream_id_
= stream_id
;
287 session()->OnStreamHeadersPriority(stream_id
, priority
);
290 void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id
, bool fin
) {
291 if (session()->is_server()) {
292 CloseConnectionWithDetails(
293 QUIC_INVALID_HEADERS_STREAM_DATA
,
294 "SPDY SYN_REPLY frame received at the server");
297 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
298 stream_id_
= stream_id
;
302 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id
,
303 const char* header_data
,
305 DCHECK_EQ(stream_id_
, stream_id
);
307 DCHECK_NE(0u, stream_id_
);
308 DCHECK_NE(0u, frame_len_
);
309 session()->OnStreamHeadersComplete(stream_id_
, fin_
, frame_len_
);
310 // Reset state for the next frame.
311 stream_id_
= kInvalidStreamId
;
315 session()->OnStreamHeaders(stream_id_
, StringPiece(header_data
, len
));
319 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len
) {
320 if (spdy_framer_
->protocol_version() == SPDY3
) {
321 // SPDY/3 headers always fit into a single frame, so the previous headers
322 // should be completely processed when a new frame is received.
323 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
324 DCHECK_EQ(0u, frame_len_
);
326 frame_len_
+= frame_len
;
329 bool QuicHeadersStream::IsConnected() {
330 return session()->connection()->connected();