Fix infinite recursion on hiding panel when created during fullscreen mode.
[chromium-blink-merge.git] / net / spdy / buffered_spdy_framer.cc
blob48614285a8332b1b8ea578eda67113e0f00c865b
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 // SPDY/4 and HTTP/2 share the same framing for now.
19 case kProtoSPDY4a2:
20 case kProtoHTTP2Draft04:
21 return SPDY4;
22 case kProtoUnknown:
23 case kProtoHTTP11:
24 case kProtoQUIC1SPDY3:
25 break;
27 NOTREACHED();
28 return SPDY2;
31 BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version,
32 bool enable_compression)
33 : spdy_framer_(version),
34 visitor_(NULL),
35 header_buffer_used_(0),
36 header_buffer_valid_(false),
37 header_stream_id_(SpdyFramer::kInvalidStream),
38 frames_received_(0) {
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) {
48 visitor_ = 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) {
58 DCHECK(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 bool fin,
66 bool unidirectional) {
67 frames_received_++;
68 DCHECK(!control_frame_fields_.get());
69 control_frame_fields_.reset(new ControlFrameFields());
70 control_frame_fields_->type = SYN_STREAM;
71 control_frame_fields_->stream_id = stream_id;
72 control_frame_fields_->associated_stream_id = associated_stream_id;
73 control_frame_fields_->priority = priority;
74 control_frame_fields_->fin = fin;
75 control_frame_fields_->unidirectional = unidirectional;
77 InitHeaderStreaming(stream_id);
80 void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id,
81 bool fin,
82 bool end) {
83 frames_received_++;
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_->fin = fin;
90 InitHeaderStreaming(stream_id);
93 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id,
94 bool fin) {
95 frames_received_++;
96 DCHECK(!control_frame_fields_.get());
97 control_frame_fields_.reset(new ControlFrameFields());
98 control_frame_fields_->type = SYN_REPLY;
99 control_frame_fields_->stream_id = stream_id;
100 control_frame_fields_->fin = fin;
102 InitHeaderStreaming(stream_id);
105 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id,
106 const char* header_data,
107 size_t len) {
108 CHECK_EQ(header_stream_id_, stream_id);
110 if (len == 0) {
111 // Indicates end-of-header-block.
112 CHECK(header_buffer_valid_);
114 SpdyHeaderBlock headers;
115 size_t parsed_len = spdy_framer_.ParseHeaderBlockInBuffer(
116 header_buffer_, header_buffer_used_, &headers);
117 // TODO(rch): this really should be checking parsed_len != len,
118 // but a bunch of tests fail. Need to figure out why.
119 if (parsed_len == 0) {
120 visitor_->OnStreamError(
121 stream_id, "Could not parse Spdy Control Frame Header.");
122 return false;
124 DCHECK(control_frame_fields_.get());
125 switch (control_frame_fields_->type) {
126 case SYN_STREAM:
127 visitor_->OnSynStream(control_frame_fields_->stream_id,
128 control_frame_fields_->associated_stream_id,
129 control_frame_fields_->priority,
130 control_frame_fields_->fin,
131 control_frame_fields_->unidirectional,
132 headers);
133 break;
134 case SYN_REPLY:
135 visitor_->OnSynReply(control_frame_fields_->stream_id,
136 control_frame_fields_->fin,
137 headers);
138 break;
139 case HEADERS:
140 visitor_->OnHeaders(control_frame_fields_->stream_id,
141 control_frame_fields_->fin,
142 headers);
143 break;
144 default:
145 DCHECK(false) << "Unexpect control frame type: "
146 << control_frame_fields_->type;
147 break;
149 control_frame_fields_.reset(NULL);
150 return true;
153 const size_t available = kHeaderBufferSize - header_buffer_used_;
154 if (len > available) {
155 header_buffer_valid_ = false;
156 visitor_->OnStreamError(
157 stream_id, "Received more data than the allocated size.");
158 return false;
160 memcpy(header_buffer_ + header_buffer_used_, header_data, len);
161 header_buffer_used_ += len;
162 return true;
165 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id,
166 size_t length,
167 bool fin) {
168 frames_received_++;
169 header_stream_id_ = stream_id;
170 visitor_->OnDataFrameHeader(stream_id, length, fin);
173 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id,
174 const char* data,
175 size_t len,
176 bool fin) {
177 visitor_->OnStreamFrameData(stream_id, data, len, fin);
180 void BufferedSpdyFramer::OnSettings(bool clear_persisted) {
181 visitor_->OnSettings(clear_persisted);
184 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id,
185 uint8 flags,
186 uint32 value) {
187 visitor_->OnSetting(id, flags, value);
190 void BufferedSpdyFramer::OnSettingsAck() {
191 visitor_->OnSettingsAck();
194 void BufferedSpdyFramer::OnSettingsEnd() {
195 visitor_->OnSettingsEnd();
198 void BufferedSpdyFramer::OnPing(SpdyPingId unique_id, bool is_ack) {
199 visitor_->OnPing(unique_id, is_ack);
202 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id,
203 SpdyRstStreamStatus status) {
204 visitor_->OnRstStream(stream_id, status);
206 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id,
207 SpdyGoAwayStatus status) {
208 visitor_->OnGoAway(last_accepted_stream_id, status);
211 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id,
212 uint32 delta_window_size) {
213 visitor_->OnWindowUpdate(stream_id, delta_window_size);
216 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id,
217 SpdyStreamId promised_stream_id,
218 bool end) {
219 // TODO(jgraettinger): Deliver headers, similar to OnHeaders.
220 visitor_->OnPushPromise(stream_id, promised_stream_id);
223 void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id, bool end) {
226 SpdyMajorVersion BufferedSpdyFramer::protocol_version() {
227 return spdy_framer_.protocol_version();
230 size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
231 return spdy_framer_.ProcessInput(data, len);
234 void BufferedSpdyFramer::Reset() {
235 spdy_framer_.Reset();
238 SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const {
239 return spdy_framer_.error_code();
242 SpdyFramer::SpdyState BufferedSpdyFramer::state() const {
243 return spdy_framer_.state();
246 bool BufferedSpdyFramer::MessageFullyRead() {
247 return state() == SpdyFramer::SPDY_AUTO_RESET;
250 bool BufferedSpdyFramer::HasError() {
251 return spdy_framer_.HasError();
254 // TODO(jgraettinger): Eliminate uses of this method (prefer
255 // SpdySynStreamIR).
256 SpdyFrame* BufferedSpdyFramer::CreateSynStream(
257 SpdyStreamId stream_id,
258 SpdyStreamId associated_stream_id,
259 SpdyPriority priority,
260 SpdyControlFlags flags,
261 const SpdyHeaderBlock* headers) {
262 SpdySynStreamIR syn_stream(stream_id);
263 syn_stream.set_associated_to_stream_id(associated_stream_id);
264 syn_stream.set_priority(priority);
265 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
266 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
267 // TODO(hkhalil): Avoid copy here.
268 syn_stream.set_name_value_block(*headers);
269 return spdy_framer_.SerializeSynStream(syn_stream);
272 // TODO(jgraettinger): Eliminate uses of this method (prefer
273 // SpdySynReplyIR).
274 SpdyFrame* BufferedSpdyFramer::CreateSynReply(
275 SpdyStreamId stream_id,
276 SpdyControlFlags flags,
277 const SpdyHeaderBlock* headers) {
278 SpdySynReplyIR syn_reply(stream_id);
279 syn_reply.set_fin(flags & CONTROL_FLAG_FIN);
280 // TODO(hkhalil): Avoid copy here.
281 syn_reply.set_name_value_block(*headers);
282 return spdy_framer_.SerializeSynReply(syn_reply);
285 // TODO(jgraettinger): Eliminate uses of this method (prefer
286 // SpdyRstStreamIR).
287 SpdyFrame* BufferedSpdyFramer::CreateRstStream(
288 SpdyStreamId stream_id,
289 SpdyRstStreamStatus status) const {
290 SpdyRstStreamIR rst_ir(stream_id, status, "RST");
291 return spdy_framer_.SerializeRstStream(rst_ir);
294 // TODO(jgraettinger): Eliminate uses of this method (prefer
295 // SpdySettingsIR).
296 SpdyFrame* BufferedSpdyFramer::CreateSettings(
297 const SettingsMap& values) const {
298 SpdySettingsIR settings_ir;
299 for (SettingsMap::const_iterator it = values.begin();
300 it != values.end();
301 ++it) {
302 settings_ir.AddSetting(
303 it->first,
304 (it->second.first & SETTINGS_FLAG_PLEASE_PERSIST) != 0,
305 (it->second.first & SETTINGS_FLAG_PERSISTED) != 0,
306 it->second.second);
308 return spdy_framer_.SerializeSettings(settings_ir);
311 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR).
312 SpdyFrame* BufferedSpdyFramer::CreatePingFrame(uint32 unique_id,
313 bool is_ack) const {
314 SpdyPingIR ping_ir(unique_id);
315 ping_ir.set_is_ack(is_ack);
316 return spdy_framer_.SerializePing(ping_ir);
319 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyGoAwayIR).
320 SpdyFrame* BufferedSpdyFramer::CreateGoAway(
321 SpdyStreamId last_accepted_stream_id,
322 SpdyGoAwayStatus status) const {
323 SpdyGoAwayIR go_ir(last_accepted_stream_id, status, "");
324 return spdy_framer_.SerializeGoAway(go_ir);
327 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyHeadersIR).
328 SpdyFrame* BufferedSpdyFramer::CreateHeaders(
329 SpdyStreamId stream_id,
330 SpdyControlFlags flags,
331 const SpdyHeaderBlock* headers) {
332 SpdyHeadersIR headers_ir(stream_id);
333 headers_ir.set_fin((flags & CONTROL_FLAG_FIN) != 0);
334 headers_ir.set_name_value_block(*headers);
335 return spdy_framer_.SerializeHeaders(headers_ir);
338 // TODO(jgraettinger): Eliminate uses of this method (prefer
339 // SpdyWindowUpdateIR).
340 SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate(
341 SpdyStreamId stream_id,
342 uint32 delta_window_size) const {
343 SpdyWindowUpdateIR update_ir(stream_id, delta_window_size);
344 return spdy_framer_.SerializeWindowUpdate(update_ir);
347 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR).
348 SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
349 const char* data,
350 uint32 len,
351 SpdyDataFlags flags) {
352 SpdyDataIR data_ir(stream_id,
353 base::StringPiece(data, len));
354 data_ir.set_fin((flags & DATA_FLAG_FIN) != 0);
355 return spdy_framer_.SerializeData(data_ir);
358 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const {
359 return spdy_framer_.GetHighestPriority();
362 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) {
363 memset(header_buffer_, 0, kHeaderBufferSize);
364 header_buffer_used_ = 0;
365 header_buffer_valid_ = true;
366 header_stream_id_ = stream_id;
367 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
370 } // namespace net