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
) {
19 // SPDY/4 and HTTP/2 share the same framing for now.
21 case kProtoHTTP2Draft04
:
26 case kProtoQUIC1SPDY3
:
33 BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version
,
34 bool enable_compression
)
35 : spdy_framer_(version
),
37 header_buffer_used_(0),
38 header_buffer_valid_(false),
39 header_stream_id_(SpdyFramer::kInvalidStream
),
41 spdy_framer_
.set_enable_compression(enable_compression
);
42 memset(header_buffer_
, 0, sizeof(header_buffer_
));
45 BufferedSpdyFramer::~BufferedSpdyFramer() {
48 void BufferedSpdyFramer::set_visitor(
49 BufferedSpdyFramerVisitorInterface
* visitor
) {
51 spdy_framer_
.set_visitor(this);
54 void BufferedSpdyFramer::set_debug_visitor(
55 SpdyFramerDebugVisitorInterface
* debug_visitor
) {
56 spdy_framer_
.set_debug_visitor(debug_visitor
);
59 void BufferedSpdyFramer::OnError(SpdyFramer
* spdy_framer
) {
61 visitor_
->OnError(spdy_framer
->error_code());
64 void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id
,
65 SpdyStreamId associated_stream_id
,
66 SpdyPriority priority
,
67 uint8 credential_slot
,
69 bool unidirectional
) {
71 DCHECK(!control_frame_fields_
.get());
72 control_frame_fields_
.reset(new ControlFrameFields());
73 control_frame_fields_
->type
= SYN_STREAM
;
74 control_frame_fields_
->stream_id
= stream_id
;
75 control_frame_fields_
->associated_stream_id
= associated_stream_id
;
76 control_frame_fields_
->priority
= priority
;
77 control_frame_fields_
->credential_slot
= credential_slot
;
78 control_frame_fields_
->fin
= fin
;
79 control_frame_fields_
->unidirectional
= unidirectional
;
81 InitHeaderStreaming(stream_id
);
84 void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id
,
87 DCHECK(!control_frame_fields_
.get());
88 control_frame_fields_
.reset(new ControlFrameFields());
89 control_frame_fields_
->type
= HEADERS
;
90 control_frame_fields_
->stream_id
= stream_id
;
91 control_frame_fields_
->fin
= fin
;
93 InitHeaderStreaming(stream_id
);
96 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id
,
99 DCHECK(!control_frame_fields_
.get());
100 control_frame_fields_
.reset(new ControlFrameFields());
101 control_frame_fields_
->type
= SYN_REPLY
;
102 control_frame_fields_
->stream_id
= stream_id
;
103 control_frame_fields_
->fin
= fin
;
105 InitHeaderStreaming(stream_id
);
108 bool BufferedSpdyFramer::OnCredentialFrameData(const char* frame_data
,
114 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id
,
115 const char* header_data
,
117 CHECK_EQ(header_stream_id_
, stream_id
);
120 // Indicates end-of-header-block.
121 CHECK(header_buffer_valid_
);
123 SpdyHeaderBlock headers
;
124 size_t parsed_len
= spdy_framer_
.ParseHeaderBlockInBuffer(
125 header_buffer_
, header_buffer_used_
, &headers
);
126 // TODO(rch): this really should be checking parsed_len != len,
127 // but a bunch of tests fail. Need to figure out why.
128 if (parsed_len
== 0) {
129 visitor_
->OnStreamError(
130 stream_id
, "Could not parse Spdy Control Frame Header.");
133 DCHECK(control_frame_fields_
.get());
134 switch (control_frame_fields_
->type
) {
136 visitor_
->OnSynStream(control_frame_fields_
->stream_id
,
137 control_frame_fields_
->associated_stream_id
,
138 control_frame_fields_
->priority
,
139 control_frame_fields_
->credential_slot
,
140 control_frame_fields_
->fin
,
141 control_frame_fields_
->unidirectional
,
145 visitor_
->OnSynReply(control_frame_fields_
->stream_id
,
146 control_frame_fields_
->fin
,
150 visitor_
->OnHeaders(control_frame_fields_
->stream_id
,
151 control_frame_fields_
->fin
,
155 DCHECK(false) << "Unexpect control frame type: "
156 << control_frame_fields_
->type
;
159 control_frame_fields_
.reset(NULL
);
163 const size_t available
= kHeaderBufferSize
- header_buffer_used_
;
164 if (len
> available
) {
165 header_buffer_valid_
= false;
166 visitor_
->OnStreamError(
167 stream_id
, "Received more data than the allocated size.");
170 memcpy(header_buffer_
+ header_buffer_used_
, header_data
, len
);
171 header_buffer_used_
+= len
;
175 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id
,
179 header_stream_id_
= stream_id
;
182 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id
,
186 visitor_
->OnStreamFrameData(stream_id
, data
, len
, fin
);
189 void BufferedSpdyFramer::OnSettings(bool clear_persisted
) {
190 visitor_
->OnSettings(clear_persisted
);
193 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id
,
196 visitor_
->OnSetting(id
, flags
, value
);
199 void BufferedSpdyFramer::OnPing(uint32 unique_id
) {
200 visitor_
->OnPing(unique_id
);
203 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id
,
204 SpdyRstStreamStatus status
) {
205 visitor_
->OnRstStream(stream_id
, status
);
207 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id
,
208 SpdyGoAwayStatus status
) {
209 visitor_
->OnGoAway(last_accepted_stream_id
, status
);
212 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id
,
213 uint32 delta_window_size
) {
214 visitor_
->OnWindowUpdate(stream_id
, delta_window_size
);
217 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id
,
218 SpdyStreamId promised_stream_id
) {
219 visitor_
->OnPushPromise(stream_id
, promised_stream_id
);
222 int BufferedSpdyFramer::protocol_version() {
223 return spdy_framer_
.protocol_version();
226 size_t BufferedSpdyFramer::ProcessInput(const char* data
, size_t len
) {
227 return spdy_framer_
.ProcessInput(data
, len
);
230 void BufferedSpdyFramer::Reset() {
231 spdy_framer_
.Reset();
234 SpdyFramer::SpdyError
BufferedSpdyFramer::error_code() const {
235 return spdy_framer_
.error_code();
238 SpdyFramer::SpdyState
BufferedSpdyFramer::state() const {
239 return spdy_framer_
.state();
242 bool BufferedSpdyFramer::MessageFullyRead() {
243 return state() == SpdyFramer::SPDY_AUTO_RESET
;
246 bool BufferedSpdyFramer::HasError() {
247 return spdy_framer_
.HasError();
250 SpdyFrame
* BufferedSpdyFramer::CreateSynStream(
251 SpdyStreamId stream_id
,
252 SpdyStreamId associated_stream_id
,
253 SpdyPriority priority
,
254 uint8 credential_slot
,
255 SpdyControlFlags flags
,
257 const SpdyHeaderBlock
* headers
) {
258 return spdy_framer_
.CreateSynStream(stream_id
, associated_stream_id
, priority
,
259 credential_slot
, flags
, compressed
,
263 SpdyFrame
* BufferedSpdyFramer::CreateSynReply(
264 SpdyStreamId stream_id
,
265 SpdyControlFlags flags
,
267 const SpdyHeaderBlock
* headers
) {
268 return spdy_framer_
.CreateSynReply(stream_id
, flags
, compressed
, headers
);
271 SpdyFrame
* BufferedSpdyFramer::CreateRstStream(
272 SpdyStreamId stream_id
,
273 SpdyRstStreamStatus status
) const {
274 return spdy_framer_
.CreateRstStream(stream_id
, status
);
277 SpdyFrame
* BufferedSpdyFramer::CreateSettings(
278 const SettingsMap
& values
) const {
279 return spdy_framer_
.CreateSettings(values
);
282 SpdyFrame
* BufferedSpdyFramer::CreatePingFrame(
283 uint32 unique_id
) const {
284 return spdy_framer_
.CreatePingFrame(unique_id
);
287 SpdyFrame
* BufferedSpdyFramer::CreateGoAway(
288 SpdyStreamId last_accepted_stream_id
,
289 SpdyGoAwayStatus status
) const {
290 return spdy_framer_
.CreateGoAway(last_accepted_stream_id
, status
);
293 SpdyFrame
* BufferedSpdyFramer::CreateHeaders(
294 SpdyStreamId stream_id
,
295 SpdyControlFlags flags
,
297 const SpdyHeaderBlock
* headers
) {
298 return spdy_framer_
.CreateHeaders(stream_id
, flags
, compressed
, headers
);
301 SpdyFrame
* BufferedSpdyFramer::CreateWindowUpdate(
302 SpdyStreamId stream_id
,
303 uint32 delta_window_size
) const {
304 return spdy_framer_
.CreateWindowUpdate(stream_id
, delta_window_size
);
307 SpdyFrame
* BufferedSpdyFramer::CreateCredentialFrame(
308 const SpdyCredential
& credential
) const {
309 return spdy_framer_
.CreateCredentialFrame(credential
);
312 SpdyFrame
* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id
,
315 SpdyDataFlags flags
) {
316 return spdy_framer_
.CreateDataFrame(stream_id
, data
, len
, flags
);
319 SpdyPriority
BufferedSpdyFramer::GetHighestPriority() const {
320 return spdy_framer_
.GetHighestPriority();
323 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id
) {
324 memset(header_buffer_
, 0, kHeaderBufferSize
);
325 header_buffer_used_
= 0;
326 header_buffer_valid_
= true;
327 header_stream_id_
= stream_id
;
328 DCHECK_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);