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,
65 uint8 credential_slot,
67 bool unidirectional) {
69 DCHECK(!control_frame_fields_.get());
70 control_frame_fields_.reset(new ControlFrameFields());
71 control_frame_fields_->type = SYN_STREAM;
72 control_frame_fields_->stream_id = stream_id;
73 control_frame_fields_->associated_stream_id = associated_stream_id;
74 control_frame_fields_->priority = priority;
75 control_frame_fields_->credential_slot = credential_slot;
76 control_frame_fields_->fin = fin;
77 control_frame_fields_->unidirectional = unidirectional;
79 InitHeaderStreaming(stream_id);
82 void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id,
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_->fin = fin;
91 InitHeaderStreaming(stream_id);
94 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id,
97 DCHECK(!control_frame_fields_.get());
98 control_frame_fields_.reset(new ControlFrameFields());
99 control_frame_fields_->type = SYN_REPLY;
100 control_frame_fields_->stream_id = stream_id;
101 control_frame_fields_->fin = fin;
103 InitHeaderStreaming(stream_id);
106 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id,
107 const char* header_data,
109 CHECK_EQ(header_stream_id_, stream_id);
112 // Indicates end-of-header-block.
113 CHECK(header_buffer_valid_);
115 SpdyHeaderBlock headers;
116 size_t parsed_len = spdy_framer_.ParseHeaderBlockInBuffer(
117 header_buffer_, header_buffer_used_, &headers);
118 // TODO(rch): this really should be checking parsed_len != len,
119 // but a bunch of tests fail. Need to figure out why.
120 if (parsed_len == 0) {
121 visitor_->OnStreamError(
122 stream_id, "Could not parse Spdy Control Frame Header.");
125 DCHECK(control_frame_fields_.get());
126 switch (control_frame_fields_->type) {
128 visitor_->OnSynStream(control_frame_fields_->stream_id,
129 control_frame_fields_->associated_stream_id,
130 control_frame_fields_->priority,
131 control_frame_fields_->credential_slot,
132 control_frame_fields_->fin,
133 control_frame_fields_->unidirectional,
137 visitor_->OnSynReply(control_frame_fields_->stream_id,
138 control_frame_fields_->fin,
142 visitor_->OnHeaders(control_frame_fields_->stream_id,
143 control_frame_fields_->fin,
147 DCHECK(false) << "Unexpect control frame type: "
148 << control_frame_fields_->type;
151 control_frame_fields_.reset(NULL);
155 const size_t available = kHeaderBufferSize - header_buffer_used_;
156 if (len > available) {
157 header_buffer_valid_ = false;
158 visitor_->OnStreamError(
159 stream_id, "Received more data than the allocated size.");
162 memcpy(header_buffer_ + header_buffer_used_, header_data, len);
163 header_buffer_used_ += len;
167 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id,
171 header_stream_id_ = stream_id;
172 visitor_->OnDataFrameHeader(stream_id, length, fin);
175 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id,
179 visitor_->OnStreamFrameData(stream_id, data, len, fin);
182 void BufferedSpdyFramer::OnSettings(bool clear_persisted) {
183 visitor_->OnSettings(clear_persisted);
186 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id,
189 visitor_->OnSetting(id, flags, value);
192 void BufferedSpdyFramer::OnPing(uint32 unique_id) {
193 visitor_->OnPing(unique_id);
196 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id,
197 SpdyRstStreamStatus status) {
198 visitor_->OnRstStream(stream_id, status);
200 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id,
201 SpdyGoAwayStatus status) {
202 visitor_->OnGoAway(last_accepted_stream_id, status);
205 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id,
206 uint32 delta_window_size) {
207 visitor_->OnWindowUpdate(stream_id, delta_window_size);
210 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id,
211 SpdyStreamId promised_stream_id) {
212 visitor_->OnPushPromise(stream_id, promised_stream_id);
215 SpdyMajorVersion BufferedSpdyFramer::protocol_version() {
216 return spdy_framer_.protocol_version();
219 size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
220 return spdy_framer_.ProcessInput(data, len);
223 void BufferedSpdyFramer::Reset() {
224 spdy_framer_.Reset();
227 SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const {
228 return spdy_framer_.error_code();
231 SpdyFramer::SpdyState BufferedSpdyFramer::state() const {
232 return spdy_framer_.state();
235 bool BufferedSpdyFramer::MessageFullyRead() {
236 return state() == SpdyFramer::SPDY_AUTO_RESET;
239 bool BufferedSpdyFramer::HasError() {
240 return spdy_framer_.HasError();
243 // TODO(jgraettinger): Eliminate uses of this method (prefer
245 SpdyFrame* BufferedSpdyFramer::CreateSynStream(
246 SpdyStreamId stream_id,
247 SpdyStreamId associated_stream_id,
248 SpdyPriority priority,
249 uint8 credential_slot,
250 SpdyControlFlags flags,
251 const SpdyHeaderBlock* headers) {
252 SpdySynStreamIR syn_stream(stream_id);
253 syn_stream.set_associated_to_stream_id(associated_stream_id);
254 syn_stream.set_priority(priority);
255 syn_stream.set_slot(credential_slot);
256 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
257 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
258 // TODO(hkhalil): Avoid copy here.
259 syn_stream.set_name_value_block(*headers);
260 return spdy_framer_.SerializeSynStream(syn_stream);
263 // TODO(jgraettinger): Eliminate uses of this method (prefer
265 SpdyFrame* BufferedSpdyFramer::CreateSynReply(
266 SpdyStreamId stream_id,
267 SpdyControlFlags flags,
268 const SpdyHeaderBlock* headers) {
269 SpdySynReplyIR syn_reply(stream_id);
270 syn_reply.set_fin(flags & CONTROL_FLAG_FIN);
271 // TODO(hkhalil): Avoid copy here.
272 syn_reply.set_name_value_block(*headers);
273 return spdy_framer_.SerializeSynReply(syn_reply);
276 // TODO(jgraettinger): Eliminate uses of this method (prefer
278 SpdyFrame* BufferedSpdyFramer::CreateRstStream(
279 SpdyStreamId stream_id,
280 SpdyRstStreamStatus status) const {
281 SpdyRstStreamIR rst_ir(stream_id, status, "RST");
282 return spdy_framer_.SerializeRstStream(rst_ir);
285 // TODO(jgraettinger): Eliminate uses of this method (prefer
287 SpdyFrame* BufferedSpdyFramer::CreateSettings(
288 const SettingsMap& values) const {
289 SpdySettingsIR settings_ir;
290 for (SettingsMap::const_iterator it = values.begin();
293 settings_ir.AddSetting(
295 (it->second.first & SETTINGS_FLAG_PLEASE_PERSIST) != 0,
296 (it->second.first & SETTINGS_FLAG_PERSISTED) != 0,
299 return spdy_framer_.SerializeSettings(settings_ir);
302 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR).
303 SpdyFrame* BufferedSpdyFramer::CreatePingFrame(uint32 unique_id) const {
304 SpdyPingIR ping_ir(unique_id);
305 return spdy_framer_.SerializePing(ping_ir);
308 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyGoAwayIR).
309 SpdyFrame* BufferedSpdyFramer::CreateGoAway(
310 SpdyStreamId last_accepted_stream_id,
311 SpdyGoAwayStatus status) const {
312 SpdyGoAwayIR go_ir(last_accepted_stream_id, status, "");
313 return spdy_framer_.SerializeGoAway(go_ir);
316 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyHeadersIR).
317 SpdyFrame* BufferedSpdyFramer::CreateHeaders(
318 SpdyStreamId stream_id,
319 SpdyControlFlags flags,
320 const SpdyHeaderBlock* headers) {
321 SpdyHeadersIR headers_ir(stream_id);
322 headers_ir.set_fin((flags & CONTROL_FLAG_FIN) != 0);
323 headers_ir.set_name_value_block(*headers);
324 return spdy_framer_.SerializeHeaders(headers_ir);
327 // TODO(jgraettinger): Eliminate uses of this method (prefer
328 // SpdyWindowUpdateIR).
329 SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate(
330 SpdyStreamId stream_id,
331 uint32 delta_window_size) const {
332 SpdyWindowUpdateIR update_ir(stream_id, delta_window_size);
333 return spdy_framer_.SerializeWindowUpdate(update_ir);
336 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR).
337 SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
340 SpdyDataFlags flags) {
341 SpdyDataIR data_ir(stream_id,
342 base::StringPiece(data, len));
343 data_ir.set_fin((flags & DATA_FLAG_FIN) != 0);
344 return spdy_framer_.SerializeData(data_ir);
347 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const {
348 return spdy_framer_.GetHighestPriority();
351 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) {
352 memset(header_buffer_, 0, kHeaderBufferSize);
353 header_buffer_used_ = 0;
354 header_buffer_valid_ = true;
355 header_stream_id_ = stream_id;
356 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);