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 SpdyMajorVersion BufferedSpdyFramer::protocol_version() { 238 return spdy_framer_.protocol_version(); 239 } 240 241 size_t BufferedSpdyFramer::ProcessInput(const char* data, size_t len) { 242 return spdy_framer_.ProcessInput(data, len); 243 } 244 245 void BufferedSpdyFramer::Reset() { 246 spdy_framer_.Reset(); 247 } 248 249 SpdyFramer::SpdyError BufferedSpdyFramer::error_code() const { 250 return spdy_framer_.error_code(); 251 } 252 253 SpdyFramer::SpdyState BufferedSpdyFramer::state() const { 254 return spdy_framer_.state(); 255 } 256 257 bool BufferedSpdyFramer::MessageFullyRead() { 258 return state() == SpdyFramer::SPDY_AUTO_RESET; 259 } 260 261 bool BufferedSpdyFramer::HasError() { 262 return spdy_framer_.HasError(); 263 } 264 265 // TODO(jgraettinger): Eliminate uses of this method (prefer 266 // SpdySynStreamIR). 267 SpdyFrame* BufferedSpdyFramer::CreateSynStream( 268 SpdyStreamId stream_id, 269 SpdyStreamId associated_stream_id, 270 SpdyPriority priority, 271 SpdyControlFlags flags, 272 const SpdyHeaderBlock* headers) { 273 SpdySynStreamIR syn_stream(stream_id); 274 syn_stream.set_associated_to_stream_id(associated_stream_id); 275 syn_stream.set_priority(priority); 276 syn_stream.set_fin((flags & CONTROL_FLAG_FIN) != 0); 277 syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0); 278 // TODO(hkhalil): Avoid copy here. 279 syn_stream.set_name_value_block(*headers); 280 return spdy_framer_.SerializeSynStream(syn_stream); 281 } 282 283 // TODO(jgraettinger): Eliminate uses of this method (prefer 284 // SpdySynReplyIR). 285 SpdyFrame* BufferedSpdyFramer::CreateSynReply( 286 SpdyStreamId stream_id, 287 SpdyControlFlags flags, 288 const SpdyHeaderBlock* headers) { 289 SpdySynReplyIR syn_reply(stream_id); 290 syn_reply.set_fin(flags & CONTROL_FLAG_FIN); 291 // TODO(hkhalil): Avoid copy here. 292 syn_reply.set_name_value_block(*headers); 293 return spdy_framer_.SerializeSynReply(syn_reply); 294 } 295 296 // TODO(jgraettinger): Eliminate uses of this method (prefer 297 // SpdyRstStreamIR). 298 SpdyFrame* BufferedSpdyFramer::CreateRstStream( 299 SpdyStreamId stream_id, 300 SpdyRstStreamStatus status) const { 301 // RST_STREAM payloads are not part of any SPDY spec. 302 // SpdyFramer will accept them, but don't create them. 303 SpdyRstStreamIR rst_ir(stream_id, status, ""); 304 return spdy_framer_.SerializeRstStream(rst_ir); 305 } 306 307 // TODO(jgraettinger): Eliminate uses of this method (prefer 308 // SpdySettingsIR). 309 SpdyFrame* BufferedSpdyFramer::CreateSettings( 310 const SettingsMap& values) const { 311 SpdySettingsIR settings_ir; 312 for (SettingsMap::const_iterator it = values.begin(); 313 it != values.end(); 314 ++it) { 315 settings_ir.AddSetting( 316 it->first, 317 (it->second.first & SETTINGS_FLAG_PLEASE_PERSIST) != 0, 318 (it->second.first & SETTINGS_FLAG_PERSISTED) != 0, 319 it->second.second); 320 } 321 return spdy_framer_.SerializeSettings(settings_ir); 322 } 323 324 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPingIR). 325 SpdyFrame* BufferedSpdyFramer::CreatePingFrame(uint32 unique_id, 326 bool is_ack) const { 327 SpdyPingIR ping_ir(unique_id); 328 ping_ir.set_is_ack(is_ack); 329 return spdy_framer_.SerializePing(ping_ir); 330 } 331 332 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyGoAwayIR). 333 SpdyFrame* BufferedSpdyFramer::CreateGoAway( 334 SpdyStreamId last_accepted_stream_id, 335 SpdyGoAwayStatus status) const { 336 SpdyGoAwayIR go_ir(last_accepted_stream_id, status, ""); 337 return spdy_framer_.SerializeGoAway(go_ir); 338 } 339 340 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyHeadersIR). 341 SpdyFrame* BufferedSpdyFramer::CreateHeaders( 342 SpdyStreamId stream_id, 343 SpdyControlFlags flags, 344 const SpdyHeaderBlock* headers) { 345 SpdyHeadersIR headers_ir(stream_id); 346 headers_ir.set_fin((flags & CONTROL_FLAG_FIN) != 0); 347 headers_ir.set_name_value_block(*headers); 348 return spdy_framer_.SerializeHeaders(headers_ir); 349 } 350 351 // TODO(jgraettinger): Eliminate uses of this method (prefer 352 // SpdyWindowUpdateIR). 353 SpdyFrame* BufferedSpdyFramer::CreateWindowUpdate( 354 SpdyStreamId stream_id, 355 uint32 delta_window_size) const { 356 SpdyWindowUpdateIR update_ir(stream_id, delta_window_size); 357 return spdy_framer_.SerializeWindowUpdate(update_ir); 358 } 359 360 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyDataIR). 361 SpdyFrame* BufferedSpdyFramer::CreateDataFrame(SpdyStreamId stream_id, 362 const char* data, 363 uint32 len, 364 SpdyDataFlags flags) { 365 SpdyDataIR data_ir(stream_id, 366 base::StringPiece(data, len)); 367 data_ir.set_fin((flags & DATA_FLAG_FIN) != 0); 368 return spdy_framer_.SerializeData(data_ir); 369 } 370 371 // TODO(jgraettinger): Eliminate uses of this method (prefer SpdyPushPromiseIR). 372 SpdyFrame* BufferedSpdyFramer::CreatePushPromise( 373 SpdyStreamId stream_id, 374 SpdyStreamId promised_stream_id, 375 const SpdyHeaderBlock* headers) { 376 SpdyPushPromiseIR push_promise_ir(stream_id, promised_stream_id); 377 push_promise_ir.set_name_value_block(*headers); 378 return spdy_framer_.SerializePushPromise(push_promise_ir); 379 } 380 381 SpdyPriority BufferedSpdyFramer::GetHighestPriority() const { 382 return spdy_framer_.GetHighestPriority(); 383 } 384 385 void BufferedSpdyFramer::InitHeaderStreaming(SpdyStreamId stream_id) { 386 memset(header_buffer_, 0, kHeaderBufferSize); 387 header_buffer_used_ = 0; 388 header_buffer_valid_ = true; 389 header_stream_id_ = stream_id; 390 DCHECK_NE(header_stream_id_, SpdyFramer::kInvalidStream); 391 } 392 393 } // namespace net 394