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 9 namespace net { 10 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; 24 } 25 NOTREACHED(); 26 return SPDY2; 27 } 28 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_)); 39 } 40 41 BufferedSpdyFramer::~BufferedSpdyFramer() { 42 } 43 44 void BufferedSpdyFramer::set_visitor( 45 BufferedSpdyFramerVisitorInterface* visitor) { 46 visitor_ = visitor; 47 spdy_framer_.set_visitor(this); 48 } 49 50 void BufferedSpdyFramer::set_debug_visitor( 51 SpdyFramerDebugVisitorInterface* debug_visitor) { 52 spdy_framer_.set_debug_visitor(debug_visitor); 53 } 54 55 void BufferedSpdyFramer::OnError(SpdyFramer* spdy_framer) { 56 DCHECK(spdy_framer); 57 visitor_->OnError(spdy_framer->error_code()); 58 } 59 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; 74 75 InitHeaderStreaming(stream_id); 76 } 77 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; 87 88 InitHeaderStreaming(stream_id); 89 } 90 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; 99 100 InitHeaderStreaming(stream_id); 101 } 102 103 bool BufferedSpdyFramer::OnControlFrameHeaderData(SpdyStreamId stream_id, 104 const char* header_data, 105 size_t len) { 106 CHECK_EQ(header_stream_id_, stream_id); 107 108 if (len == 0) { 109 // Indicates end-of-header-block. 110 CHECK(header_buffer_valid_); 111 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; 121 } 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; 152 } 153 control_frame_fields_.reset(NULL); 154 return true; 155 } 156 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; 163 } 164 memcpy(header_buffer_ + header_buffer_used_, header_data, len); 165 header_buffer_used_ += len; 166 return true; 167 } 168 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); 175 } 176 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); 182 } 183 184 void BufferedSpdyFramer::OnSettings(bool clear_persisted) { 185 visitor_->OnSettings(clear_persisted); 186 } 187 188 void BufferedSpdyFramer::OnSetting(SpdySettingsIds id, 189 uint8 flags, 190 uint32 value) { 191 visitor_->OnSetting(id, flags, value); 192 } 193 194 void BufferedSpdyFramer::OnSettingsAck() { 195 visitor_->OnSettingsAck(); 196 } 197 198 void BufferedSpdyFramer::OnSettingsEnd() { 199 visitor_->OnSettingsEnd(); 200 } 201 202 void BufferedSpdyFramer::OnPing(SpdyPingId unique_id, bool is_ack) { 203 visitor_->OnPing(unique_id, is_ack); 204 } 205 206 void BufferedSpdyFramer::OnRstStream(SpdyStreamId stream_id, 207 SpdyRstStreamStatus status) { 208 visitor_->OnRstStream(stream_id, status); 209 } 210 void BufferedSpdyFramer::OnGoAway(SpdyStreamId last_accepted_stream_id, 211 SpdyGoAwayStatus status) { 212 visitor_->OnGoAway(last_accepted_stream_id, status); 213 } 214 215 void BufferedSpdyFramer::OnWindowUpdate(SpdyStreamId stream_id, 216 uint32 delta_window_size) { 217 visitor_->OnWindowUpdate(stream_id, delta_window_size); 218 } 219 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; 230 231 InitHeaderStreaming(stream_id); 232 } 233 234 void BufferedSpdyFramer::OnContinuation(SpdyStreamId stream_id, bool end) { 235 } 236 237 bool BufferedSpdyFramer::OnUnknownFrame(SpdyStreamId stream_id, 238 int frame_type) { 239 return visitor_->OnUnknownFrame(stream_id, frame_type); 240 } 241 242 SpdyMajorVersion BufferedSpdyFramer::protocol_version() { 243 return spdy_framer_.protocol_version(); 244 } 245 246 size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) { 247 return spdy_framer_.ProcessInput(data, len); 248 } 249 250 void BufferedSpdyFramer::Reset() { 251 spdy_framer_.Reset(); 252 } 253 254 SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const { 255 return spdy_framer_.error_code(); 256 } 257 258 SpdyFramer::SpdyState BufferedSpdyFramer::state() const { 259 return spdy_framer_.state(); 260 } 261 262 bool BufferedSpdyFramer::MessageFullyRead() { 263 return state() == SpdyFramer::SPDY_AUTO_RESET; 264 } 265 266 bool BufferedSpdyFramer::HasError() { 267 return spdy_framer_.HasError(); 268 } 269 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); 286 } 287 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); 299 } 300 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); 310 } 311 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); 325 } 326 return spdy_framer_.SerializeSettings(settings_ir); 327 } 328 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); 335 } 336 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); 343 } 344 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); 354 } 355 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); 363 } 364 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); 374 } 375 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); 384 } 385 386 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const { 387 return spdy_framer_.GetHighestPriority(); 388 } 389 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); 396 } 397 398 } // namespace net 399