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
:
18 // SPDY/4 and HTTP/2 share the same framing for now.
20 case kProtoHTTP2Draft04
:
24 case kProtoQUIC1SPDY3
:
31 BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version
,
32 bool enable_compression
)
33 : spdy_framer_(version
),
35 header_buffer_used_(0),
36 header_buffer_valid_(false),
37 header_stream_id_(SpdyFramer::kInvalidStream
),
39 spdy_framer_
.set_enable_compression(enable_compression
);
40 memset(header_buffer_
, 0, sizeof(header_buffer_
));
43 BufferedSpdyFramer::~BufferedSpdyFramer() {
46 void BufferedSpdyFramer::set_visitor(
47 BufferedSpdyFramerVisitorInterface
* visitor
) {
49 spdy_framer_
.set_visitor(this);
52 void BufferedSpdyFramer::set_debug_visitor(
53 SpdyFramerDebugVisitorInterface
* debug_visitor
) {
54 spdy_framer_
.set_debug_visitor(debug_visitor
);
57 void BufferedSpdyFramer::OnError(SpdyFramer
* spdy_framer
) {
59 visitor_
->OnError(spdy_framer
->error_code());
62 void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id
,
63 SpdyStreamId associated_stream_id
,
64 SpdyPriority priority
,
66 bool unidirectional
) {
68 DCHECK(!control_frame_fields_
.get());
69 control_frame_fields_
.reset(new ControlFrameFields());
70 control_frame_fields_
->type
= SYN_STREAM
;
71 control_frame_fields_
->stream_id
= stream_id
;
72 control_frame_fields_
->associated_stream_id
= associated_stream_id
;
73 control_frame_fields_
->priority
= priority
;
74 control_frame_fields_
->fin
= fin
;
75 control_frame_fields_
->unidirectional
= unidirectional
;
77 InitHeaderStreaming(stream_id
);
80 void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id
,
84 DCHECK(!control_frame_fields_
.get());
85 control_frame_fields_
.reset(new ControlFrameFields());
86 control_frame_fields_
->type
= HEADERS
;
87 control_frame_fields_
->stream_id
= stream_id
;
88 control_frame_fields_
->fin
= fin
;
90 InitHeaderStreaming(stream_id
);
93 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id
,
96 DCHECK(!control_frame_fields_
.get());
97 control_frame_fields_
.reset(new ControlFrameFields());
98 control_frame_fields_
->type
= SYN_REPLY
;
99 control_frame_fields_
->stream_id
= stream_id
;
100 control_frame_fields_
->fin
= fin
;
102 InitHeaderStreaming(stream_id
);
105 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id
,
106 const char* header_data
,
108 CHECK_EQ(header_stream_id_
, stream_id
);
111 // Indicates end-of-header-block.
112 CHECK(header_buffer_valid_
);
114 SpdyHeaderBlock headers
;
115 size_t parsed_len
= spdy_framer_
.ParseHeaderBlockInBuffer(
116 header_buffer_
, header_buffer_used_
, &headers
);
117 // TODO(rch): this really should be checking parsed_len != len,
118 // but a bunch of tests fail. Need to figure out why.
119 if (parsed_len
== 0) {
120 visitor_
->OnStreamError(
121 stream_id
, "Could not parse Spdy Control Frame Header.");
124 DCHECK(control_frame_fields_
.get());
125 switch (control_frame_fields_
->type
) {
127 visitor_
->OnSynStream(control_frame_fields_
->stream_id
,
128 control_frame_fields_
->associated_stream_id
,
129 control_frame_fields_
->priority
,
130 control_frame_fields_
->fin
,
131 control_frame_fields_
->unidirectional
,
135 visitor_
->OnSynReply(control_frame_fields_
->stream_id
,
136 control_frame_fields_
->fin
,
140 visitor_
->OnHeaders(control_frame_fields_
->stream_id
,
141 control_frame_fields_
->fin
,
145 DCHECK(false) << "Unexpect control frame type: "
146 << control_frame_fields_
->type
;
149 control_frame_fields_
.reset(NULL
);
153 const size_t available
= kHeaderBufferSize
- header_buffer_used_
;
154 if (len
> available
) {
155 header_buffer_valid_
= false;
156 visitor_
->OnStreamError(
157 stream_id
, "Received more data than the allocated size.");
160 memcpy(header_buffer_
+ header_buffer_used_
, header_data
, len
);
161 header_buffer_used_
+= len
;
165 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id
,
169 header_stream_id_
= stream_id
;
170 visitor_
->OnDataFrameHeader(stream_id
, length
, fin
);
173 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id
,
177 visitor_
->OnStreamFrameData(stream_id
, data
, len
, fin
);
180 void BufferedSpdyFramer::OnSettings(bool clear_persisted
) {
181 visitor_
->OnSettings(clear_persisted
);
184 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id
,
187 visitor_
->OnSetting(id
, flags
, value
);
190 void BufferedSpdyFramer::OnSettingsAck() {
191 visitor_
->OnSettingsAck();
194 void BufferedSpdyFramer::OnSettingsEnd() {
195 visitor_
->OnSettingsEnd();
198 void BufferedSpdyFramer::OnPing(SpdyPingId unique_id
, bool is_ack
) {
199 visitor_
->OnPing(unique_id
, is_ack
);
202 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id
,
203 SpdyRstStreamStatus status
) {
204 visitor_
->OnRstStream(stream_id
, status
);
206 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id
,
207 SpdyGoAwayStatus status
) {
208 visitor_
->OnGoAway(last_accepted_stream_id
, status
);
211 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id
,
212 uint32 delta_window_size
) {
213 visitor_
->OnWindowUpdate(stream_id
, delta_window_size
);
216 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id
,
217 SpdyStreamId promised_stream_id
,
219 // TODO(jgraettinger): Deliver headers, similar to OnHeaders.
220 visitor_
->OnPushPromise(stream_id
, promised_stream_id
);
223 void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id
, bool end
) {
226 SpdyMajorVersion
BufferedSpdyFramer::protocol_version() {
227 return spdy_framer_
.protocol_version();
230 size_t BufferedSpdyFramer::ProcessInput(const char* data
, size_t len
) {
231 return spdy_framer_
.ProcessInput(data
, len
);
234 void BufferedSpdyFramer::Reset() {
235 spdy_framer_
.Reset();
238 SpdyFramer::SpdyError
BufferedSpdyFramer::error_code() const {
239 return spdy_framer_
.error_code();
242 SpdyFramer::SpdyState
BufferedSpdyFramer::state() const {
243 return spdy_framer_
.state();
246 bool BufferedSpdyFramer::MessageFullyRead() {
247 return state() == SpdyFramer::SPDY_AUTO_RESET
;
250 bool BufferedSpdyFramer::HasError() {
251 return spdy_framer_
.HasError();
254 // TODO(jgraettinger): Eliminate uses of this method (prefer
256 SpdyFrame
* BufferedSpdyFramer::CreateSynStream(
257 SpdyStreamId stream_id
,
258 SpdyStreamId associated_stream_id
,
259 SpdyPriority priority
,
260 SpdyControlFlags flags
,
261 const SpdyHeaderBlock
* headers
) {
262 SpdySynStreamIR
syn_stream(stream_id
);
263 syn_stream
.set_associated_to_stream_id(associated_stream_id
);
264 syn_stream
.set_priority(priority
);
265 syn_stream
.set_fin((flags
& CONTROL_FLAG_FIN
) != 0);
266 syn_stream
.set_unidirectional((flags
& CONTROL_FLAG_UNIDIRECTIONAL
) != 0);
267 // TODO(hkhalil): Avoid copy here.
268 syn_stream
.set_name_value_block(*headers
);
269 return spdy_framer_
.SerializeSynStream(syn_stream
);
272 // TODO(jgraettinger): Eliminate uses of this method (prefer
274 SpdyFrame
* BufferedSpdyFramer::CreateSynReply(
275 SpdyStreamId stream_id
,
276 SpdyControlFlags flags
,
277 const SpdyHeaderBlock
* headers
) {
278 SpdySynReplyIR
syn_reply(stream_id
);
279 syn_reply
.set_fin(flags
& CONTROL_FLAG_FIN
);
280 // TODO(hkhalil): Avoid copy here.
281 syn_reply
.set_name_value_block(*headers
);
282 return spdy_framer_
.SerializeSynReply(syn_reply
);
285 // TODO(jgraettinger): Eliminate uses of this method (prefer
287 SpdyFrame
* BufferedSpdyFramer::CreateRstStream(
288 SpdyStreamId stream_id
,
289 SpdyRstStreamStatus status
) const {
290 SpdyRstStreamIR
rst_ir(stream_id
, status
, "RST");
291 return spdy_framer_
.SerializeRstStream(rst_ir
);
294 // TODO(jgraettinger): Eliminate uses of this method (prefer
296 SpdyFrame
* BufferedSpdyFramer::CreateSettings(
297 const SettingsMap
& values
) const {
298 SpdySettingsIR settings_ir
;
299 for (SettingsMap::const_iterator it
= values
.begin();
302 settings_ir
.AddSetting(
304 (it
->second
.first
& SETTINGS_FLAG_PLEASE_PERSIST
) != 0,
305 (it
->second
.first
& SETTINGS_FLAG_PERSISTED
) != 0,
308 return spdy_framer_
.SerializeSettings(settings_ir
);
311 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR).
312 SpdyFrame
* BufferedSpdyFramer::CreatePingFrame(uint32 unique_id
,
314 SpdyPingIR
ping_ir(unique_id
);
315 ping_ir
.set_is_ack(is_ack
);
316 return spdy_framer_
.SerializePing(ping_ir
);
319 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyGoAwayIR).
320 SpdyFrame
* BufferedSpdyFramer::CreateGoAway(
321 SpdyStreamId last_accepted_stream_id
,
322 SpdyGoAwayStatus status
) const {
323 SpdyGoAwayIR
go_ir(last_accepted_stream_id
, status
, "");
324 return spdy_framer_
.SerializeGoAway(go_ir
);
327 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyHeadersIR).
328 SpdyFrame
* BufferedSpdyFramer::CreateHeaders(
329 SpdyStreamId stream_id
,
330 SpdyControlFlags flags
,
331 const SpdyHeaderBlock
* headers
) {
332 SpdyHeadersIR
headers_ir(stream_id
);
333 headers_ir
.set_fin((flags
& CONTROL_FLAG_FIN
) != 0);
334 headers_ir
.set_name_value_block(*headers
);
335 return spdy_framer_
.SerializeHeaders(headers_ir
);
338 // TODO(jgraettinger): Eliminate uses of this method (prefer
339 // SpdyWindowUpdateIR).
340 SpdyFrame
* BufferedSpdyFramer::CreateWindowUpdate(
341 SpdyStreamId stream_id
,
342 uint32 delta_window_size
) const {
343 SpdyWindowUpdateIR
update_ir(stream_id
, delta_window_size
);
344 return spdy_framer_
.SerializeWindowUpdate(update_ir
);
347 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR).
348 SpdyFrame
* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id
,
351 SpdyDataFlags flags
) {
352 SpdyDataIR
data_ir(stream_id
,
353 base::StringPiece(data
, len
));
354 data_ir
.set_fin((flags
& DATA_FLAG_FIN
) != 0);
355 return spdy_framer_
.SerializeData(data_ir
);
358 SpdyPriority
BufferedSpdyFramer::GetHighestPriority() const {
359 return spdy_framer_
.GetHighestPriority();
362 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id
) {
363 memset(header_buffer_
, 0, kHeaderBufferSize
);
364 header_buffer_used_
= 0;
365 header_buffer_valid_
= true;
366 header_stream_id_
= stream_id
;
367 DCHECK_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);