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"
8 #include "net/quic/quic_spdy_decompressor.h"
10 using base::StringPiece
;
16 const QuicStreamId kInvalidStreamId
= 0;
20 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to
21 // the QuicDataStream, and closes the connection if any unexpected frames
23 class QuicHeadersStream::SpdyFramerVisitor
24 : public SpdyFramerVisitorInterface
,
25 public SpdyFramerDebugVisitorInterface
{
27 explicit SpdyFramerVisitor(QuicHeadersStream
* stream
) : stream_(stream
) {}
29 // SpdyFramerVisitorInterface implementation
30 virtual void OnSynStream(SpdyStreamId stream_id
,
31 SpdyStreamId associated_stream_id
,
32 SpdyPriority priority
,
33 uint8 credential_slot
,
35 bool unidirectional
) OVERRIDE
{
36 if (!stream_
->IsConnected()) {
40 if (associated_stream_id
!= 0) {
41 CloseConnection("associated_stream_id != 0");
45 if (credential_slot
!= 0) {
46 CloseConnection("credential_slot != 0");
50 if (unidirectional
!= 0) {
51 CloseConnection("unidirectional != 0");
55 stream_
->OnSynStream(stream_id
, priority
, fin
);
58 virtual void OnSynReply(SpdyStreamId stream_id
, bool fin
) OVERRIDE
{
59 if (!stream_
->IsConnected()) {
63 stream_
->OnSynReply(stream_id
, fin
);
66 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id
,
67 const char* header_data
,
68 size_t len
) OVERRIDE
{
69 if (!stream_
->IsConnected()) {
72 stream_
->OnControlFrameHeaderData(stream_id
, header_data
, len
);
76 virtual void OnStreamFrameData(SpdyStreamId stream_id
,
80 if (fin
&& len
== 0) {
81 // The framer invokes OnStreamFrameData with zero-length data and
82 // fin = true after processing a SYN_STREAM or SYN_REPLY frame
83 // that had the fin bit set.
86 CloseConnection("SPDY DATA frame recevied.");
89 virtual void OnError(SpdyFramer
* framer
) OVERRIDE
{
90 CloseConnection("SPDY framing error.");
93 virtual void OnDataFrameHeader(SpdyStreamId stream_id
,
96 CloseConnection("SPDY DATA frame recevied.");
99 virtual void OnRstStream(SpdyStreamId stream_id
,
100 SpdyRstStreamStatus status
) OVERRIDE
{
101 CloseConnection("SPDY RST_STREAM frame recevied.");
104 virtual void OnSetting(SpdySettingsIds id
,
106 uint32 value
) OVERRIDE
{
107 CloseConnection("SPDY SETTINGS frame recevied.");
110 virtual void OnPing(uint32 unique_id
) OVERRIDE
{
111 CloseConnection("SPDY PING frame recevied.");
114 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id
,
115 SpdyGoAwayStatus status
) OVERRIDE
{
116 CloseConnection("SPDY GOAWAY frame recevied.");
119 virtual void OnHeaders(SpdyStreamId stream_id
, bool fin
) OVERRIDE
{
120 CloseConnection("SPDY HEADERS frame recevied.");
123 virtual void OnWindowUpdate(SpdyStreamId stream_id
,
124 uint32 delta_window_size
) OVERRIDE
{
125 CloseConnection("SPDY WINDOW_UPDATE frame recevied.");
128 virtual bool OnCredentialFrameData(const char* credential_data
,
129 size_t len
) OVERRIDE
{
130 CloseConnection("SPDY CREDENTIAL frame recevied.");
134 virtual void OnPushPromise(SpdyStreamId stream_id
,
135 SpdyStreamId promised_stream_id
) OVERRIDE
{
136 LOG(DFATAL
) << "PUSH_PROMISE frame received from a SPDY/3 framer";
137 CloseConnection("SPDY PUSH_PROMISE frame recevied.");
140 // SpdyFramerDebugVisitorInterface implementation
141 virtual void OnSendCompressedFrame(SpdyStreamId stream_id
,
144 size_t frame_len
) OVERRIDE
{}
146 virtual void OnReceiveCompressedFrame(SpdyStreamId stream_id
,
148 size_t frame_len
) OVERRIDE
{
149 if (stream_
->IsConnected()) {
150 stream_
->OnCompressedFrameSize(frame_len
);
155 void CloseConnection(const string
& details
) {
156 if (stream_
->IsConnected()) {
157 stream_
->CloseConnectionWithDetails(
158 QUIC_INVALID_HEADERS_STREAM_DATA
, details
);
163 QuicHeadersStream
* stream_
;
165 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor
);
168 QuicHeadersStream::QuicHeadersStream(QuicSession
* session
)
169 : ReliableQuicStream(kHeadersStreamId
, session
),
170 stream_id_(kInvalidStreamId
),
174 spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
175 spdy_framer_
.set_visitor(spdy_framer_visitor_
.get());
176 spdy_framer_
.set_debug_visitor(spdy_framer_visitor_
.get());
179 QuicHeadersStream::~QuicHeadersStream() {}
181 size_t QuicHeadersStream::WriteHeaders(QuicStreamId stream_id
,
182 const SpdyHeaderBlock
& headers
,
184 scoped_ptr
<SpdySerializedFrame
> frame
;
185 if (session()->is_server()) {
186 SpdySynReplyIR
syn_reply(stream_id
);
187 *syn_reply
.GetMutableNameValueBlock() = headers
;
188 syn_reply
.set_fin(fin
);
189 frame
.reset(spdy_framer_
.SerializeFrame(syn_reply
));
191 SpdySynStreamIR
syn_stream(stream_id
);
192 *syn_stream
.GetMutableNameValueBlock() = headers
;
193 syn_stream
.set_fin(fin
);
194 frame
.reset(spdy_framer_
.SerializeFrame(syn_stream
));
196 WriteOrBufferData(StringPiece(frame
->data(), frame
->size()), false);
197 return frame
->size();
200 uint32
QuicHeadersStream::ProcessRawData(const char* data
,
202 return spdy_framer_
.ProcessInput(data
, data_len
);
205 QuicPriority
QuicHeadersStream::EffectivePriority() const { return 0; }
207 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id
,
208 SpdyPriority priority
,
210 if (!session()->is_server()) {
211 CloseConnectionWithDetails(
212 QUIC_INVALID_HEADERS_STREAM_DATA
,
213 "SPDY SYN_STREAM frame recevied at the client");
216 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
217 stream_id_
= stream_id
;
219 session()->OnStreamHeadersPriority(stream_id
, priority
);
222 void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id
, bool fin
) {
223 if (session()->is_server()) {
224 CloseConnectionWithDetails(
225 QUIC_INVALID_HEADERS_STREAM_DATA
,
226 "SPDY SYN_REPLY frame recevied at the server");
229 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
230 stream_id_
= stream_id
;
234 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id
,
235 const char* header_data
,
237 DCHECK_EQ(stream_id_
, stream_id
);
239 DCHECK_NE(0u, stream_id_
);
240 DCHECK_NE(0u, frame_len_
);
241 session()->OnStreamHeadersComplete(stream_id_
, fin_
, frame_len_
);
242 // Reset state for the next frame.
243 stream_id_
= kInvalidStreamId
;
247 session()->OnStreamHeaders(stream_id_
, StringPiece(header_data
, len
));
251 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len
) {
252 DCHECK_EQ(kInvalidStreamId
, stream_id_
);
253 DCHECK_EQ(0u, frame_len_
);
254 frame_len_
= frame_len
;
257 bool QuicHeadersStream::IsConnected() {
258 return session()->connection()->connected();