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.
5 #include "net/spdy/buffered_spdy_framer.h"
7 #include "base/logging.h"
11 SpdyMajorVersion
NextProtoToSpdyMajorVersion(NextProto next_proto
) {
13 case kProtoDeprecatedSPDY2
:
23 case kProtoQUIC1SPDY3
:
30 BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version
,
31 bool enable_compression
)
32 : spdy_framer_(version
),
34 header_buffer_used_(0),
35 header_buffer_valid_(false),
36 header_stream_id_(SpdyFramer::kInvalidStream
),
38 spdy_framer_
.set_enable_compression(enable_compression
);
39 memset(header_buffer_
, 0, sizeof(header_buffer_
));
42 BufferedSpdyFramer::~BufferedSpdyFramer() {
45 void BufferedSpdyFramer::set_visitor(
46 BufferedSpdyFramerVisitorInterface
* visitor
) {
48 spdy_framer_
.set_visitor(this);
51 void BufferedSpdyFramer::set_debug_visitor(
52 SpdyFramerDebugVisitorInterface
* debug_visitor
) {
53 spdy_framer_
.set_debug_visitor(debug_visitor
);
56 void BufferedSpdyFramer::OnError(SpdyFramer
* spdy_framer
) {
58 visitor_
->OnError(spdy_framer
->error_code());
61 void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id
,
62 SpdyStreamId associated_stream_id
,
63 SpdyPriority priority
,
65 bool unidirectional
) {
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
;
76 InitHeaderStreaming(stream_id
);
79 void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id
,
81 SpdyPriority priority
,
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
;
93 control_frame_fields_
->fin
= fin
;
95 InitHeaderStreaming(stream_id
);
98 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id
,
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
;
107 InitHeaderStreaming(stream_id
);
110 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id
,
111 const char* header_data
,
113 CHECK_EQ(header_stream_id_
, stream_id
);
116 // Indicates end-of-header-block.
117 CHECK(header_buffer_valid_
);
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.");
129 DCHECK(control_frame_fields_
.get());
130 switch (control_frame_fields_
->type
) {
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
,
140 visitor_
->OnSynReply(control_frame_fields_
->stream_id
,
141 control_frame_fields_
->fin
,
145 visitor_
->OnHeaders(control_frame_fields_
->stream_id
,
146 control_frame_fields_
->has_priority
,
147 control_frame_fields_
->priority
,
148 control_frame_fields_
->fin
,
152 DCHECK_LT(SPDY3
, protocol_version());
153 visitor_
->OnPushPromise(control_frame_fields_
->stream_id
,
154 control_frame_fields_
->promised_stream_id
,
158 DCHECK(false) << "Unexpect control frame type: "
159 << control_frame_fields_
->type
;
162 control_frame_fields_
.reset(NULL
);
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.");
173 memcpy(header_buffer_
+ header_buffer_used_
, header_data
, len
);
174 header_buffer_used_
+= len
;
178 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id
,
182 header_stream_id_
= stream_id
;
183 visitor_
->OnDataFrameHeader(stream_id
, length
, fin
);
186 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id
,
190 visitor_
->OnStreamFrameData(stream_id
, data
, len
, fin
);
193 void BufferedSpdyFramer::OnSettings(bool clear_persisted
) {
194 visitor_
->OnSettings(clear_persisted
);
197 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id
,
200 visitor_
->OnSetting(id
, flags
, value
);
203 void BufferedSpdyFramer::OnSettingsAck() {
204 visitor_
->OnSettingsAck();
207 void BufferedSpdyFramer::OnSettingsEnd() {
208 visitor_
->OnSettingsEnd();
211 void BufferedSpdyFramer::OnPing(SpdyPingId unique_id
, bool is_ack
) {
212 visitor_
->OnPing(unique_id
, is_ack
);
215 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id
,
216 SpdyRstStreamStatus status
) {
217 visitor_
->OnRstStream(stream_id
, status
);
219 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id
,
220 SpdyGoAwayStatus status
) {
221 visitor_
->OnGoAway(last_accepted_stream_id
, status
);
224 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id
,
225 uint32 delta_window_size
) {
226 visitor_
->OnWindowUpdate(stream_id
, delta_window_size
);
229 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id
,
230 SpdyStreamId promised_stream_id
,
232 DCHECK_LT(SPDY3
, protocol_version());
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
;
240 InitHeaderStreaming(stream_id
);
243 void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id
, bool end
) {
246 bool BufferedSpdyFramer::OnUnknownFrame(SpdyStreamId stream_id
,
248 return visitor_
->OnUnknownFrame(stream_id
, frame_type
);
251 SpdyMajorVersion
BufferedSpdyFramer::protocol_version() {
252 return spdy_framer_
.protocol_version();
255 size_t BufferedSpdyFramer::ProcessInput(const char* data
, size_t len
) {
256 return spdy_framer_
.ProcessInput(data
, len
);
259 void BufferedSpdyFramer::Reset() {
260 spdy_framer_
.Reset();
263 SpdyFramer::SpdyError
BufferedSpdyFramer::error_code() const {
264 return spdy_framer_
.error_code();
267 SpdyFramer::SpdyState
BufferedSpdyFramer::state() const {
268 return spdy_framer_
.state();
271 bool BufferedSpdyFramer::MessageFullyRead() {
272 return state() == SpdyFramer::SPDY_AUTO_RESET
;
275 bool BufferedSpdyFramer::HasError() {
276 return spdy_framer_
.HasError();
279 // TODO(jgraettinger): Eliminate uses of this method (prefer
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
);
297 // TODO(jgraettinger): Eliminate uses of this method (prefer
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
);
310 // TODO(jgraettinger): Eliminate uses of this method (prefer
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
);
321 // TODO(jgraettinger): Eliminate uses of this method (prefer
323 SpdyFrame
* BufferedSpdyFramer::CreateSettings(
324 const SettingsMap
& values
) const {
325 SpdySettingsIR settings_ir
;
326 for (SettingsMap::const_iterator it
= values
.begin();
329 settings_ir
.AddSetting(
331 (it
->second
.first
& SETTINGS_FLAG_PLEASE_PERSIST
) != 0,
332 (it
->second
.first
& SETTINGS_FLAG_PERSISTED
) != 0,
335 return spdy_framer_
.SerializeSettings(settings_ir
);
338 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR).
339 SpdyFrame
* BufferedSpdyFramer::CreatePingFrame(SpdyPingId unique_id
,
341 SpdyPingIR
ping_ir(unique_id
);
342 ping_ir
.set_is_ack(is_ack
);
343 return spdy_framer_
.SerializePing(ping_ir
);
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
);
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
);
366 headers_ir
.set_name_value_block(*headers
);
367 return spdy_framer_
.SerializeHeaders(headers_ir
);
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
);
379 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR).
380 SpdyFrame
* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id
,
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
);
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
);
400 SpdyPriority
BufferedSpdyFramer::GetHighestPriority() const {
401 return spdy_framer_
.GetHighestPriority();
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
);