Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / net / spdy / buffered_spdy_framer.cc
blob2fa15b8b9b860c2582e6ec1fb8cfc508af023bfa
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"
9 namespace net {
11 SpdyMajorVersion NextProtoToSpdyMajorVersion(NextProto next_proto) {
12 switch (next_proto) {
13 case kProtoDeprecatedSPDY2:
14 return SPDY2;
15 case kProtoSPDY3:
16 case kProtoSPDY31:
17 return SPDY3;
18 case kProtoHTTP2:
19 return HTTP2;
20 case kProtoUnknown:
21 case kProtoHTTP11:
22 case kProtoQUIC1SPDY3:
23 break;
25 NOTREACHED();
26 return SPDY2;
29 BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version,
30 bool enable_compression)
31 : spdy_framer_(version),
32 visitor_(NULL),
33 header_buffer_used_(0),
34 header_buffer_valid_(false),
35 header_stream_id_(SpdyFramer::kInvalidStream),
36 frames_received_(0) {
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) {
46 visitor_ = 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) {
56 DCHECK(spdy_framer);
57 visitor_->OnError(spdy_framer->error_code());
60 void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id,
61 SpdyStreamId associated_stream_id,
62 SpdyPriority priority,
63 bool fin,
64 bool unidirectional) {
65 frames_received_++;
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,
79 bool has_priority,
80 SpdyPriority priority,
81 SpdyStreamId parent_stream_id,
82 bool exclusive,
83 bool fin,
84 bool end) {
85 frames_received_++;
86 DCHECK(!control_frame_fields_.get());
87 control_frame_fields_.reset(new ControlFrameFields());
88 control_frame_fields_->type = HEADERS;
89 control_frame_fields_->stream_id = stream_id;
90 control_frame_fields_->has_priority = has_priority;
91 if (control_frame_fields_->has_priority) {
92 control_frame_fields_->priority = priority;
93 control_frame_fields_->parent_stream_id = parent_stream_id;
94 control_frame_fields_->exclusive = exclusive;
96 control_frame_fields_->fin = fin;
98 InitHeaderStreaming(stream_id);
101 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id,
102 bool fin) {
103 frames_received_++;
104 DCHECK(!control_frame_fields_.get());
105 control_frame_fields_.reset(new ControlFrameFields());
106 control_frame_fields_->type = SYN_REPLY;
107 control_frame_fields_->stream_id = stream_id;
108 control_frame_fields_->fin = fin;
110 InitHeaderStreaming(stream_id);
113 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id,
114 const char* header_data,
115 size_t len) {
116 CHECK_EQ(header_stream_id_, stream_id);
118 if (len == 0) {
119 // Indicates end-of-header-block.
120 CHECK(header_buffer_valid_);
122 SpdyHeaderBlock headers;
123 size_t parsed_len = spdy_framer_.ParseHeaderBlockInBuffer(
124 header_buffer_, header_buffer_used_, &headers);
125 // TODO(rch): this really should be checking parsed_len != len,
126 // but a bunch of tests fail. Need to figure out why.
127 if (parsed_len == 0) {
128 visitor_->OnStreamError(
129 stream_id, "Could not parse Spdy Control Frame Header.");
130 return false;
132 DCHECK(control_frame_fields_.get());
133 switch (control_frame_fields_->type) {
134 case SYN_STREAM:
135 visitor_->OnSynStream(control_frame_fields_->stream_id,
136 control_frame_fields_->associated_stream_id,
137 control_frame_fields_->priority,
138 control_frame_fields_->fin,
139 control_frame_fields_->unidirectional,
140 headers);
141 break;
142 case SYN_REPLY:
143 visitor_->OnSynReply(control_frame_fields_->stream_id,
144 control_frame_fields_->fin,
145 headers);
146 break;
147 case HEADERS:
148 visitor_->OnHeaders(control_frame_fields_->stream_id,
149 control_frame_fields_->has_priority,
150 control_frame_fields_->priority,
151 control_frame_fields_->parent_stream_id,
152 control_frame_fields_->exclusive,
153 control_frame_fields_->fin, headers);
154 break;
155 case PUSH_PROMISE:
156 DCHECK_LT(SPDY3, protocol_version());
157 visitor_->OnPushPromise(control_frame_fields_->stream_id,
158 control_frame_fields_->promised_stream_id,
159 headers);
160 break;
161 default:
162 DCHECK(false) << "Unexpect control frame type: "
163 << control_frame_fields_->type;
164 break;
166 control_frame_fields_.reset(NULL);
167 return true;
170 const size_t available = kHeaderBufferSize - header_buffer_used_;
171 if (len > available) {
172 header_buffer_valid_ = false;
173 visitor_->OnStreamError(
174 stream_id, "Received more data than the allocated size.");
175 return false;
177 memcpy(header_buffer_ + header_buffer_used_, header_data, len);
178 header_buffer_used_ += len;
179 return true;
182 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id,
183 size_t length,
184 bool fin) {
185 frames_received_++;
186 header_stream_id_ = stream_id;
187 visitor_->OnDataFrameHeader(stream_id, length, fin);
190 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id,
191 const char* data,
192 size_t len,
193 bool fin) {
194 visitor_->OnStreamFrameData(stream_id, data, len, fin);
197 void BufferedSpdyFramer::OnStreamPadding(SpdyStreamId stream_id, size_t len) {
198 visitor_->OnStreamPadding(stream_id, len);
201 void BufferedSpdyFramer::OnSettings(bool clear_persisted) {
202 visitor_->OnSettings(clear_persisted);
205 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id,
206 uint8 flags,
207 uint32 value) {
208 visitor_->OnSetting(id, flags, value);
211 void BufferedSpdyFramer::OnSettingsAck() {
212 visitor_->OnSettingsAck();
215 void BufferedSpdyFramer::OnSettingsEnd() {
216 visitor_->OnSettingsEnd();
219 void BufferedSpdyFramer::OnPing(SpdyPingId unique_id, bool is_ack) {
220 visitor_->OnPing(unique_id, is_ack);
223 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id,
224 SpdyRstStreamStatus status) {
225 visitor_->OnRstStream(stream_id, status);
227 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id,
228 SpdyGoAwayStatus status) {
229 visitor_->OnGoAway(last_accepted_stream_id, status);
232 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id,
233 int delta_window_size) {
234 visitor_->OnWindowUpdate(stream_id, delta_window_size);
237 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id,
238 SpdyStreamId promised_stream_id,
239 bool end) {
240 DCHECK_LT(SPDY3, protocol_version());
241 frames_received_++;
242 DCHECK(!control_frame_fields_.get());
243 control_frame_fields_.reset(new ControlFrameFields());
244 control_frame_fields_->type = PUSH_PROMISE;
245 control_frame_fields_->stream_id = stream_id;
246 control_frame_fields_->promised_stream_id = promised_stream_id;
248 InitHeaderStreaming(stream_id);
251 void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id, bool end) {
254 bool BufferedSpdyFramer::OnUnknownFrame(SpdyStreamId stream_id,
255 int frame_type) {
256 return visitor_->OnUnknownFrame(stream_id, frame_type);
259 SpdyMajorVersion BufferedSpdyFramer::protocol_version() {
260 return spdy_framer_.protocol_version();
263 size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
264 return spdy_framer_.ProcessInput(data, len);
267 void BufferedSpdyFramer::Reset() {
268 spdy_framer_.Reset();
271 SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const {
272 return spdy_framer_.error_code();
275 SpdyFramer::SpdyState BufferedSpdyFramer::state() const {
276 return spdy_framer_.state();
279 bool BufferedSpdyFramer::MessageFullyRead() {
280 return state() == SpdyFramer::SPDY_FRAME_COMPLETE;
283 bool BufferedSpdyFramer::HasError() {
284 return spdy_framer_.HasError();
287 // TODO(jgraettinger): Eliminate uses of this method (prefer
288 // SpdySynStreamIR).
289 SpdyFrame* BufferedSpdyFramer::CreateSynStream(
290 SpdyStreamId stream_id,
291 SpdyStreamId associated_stream_id,
292 SpdyPriority priority,
293 SpdyControlFlags flags,
294 const SpdyHeaderBlock* headers) {
295 SpdySynStreamIR syn_stream(stream_id);
296 syn_stream.set_associated_to_stream_id(associated_stream_id);
297 syn_stream.set_priority(priority);
298 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
299 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
300 // TODO(hkhalil): Avoid copy here.
301 syn_stream.set_header_block(*headers);
302 return spdy_framer_.SerializeSynStream(syn_stream);
305 // TODO(jgraettinger): Eliminate uses of this method (prefer
306 // SpdySynReplyIR).
307 SpdyFrame* BufferedSpdyFramer::CreateSynReply(
308 SpdyStreamId stream_id,
309 SpdyControlFlags flags,
310 const SpdyHeaderBlock* headers) {
311 SpdySynReplyIR syn_reply(stream_id);
312 syn_reply.set_fin(flags & CONTROL_FLAG_FIN);
313 // TODO(hkhalil): Avoid copy here.
314 syn_reply.set_header_block(*headers);
315 return spdy_framer_.SerializeSynReply(syn_reply);
318 // TODO(jgraettinger): Eliminate uses of this method (prefer
319 // SpdyRstStreamIR).
320 SpdyFrame* BufferedSpdyFramer::CreateRstStream(
321 SpdyStreamId stream_id,
322 SpdyRstStreamStatus status) const {
323 // RST_STREAM payloads are not part of any SPDY spec.
324 // SpdyFramer will accept them, but don't create them.
325 SpdyRstStreamIR rst_ir(stream_id, status, "");
326 return spdy_framer_.SerializeRstStream(rst_ir);
329 // TODO(jgraettinger): Eliminate uses of this method (prefer
330 // SpdySettingsIR).
331 SpdyFrame* BufferedSpdyFramer::CreateSettings(
332 const SettingsMap& values) const {
333 SpdySettingsIR settings_ir;
334 for (SettingsMap::const_iterator it = values.begin();
335 it != values.end();
336 ++it) {
337 settings_ir.AddSetting(
338 it->first,
339 (it->second.first & SETTINGS_FLAG_PLEASE_PERSIST) != 0,
340 (it->second.first & SETTINGS_FLAG_PERSISTED) != 0,
341 it->second.second);
343 return spdy_framer_.SerializeSettings(settings_ir);
346 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR).
347 SpdyFrame* BufferedSpdyFramer::CreatePingFrame(SpdyPingId unique_id,
348 bool is_ack) const {
349 SpdyPingIR ping_ir(unique_id);
350 ping_ir.set_is_ack(is_ack);
351 return spdy_framer_.SerializePing(ping_ir);
354 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyGoAwayIR).
355 SpdyFrame* BufferedSpdyFramer::CreateGoAway(
356 SpdyStreamId last_accepted_stream_id,
357 SpdyGoAwayStatus status) const {
358 SpdyGoAwayIR go_ir(last_accepted_stream_id, status, "");
359 return spdy_framer_.SerializeGoAway(go_ir);
362 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyHeadersIR).
363 SpdyFrame* BufferedSpdyFramer::CreateHeaders(
364 SpdyStreamId stream_id,
365 SpdyControlFlags flags,
366 SpdyPriority priority,
367 const SpdyHeaderBlock* headers) {
368 SpdyHeadersIR headers_ir(stream_id);
369 headers_ir.set_fin((flags & CONTROL_FLAG_FIN) != 0);
370 if (flags & HEADERS_FLAG_PRIORITY) {
371 headers_ir.set_has_priority(true);
372 headers_ir.set_priority(priority);
374 headers_ir.set_header_block(*headers);
375 return spdy_framer_.SerializeHeaders(headers_ir);
378 // TODO(jgraettinger): Eliminate uses of this method (prefer
379 // SpdyWindowUpdateIR).
380 SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate(
381 SpdyStreamId stream_id,
382 uint32 delta_window_size) const {
383 SpdyWindowUpdateIR update_ir(stream_id, delta_window_size);
384 return spdy_framer_.SerializeWindowUpdate(update_ir);
387 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR).
388 SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
389 const char* data,
390 uint32 len,
391 SpdyDataFlags flags) {
392 SpdyDataIR data_ir(stream_id,
393 base::StringPiece(data, len));
394 data_ir.set_fin((flags & DATA_FLAG_FIN) != 0);
395 return spdy_framer_.SerializeData(data_ir);
398 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPushPromiseIR).
399 SpdyFrame* BufferedSpdyFramer::CreatePushPromise(
400 SpdyStreamId stream_id,
401 SpdyStreamId promised_stream_id,
402 const SpdyHeaderBlock* headers) {
403 SpdyPushPromiseIR push_promise_ir(stream_id, promised_stream_id);
404 push_promise_ir.set_header_block(*headers);
405 return spdy_framer_.SerializePushPromise(push_promise_ir);
408 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const {
409 return spdy_framer_.GetHighestPriority();
412 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) {
413 memset(header_buffer_, 0, kHeaderBufferSize);
414 header_buffer_used_ = 0;
415 header_buffer_valid_ = true;
416 header_stream_id_ = stream_id;
417 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
420 } // namespace net