prune resources in MemoryCache
[chromium-blink-merge.git] / net / spdy / buffered_spdy_framer.cc
blob568507e5bb407a1f635c6817d97bc2f2fea83b1a
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_15:
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::OnSettings(bool clear_persisted) {
194 visitor_->OnSettings(clear_persisted);
197 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id,
198 uint8 flags,
199 uint32 value) {
200 visitor_->OnSetting(id, flags, value);
203 void BufferedSpdyFramer::OnSettingsAck() {
204 visitor_->OnSettingsAck();
207 void BufferedSpdyFramer::OnSettingsEnd() {
208 visitor_->OnSettingsEnd();
211 void BufferedSpdyFramer::OnPing(SpdyPingId unique_id, bool is_ack) {
212 visitor_->OnPing(unique_id, is_ack);
215 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id,
216 SpdyRstStreamStatus status) {
217 visitor_->OnRstStream(stream_id, status);
219 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id,
220 SpdyGoAwayStatus status) {
221 visitor_->OnGoAway(last_accepted_stream_id, status);
224 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id,
225 uint32 delta_window_size) {
226 visitor_->OnWindowUpdate(stream_id, delta_window_size);
229 void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id,
230 SpdyStreamId promised_stream_id,
231 bool end) {
232 DCHECK_LT(SPDY3, protocol_version());
233 frames_received_++;
234 DCHECK(!control_frame_fields_.get());
235 control_frame_fields_.reset(new ControlFrameFields());
236 control_frame_fields_->type = PUSH_PROMISE;
237 control_frame_fields_->stream_id = stream_id;
238 control_frame_fields_->promised_stream_id = promised_stream_id;
240 InitHeaderStreaming(stream_id);
243 void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id, bool end) {
246 bool BufferedSpdyFramer::OnUnknownFrame(SpdyStreamId stream_id,
247 int frame_type) {
248 return visitor_->OnUnknownFrame(stream_id, frame_type);
251 SpdyMajorVersion BufferedSpdyFramer::protocol_version() {
252 return spdy_framer_.protocol_version();
255 size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) {
256 return spdy_framer_.ProcessInput(data, len);
259 void BufferedSpdyFramer::Reset() {
260 spdy_framer_.Reset();
263 SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const {
264 return spdy_framer_.error_code();
267 SpdyFramer::SpdyState BufferedSpdyFramer::state() const {
268 return spdy_framer_.state();
271 bool BufferedSpdyFramer::MessageFullyRead() {
272 return state() == SpdyFramer::SPDY_AUTO_RESET;
275 bool BufferedSpdyFramer::HasError() {
276 return spdy_framer_.HasError();
279 // TODO(jgraettinger): Eliminate uses of this method (prefer
280 // SpdySynStreamIR).
281 SpdyFrame* BufferedSpdyFramer::CreateSynStream(
282 SpdyStreamId stream_id,
283 SpdyStreamId associated_stream_id,
284 SpdyPriority priority,
285 SpdyControlFlags flags,
286 const SpdyHeaderBlock* headers) {
287 SpdySynStreamIR syn_stream(stream_id);
288 syn_stream.set_associated_to_stream_id(associated_stream_id);
289 syn_stream.set_priority(priority);
290 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0);
291 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0);
292 // TODO(hkhalil): Avoid copy here.
293 syn_stream.set_name_value_block(*headers);
294 return spdy_framer_.SerializeSynStream(syn_stream);
297 // TODO(jgraettinger): Eliminate uses of this method (prefer
298 // SpdySynReplyIR).
299 SpdyFrame* BufferedSpdyFramer::CreateSynReply(
300 SpdyStreamId stream_id,
301 SpdyControlFlags flags,
302 const SpdyHeaderBlock* headers) {
303 SpdySynReplyIR syn_reply(stream_id);
304 syn_reply.set_fin(flags & CONTROL_FLAG_FIN);
305 // TODO(hkhalil): Avoid copy here.
306 syn_reply.set_name_value_block(*headers);
307 return spdy_framer_.SerializeSynReply(syn_reply);
310 // TODO(jgraettinger): Eliminate uses of this method (prefer
311 // SpdyRstStreamIR).
312 SpdyFrame* BufferedSpdyFramer::CreateRstStream(
313 SpdyStreamId stream_id,
314 SpdyRstStreamStatus status) const {
315 // RST_STREAM payloads are not part of any SPDY spec.
316 // SpdyFramer will accept them, but don't create them.
317 SpdyRstStreamIR rst_ir(stream_id, status, "");
318 return spdy_framer_.SerializeRstStream(rst_ir);
321 // TODO(jgraettinger): Eliminate uses of this method (prefer
322 // SpdySettingsIR).
323 SpdyFrame* BufferedSpdyFramer::CreateSettings(
324 const SettingsMap& values) const {
325 SpdySettingsIR settings_ir;
326 for (SettingsMap::const_iterator it = values.begin();
327 it != values.end();
328 ++it) {
329 settings_ir.AddSetting(
330 it->first,
331 (it->second.first & SETTINGS_FLAG_PLEASE_PERSIST) != 0,
332 (it->second.first & SETTINGS_FLAG_PERSISTED) != 0,
333 it->second.second);
335 return spdy_framer_.SerializeSettings(settings_ir);
338 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR).
339 SpdyFrame* BufferedSpdyFramer::CreatePingFrame(SpdyPingId unique_id,
340 bool is_ack) const {
341 SpdyPingIR ping_ir(unique_id);
342 ping_ir.set_is_ack(is_ack);
343 return spdy_framer_.SerializePing(ping_ir);
346 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyGoAwayIR).
347 SpdyFrame* BufferedSpdyFramer::CreateGoAway(
348 SpdyStreamId last_accepted_stream_id,
349 SpdyGoAwayStatus status) const {
350 SpdyGoAwayIR go_ir(last_accepted_stream_id, status, "");
351 return spdy_framer_.SerializeGoAway(go_ir);
354 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyHeadersIR).
355 SpdyFrame* BufferedSpdyFramer::CreateHeaders(
356 SpdyStreamId stream_id,
357 SpdyControlFlags flags,
358 SpdyPriority priority,
359 const SpdyHeaderBlock* headers) {
360 SpdyHeadersIR headers_ir(stream_id);
361 headers_ir.set_fin((flags & CONTROL_FLAG_FIN) != 0);
362 if (flags & HEADERS_FLAG_PRIORITY) {
363 headers_ir.set_has_priority(true);
364 headers_ir.set_priority(priority);
366 headers_ir.set_name_value_block(*headers);
367 return spdy_framer_.SerializeHeaders(headers_ir);
370 // TODO(jgraettinger): Eliminate uses of this method (prefer
371 // SpdyWindowUpdateIR).
372 SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate(
373 SpdyStreamId stream_id,
374 uint32 delta_window_size) const {
375 SpdyWindowUpdateIR update_ir(stream_id, delta_window_size);
376 return spdy_framer_.SerializeWindowUpdate(update_ir);
379 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR).
380 SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id,
381 const char* data,
382 uint32 len,
383 SpdyDataFlags flags) {
384 SpdyDataIR data_ir(stream_id,
385 base::StringPiece(data, len));
386 data_ir.set_fin((flags & DATA_FLAG_FIN) != 0);
387 return spdy_framer_.SerializeData(data_ir);
390 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPushPromiseIR).
391 SpdyFrame* BufferedSpdyFramer::CreatePushPromise(
392 SpdyStreamId stream_id,
393 SpdyStreamId promised_stream_id,
394 const SpdyHeaderBlock* headers) {
395 SpdyPushPromiseIR push_promise_ir(stream_id, promised_stream_id);
396 push_promise_ir.set_name_value_block(*headers);
397 return spdy_framer_.SerializePushPromise(push_promise_ir);
400 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const {
401 return spdy_framer_.GetHighestPriority();
404 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) {
405 memset(header_buffer_, 0, kHeaderBufferSize);
406 header_buffer_used_ = 0;
407 header_buffer_valid_ = true;
408 header_stream_id_ = stream_id;
409 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream);
412 } // namespace net