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,
80 SpdyPriority priority,
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_->has_priority = has_priority;
89 if (control_frame_fields_->has_priority) {
90 control_frame_fields_->priority = priority;
92 control_frame_fields_->fin = fin;
94 InitHeaderStreaming(stream_id);
97 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id,
100 DCHECK(!control_frame_fields_.get());
101 control_frame_fields_.reset(new ControlFrameFields());
102 control_frame_fields_->type = SYN_REPLY;
103 control_frame_fields_->stream_id = stream_id;
104 control_frame_fields_->fin = fin;
106 InitHeaderStreaming(stream_id);
109 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id,
110 const char* header_data,
112 CHECK_EQ(header_stream_id_, stream_id);
115 // Indicates end-of-header-block.
116 CHECK(header_buffer_valid_);
118 SpdyHeaderBlock headers;
119 size_t parsed_len = spdy_framer_.ParseHeaderBlockInBuffer(
120 header_buffer_, header_buffer_used_, &headers);
121 // TODO(rch): this really should be checking parsed_len != len,
122 // but a bunch of tests fail. Need to figure out why.
123 if (parsed_len == 0) {
124 visitor_->OnStreamError(
125 stream_id, "Could not parse Spdy Control Frame Header.");
128 DCHECK(control_frame_fields_.get());
129 switch (control_frame_fields_->type) {
131 visitor_->OnSynStream(control_frame_fields_->stream_id,
132 control_frame_fields_->associated_stream_id,
133 control_frame_fields_->priority,
134 control_frame_fields_->fin,
135 control_frame_fields_->unidirectional,
139 visitor_->OnSynReply(control_frame_fields_->stream_id,
140 control_frame_fields_->fin,
144 visitor_->OnHeaders(control_frame_fields_->stream_id,
145 control_frame_fields_->has_priority,
146 control_frame_fields_->priority,
147 control_frame_fields_->fin,
151 DCHECK_LT(SPDY3, protocol_version());
152 visitor_->OnPushPromise(control_frame_fields_->stream_id,
153 control_frame_fields_->promised_stream_id,
157 DCHECK(false) << "Unexpect control frame type: "
158 << control_frame_fields_->type;
161 control_frame_fields_.reset(NULL);
165 const size_t available = kHeaderBufferSize - header_buffer_used_;
166 if (len > available) {
167 header_buffer_valid_ = false;
168 visitor_->OnStreamError(
169 stream_id, "Received more data than the allocated size.");
172 memcpy(header_buffer_ + header_buffer_used_, header_data, len);
173 header_buffer_used_ += len;
177 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id,
181 header_stream_id_ = stream_id;
182 visitor_->OnDataFrameHeader(stream_id, length, fin);
185 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id,
189 visitor_->OnStreamFrameData(stream_id, data, len, fin);
192 void BufferedSpdyFramer::OnSettings(bool clear_persisted) {
193 visitor_->OnSettings(clear_persisted);
196 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id,
199 visitor_->OnSetting(id, flags, value);
202 void BufferedSpdyFramer::OnSettingsAck() {
203 visitor_->OnSettingsAck();
206 void BufferedSpdyFramer::OnSettingsEnd() {
207 visitor_->OnSettingsEnd();
210 void BufferedSpdyFramer::OnPing(SpdyPingId unique_id, bool is_ack) {
211 visitor_->OnPing(unique_id, is_ack);
214 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id,
215 SpdyRstStreamStatus status) {
216 visitor_->OnRstStream(stream_id, status);
218 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id,
219 SpdyGoAwayStatus status) {
220 visitor_->OnGoAway(last_accepted_stream_id, status);
223 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id,
224 uint32 delta_window_size) {
225 visitor_->OnWindowUpdate(stream_id, delta_window_size);
228 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id,
229 SpdyStreamId promised_stream_id,
231 DCHECK_LT(SPDY3, protocol_version());
233 DCHECK(!control_frame_fields_.get());
234 control_frame_fields_.reset(new ControlFrameFields());
235 control_frame_fields_->type = PUSH_PROMISE;
236 control_frame_fields_->stream_id = stream_id;
237 control_frame_fields_->promised_stream_id = promised_stream_id;
239 InitHeaderStreaming(stream_id);
242 void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id, bool end) {
245 bool BufferedSpdyFramer::OnUnknownFrame(SpdyStreamId stream_id,
247 return visitor_->OnUnknownFrame(stream_id, frame_type);
250 SpdyMajorVersion BufferedSpdyFramer::protocol_version() {
251 return spdy_framer_.protocol_version();
254 size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
255 return spdy_framer_.ProcessInput(data, len);
258 void BufferedSpdyFramer::Reset() {
259 spdy_framer_.Reset();
262 SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const {
263 return spdy_framer_.error_code();
266 SpdyFramer::SpdyState BufferedSpdyFramer::state() const {
267 return spdy_framer_.state();
270 bool BufferedSpdyFramer::MessageFullyRead() {
271 return state() == SpdyFramer::SPDY_AUTO_RESET;
274 bool BufferedSpdyFramer::HasError() {
275 return spdy_framer_.HasError();
278 // TODO(jgraettinger): Eliminate uses of this method (prefer
280 SpdyFrame* BufferedSpdyFramer::CreateSynStream(
281 SpdyStreamId stream_id,
282 SpdyStreamId associated_stream_id,
283 SpdyPriority priority,
284 SpdyControlFlags flags,
285 const SpdyHeaderBlock* headers) {
286 SpdySynStreamIR syn_stream(stream_id);
287 syn_stream.set_associated_to_stream_id(associated_stream_id);
288 syn_stream.set_priority(priority);
289 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
290 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
291 // TODO(hkhalil): Avoid copy here.
292 syn_stream.set_name_value_block(*headers);
293 return spdy_framer_.SerializeSynStream(syn_stream);
296 // TODO(jgraettinger): Eliminate uses of this method (prefer
298 SpdyFrame* BufferedSpdyFramer::CreateSynReply(
299 SpdyStreamId stream_id,
300 SpdyControlFlags flags,
301 const SpdyHeaderBlock* headers) {
302 SpdySynReplyIR syn_reply(stream_id);
303 syn_reply.set_fin(flags & CONTROL_FLAG_FIN);
304 // TODO(hkhalil): Avoid copy here.
305 syn_reply.set_name_value_block(*headers);
306 return spdy_framer_.SerializeSynReply(syn_reply);
309 // TODO(jgraettinger): Eliminate uses of this method (prefer
311 SpdyFrame* BufferedSpdyFramer::CreateRstStream(
312 SpdyStreamId stream_id,
313 SpdyRstStreamStatus status) const {
314 // RST_STREAM payloads are not part of any SPDY spec.
315 // SpdyFramer will accept them, but don't create them.
316 SpdyRstStreamIR rst_ir(stream_id, status, "");
317 return spdy_framer_.SerializeRstStream(rst_ir);
320 // TODO(jgraettinger): Eliminate uses of this method (prefer
322 SpdyFrame* BufferedSpdyFramer::CreateSettings(
323 const SettingsMap& values) const {
324 SpdySettingsIR settings_ir;
325 for (SettingsMap::const_iterator it = values.begin();
328 settings_ir.AddSetting(
330 (it->second.first & SETTINGS_FLAG_PLEASE_PERSIST) != 0,
331 (it->second.first & SETTINGS_FLAG_PERSISTED) != 0,
334 return spdy_framer_.SerializeSettings(settings_ir);
337 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR).
338 SpdyFrame* BufferedSpdyFramer::CreatePingFrame(uint32 unique_id,
340 SpdyPingIR ping_ir(unique_id);
341 ping_ir.set_is_ack(is_ack);
342 return spdy_framer_.SerializePing(ping_ir);
345 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyGoAwayIR).
346 SpdyFrame* BufferedSpdyFramer::CreateGoAway(
347 SpdyStreamId last_accepted_stream_id,
348 SpdyGoAwayStatus status) const {
349 SpdyGoAwayIR go_ir(last_accepted_stream_id, status, "");
350 return spdy_framer_.SerializeGoAway(go_ir);
353 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyHeadersIR).
354 SpdyFrame* BufferedSpdyFramer::CreateHeaders(
355 SpdyStreamId stream_id,
356 SpdyControlFlags flags,
357 SpdyPriority priority,
358 const SpdyHeaderBlock* headers) {
359 SpdyHeadersIR headers_ir(stream_id);
360 headers_ir.set_fin((flags & CONTROL_FLAG_FIN) != 0);
361 if (flags & HEADERS_FLAG_PRIORITY) {
362 headers_ir.set_has_priority(true);
363 headers_ir.set_priority(priority);
365 headers_ir.set_name_value_block(*headers);
366 return spdy_framer_.SerializeHeaders(headers_ir);
369 // TODO(jgraettinger): Eliminate uses of this method (prefer
370 // SpdyWindowUpdateIR).
371 SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate(
372 SpdyStreamId stream_id,
373 uint32 delta_window_size) const {
374 SpdyWindowUpdateIR update_ir(stream_id, delta_window_size);
375 return spdy_framer_.SerializeWindowUpdate(update_ir);
378 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR).
379 SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
382 SpdyDataFlags flags) {
383 SpdyDataIR data_ir(stream_id,
384 base::StringPiece(data, len));
385 data_ir.set_fin((flags & DATA_FLAG_FIN) != 0);
386 return spdy_framer_.SerializeData(data_ir);
389 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPushPromiseIR).
390 SpdyFrame* BufferedSpdyFramer::CreatePushPromise(
391 SpdyStreamId stream_id,
392 SpdyStreamId promised_stream_id,
393 const SpdyHeaderBlock* headers) {
394 SpdyPushPromiseIR push_promise_ir(stream_id, promised_stream_id);
395 push_promise_ir.set_name_value_block(*headers);
396 return spdy_framer_.SerializePushPromise(push_promise_ir);
399 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const {
400 return spdy_framer_.GetHighestPriority();
403 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) {
404 memset(header_buffer_, 0, kHeaderBufferSize);
405 header_buffer_used_ = 0;
406 header_buffer_valid_ = true;
407 header_stream_id_ = stream_id;
408 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);