Added the network error code to <webview> loadabort message and event.
[chromium-blink-merge.git] / net / spdy / buffered_spdy_framer.cc
blob4a8a46dd40d55811dc1ce551fb1f68eb5107f9a2
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 kProtoSPDY4_14:
19 case kProtoSPDY4:
20 return SPDY4;
21 case kProtoUnknown:
22 case kProtoHTTP11:
23 case kProtoQUIC1SPDY3:
24 break;
26 NOTREACHED();
27 return SPDY2;
30 BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version,
31 bool enable_compression)
32 : spdy_framer_(version),
33 visitor_(NULL),
34 header_buffer_used_(0),
35 header_buffer_valid_(false),
36 header_stream_id_(SpdyFramer::kInvalidStream),
37 frames_received_(0) {
38 spdy_framer_.set_enable_compression(enable_compression);
39 memset(header_buffer_, 0, sizeof(header_buffer_));
42 BufferedSpdyFramer::~BufferedSpdyFramer() {
45 void BufferedSpdyFramer::set_visitor(
46 BufferedSpdyFramerVisitorInterface* visitor) {
47 visitor_ = visitor;
48 spdy_framer_.set_visitor(this);
51 void BufferedSpdyFramer::set_debug_visitor(
52 SpdyFramerDebugVisitorInterface* debug_visitor) {
53 spdy_framer_.set_debug_visitor(debug_visitor);
56 void BufferedSpdyFramer::OnError(SpdyFramer* spdy_framer) {
57 DCHECK(spdy_framer);
58 visitor_->OnError(spdy_framer->error_code());
61 void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id,
62 SpdyStreamId associated_stream_id,
63 SpdyPriority priority,
64 bool fin,
65 bool unidirectional) {
66 frames_received_++;
67 DCHECK(!control_frame_fields_.get());
68 control_frame_fields_.reset(new ControlFrameFields());
69 control_frame_fields_->type = SYN_STREAM;
70 control_frame_fields_->stream_id = stream_id;
71 control_frame_fields_->associated_stream_id = associated_stream_id;
72 control_frame_fields_->priority = priority;
73 control_frame_fields_->fin = fin;
74 control_frame_fields_->unidirectional = unidirectional;
76 InitHeaderStreaming(stream_id);
79 void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id,
80 bool has_priority,
81 SpdyPriority priority,
82 bool fin,
83 bool end) {
84 frames_received_++;
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_->has_priority = has_priority;
90 if (control_frame_fields_->has_priority) {
91 control_frame_fields_->priority = priority;
93 control_frame_fields_->fin = fin;
95 InitHeaderStreaming(stream_id);
98 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id,
99 bool fin) {
100 frames_received_++;
101 DCHECK(!control_frame_fields_.get());
102 control_frame_fields_.reset(new ControlFrameFields());
103 control_frame_fields_->type = SYN_REPLY;
104 control_frame_fields_->stream_id = stream_id;
105 control_frame_fields_->fin = fin;
107 InitHeaderStreaming(stream_id);
110 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id,
111 const char* header_data,
112 size_t len) {
113 CHECK_EQ(header_stream_id_, stream_id);
115 if (len == 0) {
116 // Indicates end-of-header-block.
117 CHECK(header_buffer_valid_);
119 SpdyHeaderBlock headers;
120 size_t parsed_len = spdy_framer_.ParseHeaderBlockInBuffer(
121 header_buffer_, header_buffer_used_, &headers);
122 // TODO(rch): this really should be checking parsed_len != len,
123 // but a bunch of tests fail. Need to figure out why.
124 if (parsed_len == 0) {
125 visitor_->OnStreamError(
126 stream_id, "Could not parse Spdy Control Frame Header.");
127 return false;
129 DCHECK(control_frame_fields_.get());
130 switch (control_frame_fields_->type) {
131 case SYN_STREAM:
132 visitor_->OnSynStream(control_frame_fields_->stream_id,
133 control_frame_fields_->associated_stream_id,
134 control_frame_fields_->priority,
135 control_frame_fields_->fin,
136 control_frame_fields_->unidirectional,
137 headers);
138 break;
139 case SYN_REPLY:
140 visitor_->OnSynReply(control_frame_fields_->stream_id,
141 control_frame_fields_->fin,
142 headers);
143 break;
144 case HEADERS:
145 visitor_->OnHeaders(control_frame_fields_->stream_id,
146 control_frame_fields_->has_priority,
147 control_frame_fields_->priority,
148 control_frame_fields_->fin,
149 headers);
150 break;
151 case PUSH_PROMISE:
152 DCHECK_LT(SPDY3, protocol_version());
153 visitor_->OnPushPromise(control_frame_fields_->stream_id,
154 control_frame_fields_->promised_stream_id,
155 headers);
156 break;
157 default:
158 DCHECK(false) << "Unexpect control frame type: "
159 << control_frame_fields_->type;
160 break;
162 control_frame_fields_.reset(NULL);
163 return true;
166 const size_t available = kHeaderBufferSize - header_buffer_used_;
167 if (len > available) {
168 header_buffer_valid_ = false;
169 visitor_->OnStreamError(
170 stream_id, "Received more data than the allocated size.");
171 return false;
173 memcpy(header_buffer_ + header_buffer_used_, header_data, len);
174 header_buffer_used_ += len;
175 return true;
178 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id,
179 size_t length,
180 bool fin) {
181 frames_received_++;
182 header_stream_id_ = stream_id;
183 visitor_->OnDataFrameHeader(stream_id, length, fin);
186 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id,
187 const char* data,
188 size_t len,
189 bool fin) {
190 visitor_->OnStreamFrameData(stream_id, data, len, fin);
193 void BufferedSpdyFramer::OnStreamPadding(SpdyStreamId stream_id, size_t len) {
194 visitor_->OnStreamPadding(stream_id, len);
197 void BufferedSpdyFramer::OnSettings(bool clear_persisted) {
198 visitor_->OnSettings(clear_persisted);
201 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id,
202 uint8 flags,
203 uint32 value) {
204 visitor_->OnSetting(id, flags, value);
207 void BufferedSpdyFramer::OnSettingsAck() {
208 visitor_->OnSettingsAck();
211 void BufferedSpdyFramer::OnSettingsEnd() {
212 visitor_->OnSettingsEnd();
215 void BufferedSpdyFramer::OnPing(SpdyPingId unique_id, bool is_ack) {
216 visitor_->OnPing(unique_id, is_ack);
219 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id,
220 SpdyRstStreamStatus status) {
221 visitor_->OnRstStream(stream_id, status);
223 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id,
224 SpdyGoAwayStatus status) {
225 visitor_->OnGoAway(last_accepted_stream_id, status);
228 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id,
229 uint32 delta_window_size) {
230 visitor_->OnWindowUpdate(stream_id, delta_window_size);
233 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id,
234 SpdyStreamId promised_stream_id,
235 bool end) {
236 DCHECK_LT(SPDY3, protocol_version());
237 frames_received_++;
238 DCHECK(!control_frame_fields_.get());
239 control_frame_fields_.reset(new ControlFrameFields());
240 control_frame_fields_->type = PUSH_PROMISE;
241 control_frame_fields_->stream_id = stream_id;
242 control_frame_fields_->promised_stream_id = promised_stream_id;
244 InitHeaderStreaming(stream_id);
247 void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id, bool end) {
250 bool BufferedSpdyFramer::OnUnknownFrame(SpdyStreamId stream_id,
251 int frame_type) {
252 return visitor_->OnUnknownFrame(stream_id, frame_type);
255 SpdyMajorVersion BufferedSpdyFramer::protocol_version() {
256 return spdy_framer_.protocol_version();
259 size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
260 return spdy_framer_.ProcessInput(data, len);
263 void BufferedSpdyFramer::Reset() {
264 spdy_framer_.Reset();
267 SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const {
268 return spdy_framer_.error_code();
271 SpdyFramer::SpdyState BufferedSpdyFramer::state() const {
272 return spdy_framer_.state();
275 bool BufferedSpdyFramer::MessageFullyRead() {
276 return state() == SpdyFramer::SPDY_AUTO_RESET;
279 bool BufferedSpdyFramer::HasError() {
280 return spdy_framer_.HasError();
283 // TODO(jgraettinger): Eliminate uses of this method (prefer
284 // SpdySynStreamIR).
285 SpdyFrame* BufferedSpdyFramer::CreateSynStream(
286 SpdyStreamId stream_id,
287 SpdyStreamId associated_stream_id,
288 SpdyPriority priority,
289 SpdyControlFlags flags,
290 const SpdyHeaderBlock* headers) {
291 SpdySynStreamIR syn_stream(stream_id);
292 syn_stream.set_associated_to_stream_id(associated_stream_id);
293 syn_stream.set_priority(priority);
294 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
295 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
296 // TODO(hkhalil): Avoid copy here.
297 syn_stream.set_name_value_block(*headers);
298 return spdy_framer_.SerializeSynStream(syn_stream);
301 // TODO(jgraettinger): Eliminate uses of this method (prefer
302 // SpdySynReplyIR).
303 SpdyFrame* BufferedSpdyFramer::CreateSynReply(
304 SpdyStreamId stream_id,
305 SpdyControlFlags flags,
306 const SpdyHeaderBlock* headers) {
307 SpdySynReplyIR syn_reply(stream_id);
308 syn_reply.set_fin(flags & CONTROL_FLAG_FIN);
309 // TODO(hkhalil): Avoid copy here.
310 syn_reply.set_name_value_block(*headers);
311 return spdy_framer_.SerializeSynReply(syn_reply);
314 // TODO(jgraettinger): Eliminate uses of this method (prefer
315 // SpdyRstStreamIR).
316 SpdyFrame* BufferedSpdyFramer::CreateRstStream(
317 SpdyStreamId stream_id,
318 SpdyRstStreamStatus status) const {
319 // RST_STREAM payloads are not part of any SPDY spec.
320 // SpdyFramer will accept them, but don't create them.
321 SpdyRstStreamIR rst_ir(stream_id, status, "");
322 return spdy_framer_.SerializeRstStream(rst_ir);
325 // TODO(jgraettinger): Eliminate uses of this method (prefer
326 // SpdySettingsIR).
327 SpdyFrame* BufferedSpdyFramer::CreateSettings(
328 const SettingsMap& values) const {
329 SpdySettingsIR settings_ir;
330 for (SettingsMap::const_iterator it = values.begin();
331 it != values.end();
332 ++it) {
333 settings_ir.AddSetting(
334 it->first,
335 (it->second.first & SETTINGS_FLAG_PLEASE_PERSIST) != 0,
336 (it->second.first & SETTINGS_FLAG_PERSISTED) != 0,
337 it->second.second);
339 return spdy_framer_.SerializeSettings(settings_ir);
342 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR).
343 SpdyFrame* BufferedSpdyFramer::CreatePingFrame(SpdyPingId unique_id,
344 bool is_ack) const {
345 SpdyPingIR ping_ir(unique_id);
346 ping_ir.set_is_ack(is_ack);
347 return spdy_framer_.SerializePing(ping_ir);
350 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyGoAwayIR).
351 SpdyFrame* BufferedSpdyFramer::CreateGoAway(
352 SpdyStreamId last_accepted_stream_id,
353 SpdyGoAwayStatus status) const {
354 SpdyGoAwayIR go_ir(last_accepted_stream_id, status, "");
355 return spdy_framer_.SerializeGoAway(go_ir);
358 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyHeadersIR).
359 SpdyFrame* BufferedSpdyFramer::CreateHeaders(
360 SpdyStreamId stream_id,
361 SpdyControlFlags flags,
362 SpdyPriority priority,
363 const SpdyHeaderBlock* headers) {
364 SpdyHeadersIR headers_ir(stream_id);
365 headers_ir.set_fin((flags & CONTROL_FLAG_FIN) != 0);
366 if (flags & HEADERS_FLAG_PRIORITY) {
367 headers_ir.set_has_priority(true);
368 headers_ir.set_priority(priority);
370 headers_ir.set_name_value_block(*headers);
371 return spdy_framer_.SerializeHeaders(headers_ir);
374 // TODO(jgraettinger): Eliminate uses of this method (prefer
375 // SpdyWindowUpdateIR).
376 SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate(
377 SpdyStreamId stream_id,
378 uint32 delta_window_size) const {
379 SpdyWindowUpdateIR update_ir(stream_id, delta_window_size);
380 return spdy_framer_.SerializeWindowUpdate(update_ir);
383 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR).
384 SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
385 const char* data,
386 uint32 len,
387 SpdyDataFlags flags) {
388 SpdyDataIR data_ir(stream_id,
389 base::StringPiece(data, len));
390 data_ir.set_fin((flags & DATA_FLAG_FIN) != 0);
391 return spdy_framer_.SerializeData(data_ir);
394 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPushPromiseIR).
395 SpdyFrame* BufferedSpdyFramer::CreatePushPromise(
396 SpdyStreamId stream_id,
397 SpdyStreamId promised_stream_id,
398 const SpdyHeaderBlock* headers) {
399 SpdyPushPromiseIR push_promise_ir(stream_id, promised_stream_id);
400 push_promise_ir.set_name_value_block(*headers);
401 return spdy_framer_.SerializePushPromise(push_promise_ir);
404 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const {
405 return spdy_framer_.GetHighestPriority();
408 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) {
409 memset(header_buffer_, 0, kHeaderBufferSize);
410 header_buffer_used_ = 0;
411 header_buffer_valid_ = true;
412 header_stream_id_ = stream_id;
413 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
416 } // namespace net