OLD | NEW |
| (Empty) |
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 "base/strings/stringprintf.h" | |
8 #include "net/quic/quic_session.h" | |
9 | |
10 using base::StringPiece; | |
11 using std::string; | |
12 | |
13 namespace net { | |
14 | |
15 namespace { | |
16 | |
17 const QuicStreamId kInvalidStreamId = 0; | |
18 | |
19 } // namespace | |
20 | |
21 // A SpdyFramer visitor which passed SYN_STREAM and SYN_REPLY frames to | |
22 // the QuicDataStream, and closes the connection if any unexpected frames | |
23 // are received. | |
24 class QuicHeadersStream::SpdyFramerVisitor | |
25 : public SpdyFramerVisitorInterface, | |
26 public SpdyFramerDebugVisitorInterface { | |
27 public: | |
28 SpdyFramerVisitor(SpdyMajorVersion spdy_version, QuicHeadersStream* stream) | |
29 : spdy_version_(spdy_version), stream_(stream) {} | |
30 | |
31 // SpdyFramerVisitorInterface implementation | |
32 void OnSynStream(SpdyStreamId stream_id, | |
33 SpdyStreamId associated_stream_id, | |
34 SpdyPriority priority, | |
35 bool fin, | |
36 bool unidirectional) override { | |
37 if (spdy_version_ != SPDY3) { | |
38 CloseConnection("SPDY SYN_STREAM frame received."); | |
39 return; | |
40 } | |
41 | |
42 if (!stream_->IsConnected()) { | |
43 return; | |
44 } | |
45 | |
46 if (associated_stream_id != 0) { | |
47 CloseConnection("associated_stream_id != 0"); | |
48 return; | |
49 } | |
50 | |
51 if (unidirectional != 0) { | |
52 CloseConnection("unidirectional != 0"); | |
53 return; | |
54 } | |
55 | |
56 stream_->OnSynStream(stream_id, priority, fin); | |
57 } | |
58 | |
59 void OnSynReply(SpdyStreamId stream_id, bool fin) override { | |
60 if (spdy_version_ != SPDY3) { | |
61 CloseConnection("SPDY SYN_REPLY frame received."); | |
62 return; | |
63 } | |
64 | |
65 if (!stream_->IsConnected()) { | |
66 return; | |
67 } | |
68 | |
69 stream_->OnSynReply(stream_id, fin); | |
70 } | |
71 | |
72 bool OnControlFrameHeaderData(SpdyStreamId stream_id, | |
73 const char* header_data, | |
74 size_t len) override { | |
75 if (!stream_->IsConnected()) { | |
76 return false; | |
77 } | |
78 stream_->OnControlFrameHeaderData(stream_id, header_data, len); | |
79 return true; | |
80 } | |
81 | |
82 void OnStreamFrameData(SpdyStreamId stream_id, | |
83 const char* data, | |
84 size_t len, | |
85 bool fin) override { | |
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. | |
90 return; | |
91 } | |
92 CloseConnection("SPDY DATA frame received."); | |
93 } | |
94 | |
95 void OnError(SpdyFramer* framer) override { | |
96 CloseConnection(base::StringPrintf( | |
97 "SPDY framing error: %s", | |
98 SpdyFramer::ErrorCodeToString(framer->error_code()))); | |
99 } | |
100 | |
101 void OnDataFrameHeader(SpdyStreamId stream_id, | |
102 size_t length, | |
103 bool fin) override { | |
104 CloseConnection("SPDY DATA frame received."); | |
105 } | |
106 | |
107 void OnRstStream(SpdyStreamId stream_id, | |
108 SpdyRstStreamStatus status) override { | |
109 CloseConnection("SPDY RST_STREAM frame received."); | |
110 } | |
111 | |
112 void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) override { | |
113 CloseConnection("SPDY SETTINGS frame received."); | |
114 } | |
115 | |
116 void OnSettingsAck() override { | |
117 CloseConnection("SPDY SETTINGS frame received."); | |
118 } | |
119 | |
120 void OnSettingsEnd() override { | |
121 CloseConnection("SPDY SETTINGS frame received."); | |
122 } | |
123 | |
124 void OnPing(SpdyPingId unique_id, bool is_ack) override { | |
125 CloseConnection("SPDY PING frame received."); | |
126 } | |
127 | |
128 void OnGoAway(SpdyStreamId last_accepted_stream_id, | |
129 SpdyGoAwayStatus status) override { | |
130 CloseConnection("SPDY GOAWAY frame received."); | |
131 } | |
132 | |
133 void OnHeaders(SpdyStreamId stream_id, | |
134 bool has_priority, | |
135 SpdyPriority priority, | |
136 bool fin, | |
137 bool end) override { | |
138 if (spdy_version_ == SPDY3) { | |
139 CloseConnection("SPDY HEADERS frame received."); | |
140 return; | |
141 } | |
142 if (!stream_->IsConnected()) { | |
143 return; | |
144 } | |
145 if (has_priority) { | |
146 stream_->OnSynStream(stream_id, priority, fin); | |
147 } else { | |
148 stream_->OnSynReply(stream_id, fin); | |
149 } | |
150 } | |
151 | |
152 void OnWindowUpdate(SpdyStreamId stream_id, | |
153 uint32 delta_window_size) override { | |
154 CloseConnection("SPDY WINDOW_UPDATE frame received."); | |
155 } | |
156 | |
157 void OnPushPromise(SpdyStreamId stream_id, | |
158 SpdyStreamId promised_stream_id, | |
159 bool end) override { | |
160 LOG(DFATAL) << "PUSH_PROMISE frame received from a SPDY/3 framer"; | |
161 CloseConnection("SPDY PUSH_PROMISE frame received."); | |
162 } | |
163 | |
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."); | |
168 } | |
169 } | |
170 | |
171 bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override { | |
172 CloseConnection("Unknown frame type received."); | |
173 return false; | |
174 } | |
175 | |
176 // SpdyFramerDebugVisitorInterface implementation | |
177 void OnSendCompressedFrame(SpdyStreamId stream_id, | |
178 SpdyFrameType type, | |
179 size_t payload_len, | |
180 size_t frame_len) override {} | |
181 | |
182 void OnReceiveCompressedFrame(SpdyStreamId stream_id, | |
183 SpdyFrameType type, | |
184 size_t frame_len) override { | |
185 if (stream_->IsConnected()) { | |
186 stream_->OnCompressedFrameSize(frame_len); | |
187 } | |
188 } | |
189 | |
190 private: | |
191 void CloseConnection(const string& details) { | |
192 if (stream_->IsConnected()) { | |
193 stream_->CloseConnectionWithDetails( | |
194 QUIC_INVALID_HEADERS_STREAM_DATA, details); | |
195 } | |
196 } | |
197 | |
198 private: | |
199 SpdyMajorVersion spdy_version_; | |
200 QuicHeadersStream* stream_; | |
201 | |
202 DISALLOW_COPY_AND_ASSIGN(SpdyFramerVisitor); | |
203 }; | |
204 | |
205 QuicHeadersStream::QuicHeadersStream(QuicSession* session) | |
206 : ReliableQuicStream(kHeadersStreamId, session), | |
207 stream_id_(kInvalidStreamId), | |
208 fin_(false), | |
209 frame_len_(0) { | |
210 InitializeFramer(session->connection()->version()); | |
211 // The headers stream is exempt from connection level flow control. | |
212 DisableConnectionFlowControlForThisStream(); | |
213 } | |
214 | |
215 QuicHeadersStream::~QuicHeadersStream() {} | |
216 | |
217 size_t QuicHeadersStream::WriteHeaders( | |
218 QuicStreamId stream_id, | |
219 const SpdyHeaderBlock& headers, | |
220 bool fin, | |
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)); | |
230 } else { | |
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)); | |
236 } | |
237 } else { | |
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); | |
244 } | |
245 frame.reset(spdy_framer_->SerializeFrame(headers_frame)); | |
246 } | |
247 WriteOrBufferData(StringPiece(frame->data(), frame->size()), false, | |
248 ack_notifier_delegate); | |
249 return frame->size(); | |
250 } | |
251 | |
252 uint32 QuicHeadersStream::ProcessRawData(const char* data, | |
253 uint32 data_len) { | |
254 return spdy_framer_->ProcessInput(data, data_len); | |
255 } | |
256 | |
257 QuicPriority QuicHeadersStream::EffectivePriority() const { return 0; } | |
258 | |
259 void QuicHeadersStream::OnSuccessfulVersionNegotiation(QuicVersion version) { | |
260 InitializeFramer(version); | |
261 } | |
262 | |
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) { | |
267 return; | |
268 } | |
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()); | |
273 } | |
274 | |
275 void QuicHeadersStream::OnSynStream(SpdyStreamId stream_id, | |
276 SpdyPriority priority, | |
277 bool fin) { | |
278 if (!session()->is_server()) { | |
279 CloseConnectionWithDetails( | |
280 QUIC_INVALID_HEADERS_STREAM_DATA, | |
281 "SPDY SYN_STREAM frame received at the client"); | |
282 return; | |
283 } | |
284 DCHECK_EQ(kInvalidStreamId, stream_id_); | |
285 stream_id_ = stream_id; | |
286 fin_ = fin; | |
287 session()->OnStreamHeadersPriority(stream_id, priority); | |
288 } | |
289 | |
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"); | |
295 return; | |
296 } | |
297 DCHECK_EQ(kInvalidStreamId, stream_id_); | |
298 stream_id_ = stream_id; | |
299 fin_ = fin; | |
300 } | |
301 | |
302 void QuicHeadersStream::OnControlFrameHeaderData(SpdyStreamId stream_id, | |
303 const char* header_data, | |
304 size_t len) { | |
305 DCHECK_EQ(stream_id_, stream_id); | |
306 if (len == 0) { | |
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; | |
312 fin_ = false; | |
313 frame_len_ = 0; | |
314 } else { | |
315 session()->OnStreamHeaders(stream_id_, StringPiece(header_data, len)); | |
316 } | |
317 } | |
318 | |
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_); | |
325 } | |
326 frame_len_ += frame_len; | |
327 } | |
328 | |
329 bool QuicHeadersStream::IsConnected() { | |
330 return session()->connection()->connected(); | |
331 } | |
332 | |
333 } // namespace net | |
OLD | NEW |