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
:
22 case kProtoQUIC1SPDY3
:
29 BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version
,
30 bool enable_compression
)
31 : spdy_framer_(version
),
33 header_buffer_used_(0),
34 header_buffer_valid_(false),
35 header_stream_id_(SpdyFramer::kInvalidStream
),
37 spdy_framer_
.set_enable_compression(enable_compression
);
38 memset(header_buffer_
, 0, sizeof(header_buffer_
));
41 BufferedSpdyFramer::~BufferedSpdyFramer() {
44 void BufferedSpdyFramer::set_visitor(
45 BufferedSpdyFramerVisitorInterface
* visitor
) {
47 spdy_framer_
.set_visitor(this);
50 void BufferedSpdyFramer::set_debug_visitor(
51 SpdyFramerDebugVisitorInterface
* debug_visitor
) {
52 spdy_framer_
.set_debug_visitor(debug_visitor
);
55 void BufferedSpdyFramer::OnError(SpdyFramer
* spdy_framer
) {
57 visitor_
->OnError(spdy_framer
->error_code());
60 void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id
,
61 SpdyStreamId associated_stream_id
,
62 SpdyPriority priority
,
64 bool unidirectional
) {
66 DCHECK(!control_frame_fields_
.get());
67 control_frame_fields_
.reset(new ControlFrameFields());
68 control_frame_fields_
->type
= SYN_STREAM
;
69 control_frame_fields_
->stream_id
= stream_id
;
70 control_frame_fields_
->associated_stream_id
= associated_stream_id
;
71 control_frame_fields_
->priority
= priority
;
72 control_frame_fields_
->fin
= fin
;
73 control_frame_fields_
->unidirectional
= unidirectional
;
75 InitHeaderStreaming(stream_id
);
78 void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id
,
82 DCHECK(!control_frame_fields_
.get());
83 control_frame_fields_
.reset(new ControlFrameFields());
84 control_frame_fields_
->type
= HEADERS
;
85 control_frame_fields_
->stream_id
= stream_id
;
86 control_frame_fields_
->fin
= fin
;
88 InitHeaderStreaming(stream_id
);
91 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id
,
94 DCHECK(!control_frame_fields_
.get());
95 control_frame_fields_
.reset(new ControlFrameFields());
96 control_frame_fields_
->type
= SYN_REPLY
;
97 control_frame_fields_
->stream_id
= stream_id
;
98 control_frame_fields_
->fin
= fin
;
100 InitHeaderStreaming(stream_id
);
103 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id
,
104 const char* header_data
,
106 CHECK_EQ(header_stream_id_
, stream_id
);
109 // Indicates end-of-header-block.
110 CHECK(header_buffer_valid_
);
112 SpdyHeaderBlock headers
;
113 size_t parsed_len
= spdy_framer_
.ParseHeaderBlockInBuffer(
114 header_buffer_
, header_buffer_used_
, &headers
);
115 // TODO(rch): this really should be checking parsed_len != len,
116 // but a bunch of tests fail. Need to figure out why.
117 if (parsed_len
== 0) {
118 visitor_
->OnStreamError(
119 stream_id
, "Could not parse Spdy Control Frame Header.");
122 DCHECK(control_frame_fields_
.get());
123 switch (control_frame_fields_
->type
) {
125 visitor_
->OnSynStream(control_frame_fields_
->stream_id
,
126 control_frame_fields_
->associated_stream_id
,
127 control_frame_fields_
->priority
,
128 control_frame_fields_
->fin
,
129 control_frame_fields_
->unidirectional
,
133 visitor_
->OnSynReply(control_frame_fields_
->stream_id
,
134 control_frame_fields_
->fin
,
138 visitor_
->OnHeaders(control_frame_fields_
->stream_id
,
139 control_frame_fields_
->fin
,
143 DCHECK_LT(SPDY3
, protocol_version());
144 visitor_
->OnPushPromise(control_frame_fields_
->stream_id
,
145 control_frame_fields_
->promised_stream_id
,
149 DCHECK(false) << "Unexpect control frame type: "
150 << control_frame_fields_
->type
;
153 control_frame_fields_
.reset(NULL
);
157 const size_t available
= kHeaderBufferSize
- header_buffer_used_
;
158 if (len
> available
) {
159 header_buffer_valid_
= false;
160 visitor_
->OnStreamError(
161 stream_id
, "Received more data than the allocated size.");
164 memcpy(header_buffer_
+ header_buffer_used_
, header_data
, len
);
165 header_buffer_used_
+= len
;
169 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id
,
173 header_stream_id_
= stream_id
;
174 visitor_
->OnDataFrameHeader(stream_id
, length
, fin
);
177 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id
,
181 visitor_
->OnStreamFrameData(stream_id
, data
, len
, fin
);
184 void BufferedSpdyFramer::OnSettings(bool clear_persisted
) {
185 visitor_
->OnSettings(clear_persisted
);
188 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id
,
191 visitor_
->OnSetting(id
, flags
, value
);
194 void BufferedSpdyFramer::OnSettingsAck() {
195 visitor_
->OnSettingsAck();
198 void BufferedSpdyFramer::OnSettingsEnd() {
199 visitor_
->OnSettingsEnd();
202 void BufferedSpdyFramer::OnPing(SpdyPingId unique_id
, bool is_ack
) {
203 visitor_
->OnPing(unique_id
, is_ack
);
206 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id
,
207 SpdyRstStreamStatus status
) {
208 visitor_
->OnRstStream(stream_id
, status
);
210 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id
,
211 SpdyGoAwayStatus status
) {
212 visitor_
->OnGoAway(last_accepted_stream_id
, status
);
215 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id
,
216 uint32 delta_window_size
) {
217 visitor_
->OnWindowUpdate(stream_id
, delta_window_size
);
220 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id
,
221 SpdyStreamId promised_stream_id
,
223 DCHECK_LT(SPDY3
, protocol_version());
225 DCHECK(!control_frame_fields_
.get());
226 control_frame_fields_
.reset(new ControlFrameFields());
227 control_frame_fields_
->type
= PUSH_PROMISE
;
228 control_frame_fields_
->stream_id
= stream_id
;
229 control_frame_fields_
->promised_stream_id
= promised_stream_id
;
231 InitHeaderStreaming(stream_id
);
234 void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id
, bool end
) {
237 bool BufferedSpdyFramer::OnUnknownFrame(SpdyStreamId stream_id
,
239 return visitor_
->OnUnknownFrame(stream_id
, frame_type
);
242 SpdyMajorVersion
BufferedSpdyFramer::protocol_version() {
243 return spdy_framer_
.protocol_version();
246 size_t BufferedSpdyFramer::ProcessInput(const char* data
, size_t len
) {
247 return spdy_framer_
.ProcessInput(data
, len
);
250 void BufferedSpdyFramer::Reset() {
251 spdy_framer_
.Reset();
254 SpdyFramer::SpdyError
BufferedSpdyFramer::error_code() const {
255 return spdy_framer_
.error_code();
258 SpdyFramer::SpdyState
BufferedSpdyFramer::state() const {
259 return spdy_framer_
.state();
262 bool BufferedSpdyFramer::MessageFullyRead() {
263 return state() == SpdyFramer::SPDY_AUTO_RESET
;
266 bool BufferedSpdyFramer::HasError() {
267 return spdy_framer_
.HasError();
270 // TODO(jgraettinger): Eliminate uses of this method (prefer
272 SpdyFrame
* BufferedSpdyFramer::CreateSynStream(
273 SpdyStreamId stream_id
,
274 SpdyStreamId associated_stream_id
,
275 SpdyPriority priority
,
276 SpdyControlFlags flags
,
277 const SpdyHeaderBlock
* headers
) {
278 SpdySynStreamIR
syn_stream(stream_id
);
279 syn_stream
.set_associated_to_stream_id(associated_stream_id
);
280 syn_stream
.set_priority(priority
);
281 syn_stream
.set_fin((flags
& CONTROL_FLAG_FIN
) != 0);
282 syn_stream
.set_unidirectional((flags
& CONTROL_FLAG_UNIDIRECTIONAL
) != 0);
283 // TODO(hkhalil): Avoid copy here.
284 syn_stream
.set_name_value_block(*headers
);
285 return spdy_framer_
.SerializeSynStream(syn_stream
);
288 // TODO(jgraettinger): Eliminate uses of this method (prefer
290 SpdyFrame
* BufferedSpdyFramer::CreateSynReply(
291 SpdyStreamId stream_id
,
292 SpdyControlFlags flags
,
293 const SpdyHeaderBlock
* headers
) {
294 SpdySynReplyIR
syn_reply(stream_id
);
295 syn_reply
.set_fin(flags
& CONTROL_FLAG_FIN
);
296 // TODO(hkhalil): Avoid copy here.
297 syn_reply
.set_name_value_block(*headers
);
298 return spdy_framer_
.SerializeSynReply(syn_reply
);
301 // TODO(jgraettinger): Eliminate uses of this method (prefer
303 SpdyFrame
* BufferedSpdyFramer::CreateRstStream(
304 SpdyStreamId stream_id
,
305 SpdyRstStreamStatus status
) const {
306 // RST_STREAM payloads are not part of any SPDY spec.
307 // SpdyFramer will accept them, but don't create them.
308 SpdyRstStreamIR
rst_ir(stream_id
, status
, "");
309 return spdy_framer_
.SerializeRstStream(rst_ir
);
312 // TODO(jgraettinger): Eliminate uses of this method (prefer
314 SpdyFrame
* BufferedSpdyFramer::CreateSettings(
315 const SettingsMap
& values
) const {
316 SpdySettingsIR settings_ir
;
317 for (SettingsMap::const_iterator it
= values
.begin();
320 settings_ir
.AddSetting(
322 (it
->second
.first
& SETTINGS_FLAG_PLEASE_PERSIST
) != 0,
323 (it
->second
.first
& SETTINGS_FLAG_PERSISTED
) != 0,
326 return spdy_framer_
.SerializeSettings(settings_ir
);
329 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR).
330 SpdyFrame
* BufferedSpdyFramer::CreatePingFrame(uint32 unique_id
,
332 SpdyPingIR
ping_ir(unique_id
);
333 ping_ir
.set_is_ack(is_ack
);
334 return spdy_framer_
.SerializePing(ping_ir
);
337 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyGoAwayIR).
338 SpdyFrame
* BufferedSpdyFramer::CreateGoAway(
339 SpdyStreamId last_accepted_stream_id
,
340 SpdyGoAwayStatus status
) const {
341 SpdyGoAwayIR
go_ir(last_accepted_stream_id
, status
, "");
342 return spdy_framer_
.SerializeGoAway(go_ir
);
345 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyHeadersIR).
346 SpdyFrame
* BufferedSpdyFramer::CreateHeaders(
347 SpdyStreamId stream_id
,
348 SpdyControlFlags flags
,
349 const SpdyHeaderBlock
* headers
) {
350 SpdyHeadersIR
headers_ir(stream_id
);
351 headers_ir
.set_fin((flags
& CONTROL_FLAG_FIN
) != 0);
352 headers_ir
.set_name_value_block(*headers
);
353 return spdy_framer_
.SerializeHeaders(headers_ir
);
356 // TODO(jgraettinger): Eliminate uses of this method (prefer
357 // SpdyWindowUpdateIR).
358 SpdyFrame
* BufferedSpdyFramer::CreateWindowUpdate(
359 SpdyStreamId stream_id
,
360 uint32 delta_window_size
) const {
361 SpdyWindowUpdateIR
update_ir(stream_id
, delta_window_size
);
362 return spdy_framer_
.SerializeWindowUpdate(update_ir
);
365 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR).
366 SpdyFrame
* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id
,
369 SpdyDataFlags flags
) {
370 SpdyDataIR
data_ir(stream_id
,
371 base::StringPiece(data
, len
));
372 data_ir
.set_fin((flags
& DATA_FLAG_FIN
) != 0);
373 return spdy_framer_
.SerializeData(data_ir
);
376 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPushPromiseIR).
377 SpdyFrame
* BufferedSpdyFramer::CreatePushPromise(
378 SpdyStreamId stream_id
,
379 SpdyStreamId promised_stream_id
,
380 const SpdyHeaderBlock
* headers
) {
381 SpdyPushPromiseIR
push_promise_ir(stream_id
, promised_stream_id
);
382 push_promise_ir
.set_name_value_block(*headers
);
383 return spdy_framer_
.SerializePushPromise(push_promise_ir
);
386 SpdyPriority
BufferedSpdyFramer::GetHighestPriority() const {
387 return spdy_framer_
.GetHighestPriority();
390 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id
) {
391 memset(header_buffer_
, 0, kHeaderBufferSize
);
392 header_buffer_used_
= 0;
393 header_buffer_valid_
= true;
394 header_stream_id_
= stream_id
;
395 DCHECK_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);