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.
4
5 #include "net/quic/quic_headers_stream.h"
6
7 #include "net/quic/quic_session.h"
8
9 using base::StringPiece;
10
11 namespace net {
12
13 namespace {
14
15 const QuicStreamId kInvalidStreamId = 0;
16
17 } // namespace
18
19 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to
20 // the QuicDataStream, and closes the connection if any unexpected frames
21 // are received.
22 class QuicHeadersStream::SpdyFramerVisitor
23 : public SpdyFramerVisitorInterface,
24 public SpdyFramerDebugVisitorInterface {
25 public:
SpdyFramerVisitor(QuicHeadersStream * stream)26 explicit SpdyFramerVisitor(QuicHeadersStream* stream) : stream_(stream) {}
27
28 // SpdyFramerVisitorInterface implementation
OnSynStream(SpdyStreamId stream_id,SpdyStreamId associated_stream_id,SpdyPriority priority,bool fin,bool unidirectional)29 virtual void OnSynStream(SpdyStreamId stream_id,
30 SpdyStreamId associated_stream_id,
31 SpdyPriority priority,
32 bool fin,
33 bool unidirectional) OVERRIDE {
34 if (!stream_->IsConnected()) {
35 return;
36 }
37
38 if (associated_stream_id != 0) {
39 CloseConnection("associated_stream_id != 0");
40 return;
41 }
42
43 if (unidirectional != 0) {
44 CloseConnection("unidirectional != 0");
45 return;
46 }
47
48 stream_->OnSynStream(stream_id, priority, fin);
49 }
50
OnSynReply(SpdyStreamId stream_id,bool fin)51 virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {
52 if (!stream_->IsConnected()) {
53 return;
54 }
55
56 stream_->OnSynReply(stream_id, fin);
57 }
58
OnControlFrameHeaderData(SpdyStreamId stream_id,const char * header_data,size_t len)59 virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
60 const char* header_data,
61 size_t len) OVERRIDE {
62 if (!stream_->IsConnected()) {
63 return false;
64 }
65 stream_->OnControlFrameHeaderData(stream_id, header_data, len);
66 return true;
67 }
68
OnStreamFrameData(SpdyStreamId stream_id,const char * data,size_t len,bool fin)69 virtual void OnStreamFrameData(SpdyStreamId stream_id,
70 const char* data,
71 size_t len,
72 bool fin) OVERRIDE {
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.
77 return;
78 }
79 CloseConnection("SPDY DATA frame received.");
80 }
81
OnError(SpdyFramer * framer)82 virtual void OnError(SpdyFramer* framer) OVERRIDE {
83 CloseConnection("SPDY framing error.");
84 }
85
OnDataFrameHeader(SpdyStreamId stream_id,size_t length,bool fin)86 virtual void OnDataFrameHeader(SpdyStreamId stream_id,
87 size_t length,
88 bool fin) OVERRIDE {
89 CloseConnection("SPDY DATA frame received.");
90 }
91
OnRstStream(SpdyStreamId stream_id,SpdyRstStreamStatus status)92 virtual void OnRstStream(SpdyStreamId stream_id,
93 SpdyRstStreamStatus status) OVERRIDE {
94 CloseConnection("SPDY RST_STREAM frame received.");
95 }
96
OnSetting(SpdySettingsIds id,uint8 flags,uint32 value)97 virtual void OnSetting(SpdySettingsIds id,
98 uint8 flags,
99 uint32 value) OVERRIDE {
100 CloseConnection("SPDY SETTINGS frame received.");
101 }
102
OnSettingsAck()103 virtual void OnSettingsAck() OVERRIDE {
104 CloseConnection("SPDY SETTINGS frame received.");
105 }
106
OnSettingsEnd()107 virtual void OnSettingsEnd() OVERRIDE {
108 CloseConnection("SPDY SETTINGS frame received.");
109 }
110
OnPing(SpdyPingId unique_id,bool is_ack)111 virtual void OnPing(SpdyPingId unique_id, bool is_ack) OVERRIDE {
112 CloseConnection("SPDY PING frame received.");
113 }
114
OnGoAway(SpdyStreamId last_accepted_stream_id,SpdyGoAwayStatus status)115 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
116 SpdyGoAwayStatus status) OVERRIDE {
117 CloseConnection("SPDY GOAWAY frame received.");
118 }
119
OnHeaders(SpdyStreamId stream_id,bool fin,bool end)120 virtual void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) OVERRIDE {
121 CloseConnection("SPDY HEADERS frame received.");
122 }
123
OnWindowUpdate(SpdyStreamId stream_id,uint32 delta_window_size)124 virtual void OnWindowUpdate(SpdyStreamId stream_id,
125 uint32 delta_window_size) OVERRIDE {
126 CloseConnection("SPDY WINDOW_UPDATE frame received.");
127 }
128
OnPushPromise(SpdyStreamId stream_id,SpdyStreamId promised_stream_id,bool end)129 virtual void OnPushPromise(SpdyStreamId stream_id,
130 SpdyStreamId promised_stream_id,
131 bool end) OVERRIDE {
132 LOG(DFATAL) << "PUSH_PROMISE frame received from a SPDY/3 framer";
133 CloseConnection("SPDY PUSH_PROMISE frame received.");
134 }
135
OnContinuation(SpdyStreamId stream_id,bool end)136 virtual void OnContinuation(SpdyStreamId stream_id, bool end) OVERRIDE {
137 CloseConnection("SPDY CONTINUATION frame received.");
138 }
139
OnUnknownFrame(SpdyStreamId stream_id,int frame_type)140 virtual bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) OVERRIDE {
141 CloseConnection("SPDY unknown frame received.");
142 return false;
143 }
144
145 // SpdyFramerDebugVisitorInterface implementation
OnSendCompressedFrame(SpdyStreamId stream_id,SpdyFrameType type,size_t payload_len,size_t frame_len)146 virtual void OnSendCompressedFrame(SpdyStreamId stream_id,
147 SpdyFrameType type,
148 size_t payload_len,
149 size_t frame_len) OVERRIDE {}
150
OnReceiveCompressedFrame(SpdyStreamId stream_id,SpdyFrameType type,size_t frame_len)151 virtual void OnReceiveCompressedFrame(SpdyStreamId stream_id,
152 SpdyFrameType type,
153 size_t frame_len) OVERRIDE {
154 if (stream_->IsConnected()) {
155 stream_->OnCompressedFrameSize(frame_len);
156 }
157 }
158
159 private:
CloseConnection(const string & details)160 void CloseConnection(const string& details) {
161 if (stream_->IsConnected()) {
162 stream_->CloseConnectionWithDetails(
163 QUIC_INVALID_HEADERS_STREAM_DATA, details);
164 }
165 }
166
167 private:
168 QuicHeadersStream* stream_;
169
170 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor);
171 };
172
QuicHeadersStream(QuicSession * session)173 QuicHeadersStream::QuicHeadersStream(QuicSession* session)
174 : ReliableQuicStream(kHeadersStreamId, session),
175 stream_id_(kInvalidStreamId),
176 fin_(false),
177 frame_len_(0),
178 spdy_framer_(SPDY3),
179 spdy_framer_visitor_(new SpdyFramerVisitor(this)) {
180 spdy_framer_.set_visitor(spdy_framer_visitor_.get());
181 spdy_framer_.set_debug_visitor(spdy_framer_visitor_.get());
182 if (version() < QUIC_VERSION_21) {
183 // Prior to QUIC_VERSION_21 the headers stream is not subject to any flow
184 // control.
185 DisableFlowControl();
186 }
187 // The headers stream is exempt from connection level flow control.
188 DisableConnectionFlowControlForThisStream();
189 }
190
~QuicHeadersStream()191 QuicHeadersStream::~QuicHeadersStream() {}
192
WriteHeaders(QuicStreamId stream_id,const SpdyHeaderBlock & headers,bool fin,QuicAckNotifier::DelegateInterface * ack_notifier_delegate)193 size_t QuicHeadersStream::WriteHeaders(
194 QuicStreamId stream_id,
195 const SpdyHeaderBlock& headers,
196 bool fin,
197 QuicAckNotifier::DelegateInterface* ack_notifier_delegate) {
198 scoped_ptr<SpdySerializedFrame> frame;
199 if (session()->is_server()) {
200 SpdySynReplyIR syn_reply(stream_id);
201 syn_reply.set_name_value_block(headers);
202 syn_reply.set_fin(fin);
203 frame.reset(spdy_framer_.SerializeFrame(syn_reply));
204 } else {
205 SpdySynStreamIR syn_stream(stream_id);
206 syn_stream.set_name_value_block(headers);
207 syn_stream.set_fin(fin);
208 frame.reset(spdy_framer_.SerializeFrame(syn_stream));
209 }
210 WriteOrBufferData(StringPiece(frame->data(), frame->size()), false,
211 ack_notifier_delegate);
212 return frame->size();
213 }
214
ProcessRawData(const char * data,uint32 data_len)215 uint32 QuicHeadersStream::ProcessRawData(const char* data,
216 uint32 data_len) {
217 return spdy_framer_.ProcessInput(data, data_len);
218 }
219
EffectivePriority() const220 QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; }
221
OnSynStream(SpdyStreamId stream_id,SpdyPriority priority,bool fin)222 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id,
223 SpdyPriority priority,
224 bool fin) {
225 if (!session()->is_server()) {
226 CloseConnectionWithDetails(
227 QUIC_INVALID_HEADERS_STREAM_DATA,
228 "SPDY SYN_STREAM frame received at the client");
229 return;
230 }
231 DCHECK_EQ(kInvalidStreamId, stream_id_);
232 stream_id_ = stream_id;
233 fin_ = fin;
234 session()->OnStreamHeadersPriority(stream_id, priority);
235 }
236
OnSynReply(SpdyStreamId stream_id,bool fin)237 void QuicHeadersStream::OnSynReply(SpdyStreamId stream_id, bool fin) {
238 if (session()->is_server()) {
239 CloseConnectionWithDetails(
240 QUIC_INVALID_HEADERS_STREAM_DATA,
241 "SPDY SYN_REPLY frame received at the server");
242 return;
243 }
244 DCHECK_EQ(kInvalidStreamId, stream_id_);
245 stream_id_ = stream_id;
246 fin_ = fin;
247 }
248
OnControlFrameHeaderData(SpdyStreamId stream_id,const char * header_data,size_t len)249 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id,
250 const char* header_data,
251 size_t len) {
252 DCHECK_EQ(stream_id_, stream_id);
253 if (len == 0) {
254 DCHECK_NE(0u, stream_id_);
255 DCHECK_NE(0u, frame_len_);
256 session()->OnStreamHeadersComplete(stream_id_, fin_, frame_len_);
257 // Reset state for the next frame.
258 stream_id_ = kInvalidStreamId;
259 fin_ = false;
260 frame_len_ = 0;
261 } else {
262 session()->OnStreamHeaders(stream_id_, StringPiece(header_data, len));
263 }
264 }
265
OnCompressedFrameSize(size_t frame_len)266 void QuicHeadersStream::OnCompressedFrameSize(size_t frame_len) {
267 DCHECK_EQ(kInvalidStreamId, stream_id_);
268 DCHECK_EQ(0u, frame_len_);
269 frame_len_ = frame_len;
270 }
271
IsConnected()272 bool QuicHeadersStream::IsConnected() {
273 return session()->connection()->connected();
274 }
275
276 } // namespace net
277