Home | History | Annotate | Download | only in spdy
      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