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. 4 5#include "net/spdy/buffered_spdy_framer.h" 6 7#include "base/logging.h" 8 9namespace net { 10 11SpdyMajorVersion NextProtoToSpdyMajorVersion(NextProto next_proto) { 12 switch (next_proto) { 13 case kProtoSPDY2: 14 case kProtoSPDY21: 15 return SPDY2; 16 case kProtoSPDY3: 17 case kProtoSPDY31: 18 return SPDY3; 19 // SPDY/4 and HTTP/2 share the same framing for now. 20 case kProtoSPDY4a2: 21 case kProtoHTTP2Draft04: 22 return SPDY4; 23 case kProtoUnknown: 24 case kProtoHTTP11: 25 case kProtoSPDY1: 26 case kProtoQUIC1SPDY3: 27 break; 28 } 29 NOTREACHED(); 30 return SPDY2; 31} 32 33BufferedSpdyFramer::BufferedSpdyFramer(SpdyMajorVersion version, 34 bool enable_compression) 35 : spdy_framer_(version), 36 visitor_(NULL), 37 header_buffer_used_(0), 38 header_buffer_valid_(false), 39 header_stream_id_(SpdyFramer::kInvalidStream), 40 frames_received_(0) { 41 spdy_framer_.set_enable_compression(enable_compression); 42 memset(header_buffer_, 0, sizeof(header_buffer_)); 43} 44 45BufferedSpdyFramer::~BufferedSpdyFramer() { 46} 47 48void BufferedSpdyFramer::set_visitor( 49 BufferedSpdyFramerVisitorInterface* visitor) { 50 visitor_ = visitor; 51 spdy_framer_.set_visitor(this); 52} 53 54void BufferedSpdyFramer::set_debug_visitor( 55 SpdyFramerDebugVisitorInterface* debug_visitor) { 56 spdy_framer_.set_debug_visitor(debug_visitor); 57} 58 59void BufferedSpdyFramer::OnError(SpdyFramer* spdy_framer) { 60 DCHECK(spdy_framer); 61 visitor_->OnError(spdy_framer->error_code()); 62} 63 64void BufferedSpdyFramer::OnSynStream(SpdyStreamId stream_id, 65 SpdyStreamId associated_stream_id, 66 SpdyPriority priority, 67 uint8 credential_slot, 68 bool fin, 69 bool unidirectional) { 70 frames_received_++; 71 DCHECK(!control_frame_fields_.get()); 72 control_frame_fields_.reset(new ControlFrameFields()); 73 control_frame_fields_->type = SYN_STREAM; 74 control_frame_fields_->stream_id = stream_id; 75 control_frame_fields_->associated_stream_id = associated_stream_id; 76 control_frame_fields_->priority = priority; 77 control_frame_fields_->credential_slot = credential_slot; 78 control_frame_fields_->fin = fin; 79 control_frame_fields_->unidirectional = unidirectional; 80 81 InitHeaderStreaming(stream_id); 82} 83 84void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id, 85 bool fin) { 86 frames_received_++; 87 DCHECK(!control_frame_fields_.get()); 88 control_frame_fields_.reset(new ControlFrameFields()); 89 control_frame_fields_->type = HEADERS; 90 control_frame_fields_->stream_id = stream_id; 91 control_frame_fields_->fin = fin; 92 93 InitHeaderStreaming(stream_id); 94} 95 96void BufferedSpdyFramer::OnSynReply(SpdyStreamId stream_id, 97 bool fin) { 98 frames_received_++; 99 DCHECK(!control_frame_fields_.get()); 100 control_frame_fields_.reset(new ControlFrameFields()); 101 control_frame_fields_->type = SYN_REPLY; 102 control_frame_fields_->stream_id = stream_id; 103 control_frame_fields_->fin = fin; 104 105 InitHeaderStreaming(stream_id); 106} 107 108bool BufferedSpdyFramer::OnCredentialFrameData(const char* frame_data, 109 size_t len) { 110 DCHECK(false); 111 return false; 112} 113 114bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id, 115 const char* header_data, 116 size_t len) { 117 CHECK_EQ(header_stream_id_, stream_id); 118 119 if (len == 0) { 120 // Indicates end-of-header-block. 121 CHECK(header_buffer_valid_); 122 123 SpdyHeaderBlock headers; 124 size_t parsed_len = spdy_framer_.ParseHeaderBlockInBuffer( 125 header_buffer_, header_buffer_used_, &headers); 126 // TODO(rch): this really should be checking parsed_len != len, 127 // but a bunch of tests fail. Need to figure out why. 128 if (parsed_len == 0) { 129 visitor_->OnStreamError( 130 stream_id, "Could not parse Spdy Control Frame Header."); 131 return false; 132 } 133 DCHECK(control_frame_fields_.get()); 134 switch (control_frame_fields_->type) { 135 case SYN_STREAM: 136 visitor_->OnSynStream(control_frame_fields_->stream_id, 137 control_frame_fields_->associated_stream_id, 138 control_frame_fields_->priority, 139 control_frame_fields_->credential_slot, 140 control_frame_fields_->fin, 141 control_frame_fields_->unidirectional, 142 headers); 143 break; 144 case SYN_REPLY: 145 visitor_->OnSynReply(control_frame_fields_->stream_id, 146 control_frame_fields_->fin, 147 headers); 148 break; 149 case HEADERS: 150 visitor_->OnHeaders(control_frame_fields_->stream_id, 151 control_frame_fields_->fin, 152 headers); 153 break; 154 default: 155 DCHECK(false) << "Unexpect control frame type: " 156 << control_frame_fields_->type; 157 break; 158 } 159 control_frame_fields_.reset(NULL); 160 return true; 161 } 162 163 const size_t available = kHeaderBufferSize - header_buffer_used_; 164 if (len > available) { 165 header_buffer_valid_ = false; 166 visitor_->OnStreamError( 167 stream_id, "Received more data than the allocated size."); 168 return false; 169 } 170 memcpy(header_buffer_ + header_buffer_used_, header_data, len); 171 header_buffer_used_ += len; 172 return true; 173} 174 175void BufferedSpdyFramer::OnDataFrameHeader(SpdyStreamId stream_id, 176 size_t length, 177 bool fin) { 178 frames_received_++; 179 header_stream_id_ = stream_id; 180} 181 182void BufferedSpdyFramer::OnStreamFrameData(SpdyStreamId stream_id, 183 const char* data, 184 size_t len, 185 bool fin) { 186 visitor_->OnStreamFrameData(stream_id, data, len, fin); 187} 188 189void BufferedSpdyFramer::OnSettings(bool clear_persisted) { 190 visitor_->OnSettings(clear_persisted); 191} 192 193void BufferedSpdyFramer::OnSetting(SpdySettingsIds id, 194 uint8 flags, 195 uint32 value) { 196 visitor_->OnSetting(id, flags, value); 197} 198 199void BufferedSpdyFramer::OnPing(uint32 unique_id) { 200 visitor_->OnPing(unique_id); 201} 202 203void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id, 204 SpdyRstStreamStatus status) { 205 visitor_->OnRstStream(stream_id, status); 206} 207void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id, 208 SpdyGoAwayStatus status) { 209 visitor_->OnGoAway(last_accepted_stream_id, status); 210} 211 212void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id, 213 uint32 delta_window_size) { 214 visitor_->OnWindowUpdate(stream_id, delta_window_size); 215} 216 217void BufferedSpdyFramer::OnPushPromise(SpdyStreamId stream_id, 218 SpdyStreamId promised_stream_id) { 219 visitor_->OnPushPromise(stream_id, promised_stream_id); 220} 221 222int BufferedSpdyFramer::protocol_version() { 223 return spdy_framer_.protocol_version(); 224} 225 226size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) { 227 return spdy_framer_.ProcessInput(data, len); 228} 229 230void BufferedSpdyFramer::Reset() { 231 spdy_framer_.Reset(); 232} 233 234SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const { 235 return spdy_framer_.error_code(); 236} 237 238SpdyFramer::SpdyState BufferedSpdyFramer::state() const { 239 return spdy_framer_.state(); 240} 241 242bool BufferedSpdyFramer::MessageFullyRead() { 243 return state() == SpdyFramer::SPDY_AUTO_RESET; 244} 245 246bool BufferedSpdyFramer::HasError() { 247 return spdy_framer_.HasError(); 248} 249 250SpdyFrame* BufferedSpdyFramer::CreateSynStream( 251 SpdyStreamId stream_id, 252 SpdyStreamId associated_stream_id, 253 SpdyPriority priority, 254 uint8 credential_slot, 255 SpdyControlFlags flags, 256 bool compressed, 257 const SpdyHeaderBlock* headers) { 258 return spdy_framer_.CreateSynStream(stream_id, associated_stream_id, priority, 259 credential_slot, flags, compressed, 260 headers); 261} 262 263SpdyFrame* BufferedSpdyFramer::CreateSynReply( 264 SpdyStreamId stream_id, 265 SpdyControlFlags flags, 266 bool compressed, 267 const SpdyHeaderBlock* headers) { 268 return spdy_framer_.CreateSynReply(stream_id, flags, compressed, headers); 269} 270 271SpdyFrame* BufferedSpdyFramer::CreateRstStream( 272 SpdyStreamId stream_id, 273 SpdyRstStreamStatus status) const { 274 return spdy_framer_.CreateRstStream(stream_id, status); 275} 276 277SpdyFrame* BufferedSpdyFramer::CreateSettings( 278 const SettingsMap& values) const { 279 return spdy_framer_.CreateSettings(values); 280} 281 282SpdyFrame* BufferedSpdyFramer::CreatePingFrame( 283 uint32 unique_id) const { 284 return spdy_framer_.CreatePingFrame(unique_id); 285} 286 287SpdyFrame* BufferedSpdyFramer::CreateGoAway( 288 SpdyStreamId last_accepted_stream_id, 289 SpdyGoAwayStatus status) const { 290 return spdy_framer_.CreateGoAway(last_accepted_stream_id, status); 291} 292 293SpdyFrame* BufferedSpdyFramer::CreateHeaders( 294 SpdyStreamId stream_id, 295 SpdyControlFlags flags, 296 bool compressed, 297 const SpdyHeaderBlock* headers) { 298 return spdy_framer_.CreateHeaders(stream_id, flags, compressed, headers); 299} 300 301SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate( 302 SpdyStreamId stream_id, 303 uint32 delta_window_size) const { 304 return spdy_framer_.CreateWindowUpdate(stream_id, delta_window_size); 305} 306 307SpdyFrame* BufferedSpdyFramer::CreateCredentialFrame( 308 const SpdyCredential& credential) const { 309 return spdy_framer_.CreateCredentialFrame(credential); 310} 311 312SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id, 313 const char* data, 314 uint32 len, 315 SpdyDataFlags flags) { 316 return spdy_framer_.CreateDataFrame(stream_id, data, len, flags); 317} 318 319SpdyPriority BufferedSpdyFramer::GetHighestPriority() const { 320 return spdy_framer_.GetHighestPriority(); 321} 322 323void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) { 324 memset(header_buffer_, 0, kHeaderBufferSize); 325 header_buffer_used_ = 0; 326 header_buffer_valid_ = true; 327 header_stream_id_ = stream_id; 328 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); 329} 330 331} // namespace net 332