OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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/spdy/buffered_spdy_framer.h" | |
6 | |
7 #include "base/logging.h" | |
8 | |
9 namespace net { | |
10 | |
11 SpdyMajorVersion NextProtoToSpdyMajorVersion(NextProto next_proto) { | |
12 switch (next_proto) { | |
13 case kProtoDeprecatedSPDY2: | |
14 return SPDY2; | |
15 case kProtoSPDY3: | |
16 case kProtoSPDY31: | |
17 return SPDY3; | |
18 case kProtoSPDY4_14: | |
19 case kProtoSPDY4_15: | |
20 return SPDY4; | |
21 case kProtoUnknown: | |
22 case kProtoHTTP11: | |
23 case kProtoQUIC1SPDY3: | |
24 break; | |
25 } | |
26 NOTREACHED(); | |
27 return SPDY2; | |
28 } | |
29 | |
30 BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version, | |
31 bool enable_compression) | |
32 : spdy_framer_(version), | |
33 visitor_(NULL), | |
34 header_buffer_used_(0), | |
35 header_buffer_valid_(false), | |
36 header_stream_id_(SpdyFramer::kInvalidStream), | |
37 frames_received_(0) { | |
38 spdy_framer_.set_enable_compression(enable_compression); | |
39 memset(header_buffer_, 0, sizeof(header_buffer_)); | |
40 } | |
41 | |
42 BufferedSpdyFramer::~BufferedSpdyFramer() { | |
43 } | |
44 | |
45 void BufferedSpdyFramer::set_visitor( | |
46 BufferedSpdyFramerVisitorInterface* visitor) { | |
47 visitor_ = visitor; | |
48 spdy_framer_.set_visitor(this); | |
49 } | |
50 | |
51 void BufferedSpdyFramer::set_debug_visitor( | |
52 SpdyFramerDebugVisitorInterface* debug_visitor) { | |
53 spdy_framer_.set_debug_visitor(debug_visitor); | |
54 } | |
55 | |
56 void BufferedSpdyFramer::OnError(SpdyFramer* spdy_framer) { | |
57 DCHECK(spdy_framer); | |
58 visitor_->OnError(spdy_framer->error_code()); | |
59 } | |
60 | |
61 void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id, | |
62 SpdyStreamId associated_stream_id, | |
63 SpdyPriority priority, | |
64 bool fin, | |
65 bool unidirectional) { | |
66 frames_received_++; | |
67 DCHECK(!control_frame_fields_.get()); | |
68 control_frame_fields_.reset(new ControlFrameFields()); | |
69 control_frame_fields_->type = SYN_STREAM; | |
70 control_frame_fields_->stream_id = stream_id; | |
71 control_frame_fields_->associated_stream_id = associated_stream_id; | |
72 control_frame_fields_->priority = priority; | |
73 control_frame_fields_->fin = fin; | |
74 control_frame_fields_->unidirectional = unidirectional; | |
75 | |
76 InitHeaderStreaming(stream_id); | |
77 } | |
78 | |
79 void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id, | |
80 bool has_priority, | |
81 SpdyPriority priority, | |
82 bool fin, | |
83 bool end) { | |
84 frames_received_++; | |
85 DCHECK(!control_frame_fields_.get()); | |
86 control_frame_fields_.reset(new ControlFrameFields()); | |
87 control_frame_fields_->type = HEADERS; | |
88 control_frame_fields_->stream_id = stream_id; | |
89 control_frame_fields_->has_priority = has_priority; | |
90 if (control_frame_fields_->has_priority) { | |
91 control_frame_fields_->priority = priority; | |
92 } | |
93 control_frame_fields_->fin = fin; | |
94 | |
95 InitHeaderStreaming(stream_id); | |
96 } | |
97 | |
98 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id, | |
99 bool fin) { | |
100 frames_received_++; | |
101 DCHECK(!control_frame_fields_.get()); | |
102 control_frame_fields_.reset(new ControlFrameFields()); | |
103 control_frame_fields_->type = SYN_REPLY; | |
104 control_frame_fields_->stream_id = stream_id; | |
105 control_frame_fields_->fin = fin; | |
106 | |
107 InitHeaderStreaming(stream_id); | |
108 } | |
109 | |
110 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id, | |
111 const char* header_data, | |
112 size_t len) { | |
113 CHECK_EQ(header_stream_id_, stream_id); | |
114 | |
115 if (len == 0) { | |
116 // Indicates end-of-header-block. | |
117 CHECK(header_buffer_valid_); | |
118 | |
119 SpdyHeaderBlock headers; | |
120 size_t parsed_len = spdy_framer_.ParseHeaderBlockInBuffer( | |
121 header_buffer_, header_buffer_used_, &headers); | |
122 // TODO(rch): this really should be checking parsed_len != len, | |
123 // but a bunch of tests fail. Need to figure out why. | |
124 if (parsed_len == 0) { | |
125 visitor_->OnStreamError( | |
126 stream_id, "Could not parse Spdy Control Frame Header."); | |
127 return false; | |
128 } | |
129 DCHECK(control_frame_fields_.get()); | |
130 switch (control_frame_fields_->type) { | |
131 case SYN_STREAM: | |
132 visitor_->OnSynStream(control_frame_fields_->stream_id, | |
133 control_frame_fields_->associated_stream_id, | |
134 control_frame_fields_->priority, | |
135 control_frame_fields_->fin, | |
136 control_frame_fields_->unidirectional, | |
137 headers); | |
138 break; | |
139 case SYN_REPLY: | |
140 visitor_->OnSynReply(control_frame_fields_->stream_id, | |
141 control_frame_fields_->fin, | |
142 headers); | |
143 break; | |
144 case HEADERS: | |
145 visitor_->OnHeaders(control_frame_fields_->stream_id, | |
146 control_frame_fields_->has_priority, | |
147 control_frame_fields_->priority, | |
148 control_frame_fields_->fin, | |
149 headers); | |
150 break; | |
151 case PUSH_PROMISE: | |
152 DCHECK_LT(SPDY3, protocol_version()); | |
153 visitor_->OnPushPromise(control_frame_fields_->stream_id, | |
154 control_frame_fields_->promised_stream_id, | |
155 headers); | |
156 break; | |
157 default: | |
158 DCHECK(false) << "Unexpect control frame type: " | |
159 << control_frame_fields_->type; | |
160 break; | |
161 } | |
162 control_frame_fields_.reset(NULL); | |
163 return true; | |
164 } | |
165 | |
166 const size_t available = kHeaderBufferSize - header_buffer_used_; | |
167 if (len > available) { | |
168 header_buffer_valid_ = false; | |
169 visitor_->OnStreamError( | |
170 stream_id, "Received more data than the allocated size."); | |
171 return false; | |
172 } | |
173 memcpy(header_buffer_ + header_buffer_used_, header_data, len); | |
174 header_buffer_used_ += len; | |
175 return true; | |
176 } | |
177 | |
178 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id, | |
179 size_t length, | |
180 bool fin) { | |
181 frames_received_++; | |
182 header_stream_id_ = stream_id; | |
183 visitor_->OnDataFrameHeader(stream_id, length, fin); | |
184 } | |
185 | |
186 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id, | |
187 const char* data, | |
188 size_t len, | |
189 bool fin) { | |
190 visitor_->OnStreamFrameData(stream_id, data, len, fin); | |
191 } | |
192 | |
193 void BufferedSpdyFramer::OnSettings(bool clear_persisted) { | |
194 visitor_->OnSettings(clear_persisted); | |
195 } | |
196 | |
197 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id, | |
198 uint8 flags, | |
199 uint32 value) { | |
200 visitor_->OnSetting(id, flags, value); | |
201 } | |
202 | |
203 void BufferedSpdyFramer::OnSettingsAck() { | |
204 visitor_->OnSettingsAck(); | |
205 } | |
206 | |
207 void BufferedSpdyFramer::OnSettingsEnd() { | |
208 visitor_->OnSettingsEnd(); | |
209 } | |
210 | |
211 void BufferedSpdyFramer::OnPing(SpdyPingId unique_id, bool is_ack) { | |
212 visitor_->OnPing(unique_id, is_ack); | |
213 } | |
214 | |
215 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id, | |
216 SpdyRstStreamStatus status) { | |
217 visitor_->OnRstStream(stream_id, status); | |
218 } | |
219 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id, | |
220 SpdyGoAwayStatus status) { | |
221 visitor_->OnGoAway(last_accepted_stream_id, status); | |
222 } | |
223 | |
224 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id, | |
225 uint32 delta_window_size) { | |
226 visitor_->OnWindowUpdate(stream_id, delta_window_size); | |
227 } | |
228 | |
229 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id, | |
230 SpdyStreamId promised_stream_id, | |
231 bool end) { | |
232 DCHECK_LT(SPDY3, protocol_version()); | |
233 frames_received_++; | |
234 DCHECK(!control_frame_fields_.get()); | |
235 control_frame_fields_.reset(new ControlFrameFields()); | |
236 control_frame_fields_->type = PUSH_PROMISE; | |
237 control_frame_fields_->stream_id = stream_id; | |
238 control_frame_fields_->promised_stream_id = promised_stream_id; | |
239 | |
240 InitHeaderStreaming(stream_id); | |
241 } | |
242 | |
243 void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id, bool end) { | |
244 } | |
245 | |
246 bool BufferedSpdyFramer::OnUnknownFrame(SpdyStreamId stream_id, | |
247 int frame_type) { | |
248 return visitor_->OnUnknownFrame(stream_id, frame_type); | |
249 } | |
250 | |
251 SpdyMajorVersion BufferedSpdyFramer::protocol_version() { | |
252 return spdy_framer_.protocol_version(); | |
253 } | |
254 | |
255 size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) { | |
256 return spdy_framer_.ProcessInput(data, len); | |
257 } | |
258 | |
259 void BufferedSpdyFramer::Reset() { | |
260 spdy_framer_.Reset(); | |
261 } | |
262 | |
263 SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const { | |
264 return spdy_framer_.error_code(); | |
265 } | |
266 | |
267 SpdyFramer::SpdyState BufferedSpdyFramer::state() const { | |
268 return spdy_framer_.state(); | |
269 } | |
270 | |
271 bool BufferedSpdyFramer::MessageFullyRead() { | |
272 return state() == SpdyFramer::SPDY_AUTO_RESET; | |
273 } | |
274 | |
275 bool BufferedSpdyFramer::HasError() { | |
276 return spdy_framer_.HasError(); | |
277 } | |
278 | |
279 // TODO(jgraettinger): Eliminate uses of this method (prefer | |
280 // SpdySynStreamIR). | |
281 SpdyFrame* BufferedSpdyFramer::CreateSynStream( | |
282 SpdyStreamId stream_id, | |
283 SpdyStreamId associated_stream_id, | |
284 SpdyPriority priority, | |
285 SpdyControlFlags flags, | |
286 const SpdyHeaderBlock* headers) { | |
287 SpdySynStreamIR syn_stream(stream_id); | |
288 syn_stream.set_associated_to_stream_id(associated_stream_id); | |
289 syn_stream.set_priority(priority); | |
290 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0); | |
291 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0); | |
292 // TODO(hkhalil): Avoid copy here. | |
293 syn_stream.set_name_value_block(*headers); | |
294 return spdy_framer_.SerializeSynStream(syn_stream); | |
295 } | |
296 | |
297 // TODO(jgraettinger): Eliminate uses of this method (prefer | |
298 // SpdySynReplyIR). | |
299 SpdyFrame* BufferedSpdyFramer::CreateSynReply( | |
300 SpdyStreamId stream_id, | |
301 SpdyControlFlags flags, | |
302 const SpdyHeaderBlock* headers) { | |
303 SpdySynReplyIR syn_reply(stream_id); | |
304 syn_reply.set_fin(flags & CONTROL_FLAG_FIN); | |
305 // TODO(hkhalil): Avoid copy here. | |
306 syn_reply.set_name_value_block(*headers); | |
307 return spdy_framer_.SerializeSynReply(syn_reply); | |
308 } | |
309 | |
310 // TODO(jgraettinger): Eliminate uses of this method (prefer | |
311 // SpdyRstStreamIR). | |
312 SpdyFrame* BufferedSpdyFramer::CreateRstStream( | |
313 SpdyStreamId stream_id, | |
314 SpdyRstStreamStatus status) const { | |
315 // RST_STREAM payloads are not part of any SPDY spec. | |
316 // SpdyFramer will accept them, but don't create them. | |
317 SpdyRstStreamIR rst_ir(stream_id, status, ""); | |
318 return spdy_framer_.SerializeRstStream(rst_ir); | |
319 } | |
320 | |
321 // TODO(jgraettinger): Eliminate uses of this method (prefer | |
322 // SpdySettingsIR). | |
323 SpdyFrame* BufferedSpdyFramer::CreateSettings( | |
324 const SettingsMap& values) const { | |
325 SpdySettingsIR settings_ir; | |
326 for (SettingsMap::const_iterator it = values.begin(); | |
327 it != values.end(); | |
328 ++it) { | |
329 settings_ir.AddSetting( | |
330 it->first, | |
331 (it->second.first & SETTINGS_FLAG_PLEASE_PERSIST) != 0, | |
332 (it->second.first & SETTINGS_FLAG_PERSISTED) != 0, | |
333 it->second.second); | |
334 } | |
335 return spdy_framer_.SerializeSettings(settings_ir); | |
336 } | |
337 | |
338 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR). | |
339 SpdyFrame* BufferedSpdyFramer::CreatePingFrame(SpdyPingId unique_id, | |
340 bool is_ack) const { | |
341 SpdyPingIR ping_ir(unique_id); | |
342 ping_ir.set_is_ack(is_ack); | |
343 return spdy_framer_.SerializePing(ping_ir); | |
344 } | |
345 | |
346 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyGoAwayIR). | |
347 SpdyFrame* BufferedSpdyFramer::CreateGoAway( | |
348 SpdyStreamId last_accepted_stream_id, | |
349 SpdyGoAwayStatus status) const { | |
350 SpdyGoAwayIR go_ir(last_accepted_stream_id, status, ""); | |
351 return spdy_framer_.SerializeGoAway(go_ir); | |
352 } | |
353 | |
354 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyHeadersIR). | |
355 SpdyFrame* BufferedSpdyFramer::CreateHeaders( | |
356 SpdyStreamId stream_id, | |
357 SpdyControlFlags flags, | |
358 SpdyPriority priority, | |
359 const SpdyHeaderBlock* headers) { | |
360 SpdyHeadersIR headers_ir(stream_id); | |
361 headers_ir.set_fin((flags & CONTROL_FLAG_FIN) != 0); | |
362 if (flags & HEADERS_FLAG_PRIORITY) { | |
363 headers_ir.set_has_priority(true); | |
364 headers_ir.set_priority(priority); | |
365 } | |
366 headers_ir.set_name_value_block(*headers); | |
367 return spdy_framer_.SerializeHeaders(headers_ir); | |
368 } | |
369 | |
370 // TODO(jgraettinger): Eliminate uses of this method (prefer | |
371 // SpdyWindowUpdateIR). | |
372 SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate( | |
373 SpdyStreamId stream_id, | |
374 uint32 delta_window_size) const { | |
375 SpdyWindowUpdateIR update_ir(stream_id, delta_window_size); | |
376 return spdy_framer_.SerializeWindowUpdate(update_ir); | |
377 } | |
378 | |
379 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR). | |
380 SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id, | |
381 const char* data, | |
382 uint32 len, | |
383 SpdyDataFlags flags) { | |
384 SpdyDataIR data_ir(stream_id, | |
385 base::StringPiece(data, len)); | |
386 data_ir.set_fin((flags & DATA_FLAG_FIN) != 0); | |
387 return spdy_framer_.SerializeData(data_ir); | |
388 } | |
389 | |
390 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPushPromiseIR). | |
391 SpdyFrame* BufferedSpdyFramer::CreatePushPromise( | |
392 SpdyStreamId stream_id, | |
393 SpdyStreamId promised_stream_id, | |
394 const SpdyHeaderBlock* headers) { | |
395 SpdyPushPromiseIR push_promise_ir(stream_id, promised_stream_id); | |
396 push_promise_ir.set_name_value_block(*headers); | |
397 return spdy_framer_.SerializePushPromise(push_promise_ir); | |
398 } | |
399 | |
400 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const { | |
401 return spdy_framer_.GetHighestPriority(); | |
402 } | |
403 | |
404 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) { | |
405 memset(header_buffer_, 0, kHeaderBufferSize); | |
406 header_buffer_used_ = 0; | |
407 header_buffer_valid_ = true; | |
408 header_stream_id_ = stream_id; | |
409 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); | |
410 } | |
411 | |
412 } // namespace net | |
OLD | NEW |