Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / net / spdy / buffered_spdy_framer.cc
blobfdc65a93c9fb20bb64c5c1f4b3d6aba5c9c0885f
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:
19 return SPDY4;
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 fin,
80 bool end) {
81 frames_received_++;
82 DCHECK(!control_frame_fields_.get());
83 control_frame_fields_.reset(new ControlFrameFields());
84 control_frame_fields_->type = HEADERS;
85 control_frame_fields_->stream_id = stream_id;
86 control_frame_fields_->fin = fin;
88 InitHeaderStreaming(stream_id);
91 void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id,
92 bool fin) {
93 frames_received_++;
94 DCHECK(!control_frame_fields_.get());
95 control_frame_fields_.reset(new ControlFrameFields());
96 control_frame_fields_->type = SYN_REPLY;
97 control_frame_fields_->stream_id = stream_id;
98 control_frame_fields_->fin = fin;
100 InitHeaderStreaming(stream_id);
103 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id,
104 const char* header_data,
105 size_t len) {
106 CHECK_EQ(header_stream_id_, stream_id);
108 if (len == 0) {
109 // Indicates end-of-header-block.
110 CHECK(header_buffer_valid_);
112 SpdyHeaderBlock headers;
113 size_t parsed_len = spdy_framer_.ParseHeaderBlockInBuffer(
114 header_buffer_, header_buffer_used_, &headers);
115 // TODO(rch): this really should be checking parsed_len != len,
116 // but a bunch of tests fail. Need to figure out why.
117 if (parsed_len == 0) {
118 visitor_->OnStreamError(
119 stream_id, "Could not parse Spdy Control Frame Header.");
120 return false;
122 DCHECK(control_frame_fields_.get());
123 switch (control_frame_fields_->type) {
124 case SYN_STREAM:
125 visitor_->OnSynStream(control_frame_fields_->stream_id,
126 control_frame_fields_->associated_stream_id,
127 control_frame_fields_->priority,
128 control_frame_fields_->fin,
129 control_frame_fields_->unidirectional,
130 headers);
131 break;
132 case SYN_REPLY:
133 visitor_->OnSynReply(control_frame_fields_->stream_id,
134 control_frame_fields_->fin,
135 headers);
136 break;
137 case HEADERS:
138 visitor_->OnHeaders(control_frame_fields_->stream_id,
139 control_frame_fields_->fin,
140 headers);
141 break;
142 case PUSH_PROMISE:
143 DCHECK_LT(SPDY3, protocol_version());
144 visitor_->OnPushPromise(control_frame_fields_->stream_id,
145 control_frame_fields_->promised_stream_id,
146 headers);
147 break;
148 default:
149 DCHECK(false) << "Unexpect control frame type: "
150 << control_frame_fields_->type;
151 break;
153 control_frame_fields_.reset(NULL);
154 return true;
157 const size_t available = kHeaderBufferSize - header_buffer_used_;
158 if (len > available) {
159 header_buffer_valid_ = false;
160 visitor_->OnStreamError(
161 stream_id, "Received more data than the allocated size.");
162 return false;
164 memcpy(header_buffer_ + header_buffer_used_, header_data, len);
165 header_buffer_used_ += len;
166 return true;
169 void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id,
170 size_t length,
171 bool fin) {
172 frames_received_++;
173 header_stream_id_ = stream_id;
174 visitor_->OnDataFrameHeader(stream_id, length, fin);
177 void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id,
178 const char* data,
179 size_t len,
180 bool fin) {
181 visitor_->OnStreamFrameData(stream_id, data, len, fin);
184 void BufferedSpdyFramer::OnSettings(bool clear_persisted) {
185 visitor_->OnSettings(clear_persisted);
188 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id,
189 uint8 flags,
190 uint32 value) {
191 visitor_->OnSetting(id, flags, value);
194 void BufferedSpdyFramer::OnSettingsAck() {
195 visitor_->OnSettingsAck();
198 void BufferedSpdyFramer::OnSettingsEnd() {
199 visitor_->OnSettingsEnd();
202 void BufferedSpdyFramer::OnPing(SpdyPingId unique_id, bool is_ack) {
203 visitor_->OnPing(unique_id, is_ack);
206 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id,
207 SpdyRstStreamStatus status) {
208 visitor_->OnRstStream(stream_id, status);
210 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id,
211 SpdyGoAwayStatus status) {
212 visitor_->OnGoAway(last_accepted_stream_id, status);
215 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id,
216 uint32 delta_window_size) {
217 visitor_->OnWindowUpdate(stream_id, delta_window_size);
220 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id,
221 SpdyStreamId promised_stream_id,
222 bool end) {
223 DCHECK_LT(SPDY3, protocol_version());
224 frames_received_++;
225 DCHECK(!control_frame_fields_.get());
226 control_frame_fields_.reset(new ControlFrameFields());
227 control_frame_fields_->type = PUSH_PROMISE;
228 control_frame_fields_->stream_id = stream_id;
229 control_frame_fields_->promised_stream_id = promised_stream_id;
231 InitHeaderStreaming(stream_id);
234 void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id, bool end) {
237 bool BufferedSpdyFramer::OnUnknownFrame(SpdyStreamId stream_id,
238 int frame_type) {
239 return visitor_->OnUnknownFrame(stream_id, frame_type);
242 SpdyMajorVersion BufferedSpdyFramer::protocol_version() {
243 return spdy_framer_.protocol_version();
246 size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
247 return spdy_framer_.ProcessInput(data, len);
250 void BufferedSpdyFramer::Reset() {
251 spdy_framer_.Reset();
254 SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const {
255 return spdy_framer_.error_code();
258 SpdyFramer::SpdyState BufferedSpdyFramer::state() const {
259 return spdy_framer_.state();
262 bool BufferedSpdyFramer::MessageFullyRead() {
263 return state() == SpdyFramer::SPDY_AUTO_RESET;
266 bool BufferedSpdyFramer::HasError() {
267 return spdy_framer_.HasError();
270 // TODO(jgraettinger): Eliminate uses of this method (prefer
271 // SpdySynStreamIR).
272 SpdyFrame* BufferedSpdyFramer::CreateSynStream(
273 SpdyStreamId stream_id,
274 SpdyStreamId associated_stream_id,
275 SpdyPriority priority,
276 SpdyControlFlags flags,
277 const SpdyHeaderBlock* headers) {
278 SpdySynStreamIR syn_stream(stream_id);
279 syn_stream.set_associated_to_stream_id(associated_stream_id);
280 syn_stream.set_priority(priority);
281 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
282 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
283 // TODO(hkhalil): Avoid copy here.
284 syn_stream.set_name_value_block(*headers);
285 return spdy_framer_.SerializeSynStream(syn_stream);
288 // TODO(jgraettinger): Eliminate uses of this method (prefer
289 // SpdySynReplyIR).
290 SpdyFrame* BufferedSpdyFramer::CreateSynReply(
291 SpdyStreamId stream_id,
292 SpdyControlFlags flags,
293 const SpdyHeaderBlock* headers) {
294 SpdySynReplyIR syn_reply(stream_id);
295 syn_reply.set_fin(flags & CONTROL_FLAG_FIN);
296 // TODO(hkhalil): Avoid copy here.
297 syn_reply.set_name_value_block(*headers);
298 return spdy_framer_.SerializeSynReply(syn_reply);
301 // TODO(jgraettinger): Eliminate uses of this method (prefer
302 // SpdyRstStreamIR).
303 SpdyFrame* BufferedSpdyFramer::CreateRstStream(
304 SpdyStreamId stream_id,
305 SpdyRstStreamStatus status) const {
306 // RST_STREAM payloads are not part of any SPDY spec.
307 // SpdyFramer will accept them, but don't create them.
308 SpdyRstStreamIR rst_ir(stream_id, status, "");
309 return spdy_framer_.SerializeRstStream(rst_ir);
312 // TODO(jgraettinger): Eliminate uses of this method (prefer
313 // SpdySettingsIR).
314 SpdyFrame* BufferedSpdyFramer::CreateSettings(
315 const SettingsMap& values) const {
316 SpdySettingsIR settings_ir;
317 for (SettingsMap::const_iterator it = values.begin();
318 it != values.end();
319 ++it) {
320 settings_ir.AddSetting(
321 it->first,
322 (it->second.first & SETTINGS_FLAG_PLEASE_PERSIST) != 0,
323 (it->second.first & SETTINGS_FLAG_PERSISTED) != 0,
324 it->second.second);
326 return spdy_framer_.SerializeSettings(settings_ir);
329 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR).
330 SpdyFrame* BufferedSpdyFramer::CreatePingFrame(uint32 unique_id,
331 bool is_ack) const {
332 SpdyPingIR ping_ir(unique_id);
333 ping_ir.set_is_ack(is_ack);
334 return spdy_framer_.SerializePing(ping_ir);
337 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyGoAwayIR).
338 SpdyFrame* BufferedSpdyFramer::CreateGoAway(
339 SpdyStreamId last_accepted_stream_id,
340 SpdyGoAwayStatus status) const {
341 SpdyGoAwayIR go_ir(last_accepted_stream_id, status, "");
342 return spdy_framer_.SerializeGoAway(go_ir);
345 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyHeadersIR).
346 SpdyFrame* BufferedSpdyFramer::CreateHeaders(
347 SpdyStreamId stream_id,
348 SpdyControlFlags flags,
349 const SpdyHeaderBlock* headers) {
350 SpdyHeadersIR headers_ir(stream_id);
351 headers_ir.set_fin((flags & CONTROL_FLAG_FIN) != 0);
352 headers_ir.set_name_value_block(*headers);
353 return spdy_framer_.SerializeHeaders(headers_ir);
356 // TODO(jgraettinger): Eliminate uses of this method (prefer
357 // SpdyWindowUpdateIR).
358 SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate(
359 SpdyStreamId stream_id,
360 uint32 delta_window_size) const {
361 SpdyWindowUpdateIR update_ir(stream_id, delta_window_size);
362 return spdy_framer_.SerializeWindowUpdate(update_ir);
365 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR).
366 SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
367 const char* data,
368 uint32 len,
369 SpdyDataFlags flags) {
370 SpdyDataIR data_ir(stream_id,
371 base::StringPiece(data, len));
372 data_ir.set_fin((flags & DATA_FLAG_FIN) != 0);
373 return spdy_framer_.SerializeData(data_ir);
376 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPushPromiseIR).
377 SpdyFrame* BufferedSpdyFramer::CreatePushPromise(
378 SpdyStreamId stream_id,
379 SpdyStreamId promised_stream_id,
380 const SpdyHeaderBlock* headers) {
381 SpdyPushPromiseIR push_promise_ir(stream_id, promised_stream_id);
382 push_promise_ir.set_name_value_block(*headers);
383 return spdy_framer_.SerializePushPromise(push_promise_ir);
386 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const {
387 return spdy_framer_.GetHighestPriority();
390 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) {
391 memset(header_buffer_, 0, kHeaderBufferSize);
392 header_buffer_used_ = 0;
393 header_buffer_valid_ = true;
394 header_stream_id_ = stream_id;
395 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
398 } // namespace net