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 BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version
,
12 bool enable_compression
)
13 : spdy_framer_(version
),
15 header_buffer_used_(0),
16 header_buffer_valid_(false),
17 header_stream_id_(SpdyFramer::kInvalidStream
),
19 spdy_framer_
.set_enable_compression(enable_compression
);
20 memset(header_buffer_
, 0, sizeof(header_buffer_
));
23 BufferedSpdyFramer::~BufferedSpdyFramer() {
26 void BufferedSpdyFramer::set_visitor(
27 BufferedSpdyFramerVisitorInterface
* visitor
) {
29 spdy_framer_
.set_visitor(this);
32 void BufferedSpdyFramer::OnError(SpdyFramer
* spdy_framer
) {
34 visitor_
->OnError(spdy_framer
->error_code());
37 void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id
,
38 SpdyStreamId associated_stream_id
,
39 SpdyPriority priority
,
40 uint8 credential_slot
,
42 bool unidirectional
) {
44 DCHECK(!control_frame_fields_
.get());
45 control_frame_fields_
.reset(new ControlFrameFields());
46 control_frame_fields_
->type
= SYN_STREAM
;
47 control_frame_fields_
->stream_id
= stream_id
;
48 control_frame_fields_
->associated_stream_id
= associated_stream_id
;
49 control_frame_fields_
->priority
= priority
;
50 control_frame_fields_
->credential_slot
= credential_slot
;
51 control_frame_fields_
->fin
= fin
;
52 control_frame_fields_
->unidirectional
= unidirectional
;
54 InitHeaderStreaming(stream_id
);
57 void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id
,
60 DCHECK(!control_frame_fields_
.get());
61 control_frame_fields_
.reset(new ControlFrameFields());
62 control_frame_fields_
->type
= HEADERS
;
63 control_frame_fields_
->stream_id
= stream_id
;
64 control_frame_fields_
->fin
= fin
;
66 InitHeaderStreaming(stream_id
);
69 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id
,
72 DCHECK(!control_frame_fields_
.get());
73 control_frame_fields_
.reset(new ControlFrameFields());
74 control_frame_fields_
->type
= SYN_REPLY
;
75 control_frame_fields_
->stream_id
= stream_id
;
76 control_frame_fields_
->fin
= fin
;
78 InitHeaderStreaming(stream_id
);
81 bool BufferedSpdyFramer::OnCredentialFrameData(const char* frame_data
,
87 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id
,
88 const char* header_data
,
90 CHECK_EQ(header_stream_id_
, stream_id
);
93 // Indicates end-of-header-block.
94 CHECK(header_buffer_valid_
);
96 SpdyHeaderBlock headers
;
97 size_t parsed_len
= spdy_framer_
.ParseHeaderBlockInBuffer(
98 header_buffer_
, header_buffer_used_
, &headers
);
99 // TODO(rch): this really should be checking parsed_len != len,
100 // but a bunch of tests fail. Need to figure out why.
101 if (parsed_len
== 0) {
102 visitor_
->OnStreamError(
103 stream_id
, "Could not parse Spdy Control Frame Header.");
106 DCHECK(control_frame_fields_
.get());
107 switch (control_frame_fields_
->type
) {
109 visitor_
->OnSynStream(control_frame_fields_
->stream_id
,
110 control_frame_fields_
->associated_stream_id
,
111 control_frame_fields_
->priority
,
112 control_frame_fields_
->credential_slot
,
113 control_frame_fields_
->fin
,
114 control_frame_fields_
->unidirectional
,
118 visitor_
->OnSynReply(control_frame_fields_
->stream_id
,
119 control_frame_fields_
->fin
,
123 visitor_
->OnHeaders(control_frame_fields_
->stream_id
,
124 control_frame_fields_
->fin
,
128 DCHECK(false) << "Unexpect control frame type: "
129 << control_frame_fields_
->type
;
132 control_frame_fields_
.reset(NULL
);
136 const size_t available
= kHeaderBufferSize
- header_buffer_used_
;
137 if (len
> available
) {
138 header_buffer_valid_
= false;
139 visitor_
->OnStreamError(
140 stream_id
, "Received more data than the allocated size.");
143 memcpy(header_buffer_
+ header_buffer_used_
, header_data
, len
);
144 header_buffer_used_
+= len
;
148 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id
,
152 header_stream_id_
= stream_id
;
155 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id
,
159 visitor_
->OnStreamFrameData(stream_id
, data
, len
, fin
);
162 void BufferedSpdyFramer::OnSettings(bool clear_persisted
) {
163 visitor_
->OnSettings(clear_persisted
);
166 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id
,
169 visitor_
->OnSetting(id
, flags
, value
);
172 void BufferedSpdyFramer::OnPing(uint32 unique_id
) {
173 visitor_
->OnPing(unique_id
);
176 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id
,
177 SpdyRstStreamStatus status
) {
178 visitor_
->OnRstStream(stream_id
, status
);
180 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id
,
181 SpdyGoAwayStatus status
) {
182 visitor_
->OnGoAway(last_accepted_stream_id
, status
);
185 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id
,
186 uint32 delta_window_size
) {
187 visitor_
->OnWindowUpdate(stream_id
, delta_window_size
);
190 void BufferedSpdyFramer::OnSynStreamCompressed(
191 size_t uncompressed_size
,
192 size_t compressed_size
) {
193 visitor_
->OnSynStreamCompressed(uncompressed_size
, compressed_size
);
196 int BufferedSpdyFramer::protocol_version() {
197 return spdy_framer_
.protocol_version();
200 size_t BufferedSpdyFramer::ProcessInput(const char* data
, size_t len
) {
201 return spdy_framer_
.ProcessInput(data
, len
);
204 void BufferedSpdyFramer::Reset() {
205 spdy_framer_
.Reset();
208 SpdyFramer::SpdyError
BufferedSpdyFramer::error_code() const {
209 return spdy_framer_
.error_code();
212 SpdyFramer::SpdyState
BufferedSpdyFramer::state() const {
213 return spdy_framer_
.state();
216 bool BufferedSpdyFramer::MessageFullyRead() {
217 return state() == SpdyFramer::SPDY_AUTO_RESET
;
220 bool BufferedSpdyFramer::HasError() {
221 return spdy_framer_
.HasError();
224 SpdyFrame
* BufferedSpdyFramer::CreateSynStream(
225 SpdyStreamId stream_id
,
226 SpdyStreamId associated_stream_id
,
227 SpdyPriority priority
,
228 uint8 credential_slot
,
229 SpdyControlFlags flags
,
231 const SpdyHeaderBlock
* headers
) {
232 return spdy_framer_
.CreateSynStream(stream_id
, associated_stream_id
, priority
,
233 credential_slot
, flags
, compressed
,
237 SpdyFrame
* BufferedSpdyFramer::CreateSynReply(
238 SpdyStreamId stream_id
,
239 SpdyControlFlags flags
,
241 const SpdyHeaderBlock
* headers
) {
242 return spdy_framer_
.CreateSynReply(stream_id
, flags
, compressed
, headers
);
245 SpdyFrame
* BufferedSpdyFramer::CreateRstStream(
246 SpdyStreamId stream_id
,
247 SpdyRstStreamStatus status
) const {
248 return spdy_framer_
.CreateRstStream(stream_id
, status
);
251 SpdyFrame
* BufferedSpdyFramer::CreateSettings(
252 const SettingsMap
& values
) const {
253 return spdy_framer_
.CreateSettings(values
);
256 SpdyFrame
* BufferedSpdyFramer::CreatePingFrame(
257 uint32 unique_id
) const {
258 return spdy_framer_
.CreatePingFrame(unique_id
);
261 SpdyFrame
* BufferedSpdyFramer::CreateGoAway(
262 SpdyStreamId last_accepted_stream_id
,
263 SpdyGoAwayStatus status
) const {
264 return spdy_framer_
.CreateGoAway(last_accepted_stream_id
, status
);
267 SpdyFrame
* BufferedSpdyFramer::CreateHeaders(
268 SpdyStreamId stream_id
,
269 SpdyControlFlags flags
,
271 const SpdyHeaderBlock
* headers
) {
272 return spdy_framer_
.CreateHeaders(stream_id
, flags
, compressed
, headers
);
275 SpdyFrame
* BufferedSpdyFramer::CreateWindowUpdate(
276 SpdyStreamId stream_id
,
277 uint32 delta_window_size
) const {
278 return spdy_framer_
.CreateWindowUpdate(stream_id
, delta_window_size
);
281 SpdyFrame
* BufferedSpdyFramer::CreateCredentialFrame(
282 const SpdyCredential
& credential
) const {
283 return spdy_framer_
.CreateCredentialFrame(credential
);
286 SpdyFrame
* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id
,
289 SpdyDataFlags flags
) {
290 return spdy_framer_
.CreateDataFrame(stream_id
, data
, len
, flags
);
293 SpdyPriority
BufferedSpdyFramer::GetHighestPriority() const {
294 return spdy_framer_
.GetHighestPriority();
297 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id
) {
298 memset(header_buffer_
, 0, kHeaderBufferSize
);
299 header_buffer_used_
= 0;
300 header_buffer_valid_
= true;
301 header_stream_id_
= stream_id
;
302 DCHECK_NE(header_stream_id_
, SpdyFramer::kInvalidStream
);