Home | History | Annotate | Download | only in quic
      1 // Copyright (c) 2013 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/quic/quic_spdy_decompressor.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/logging.h"
     10 
     11 using base::StringPiece;
     12 using std::min;
     13 
     14 namespace net {
     15 
     16 class SpdyFramerVisitor : public SpdyFramerVisitorInterface {
     17  public:
     18   explicit SpdyFramerVisitor(QuicSpdyDecompressor::Visitor* visitor)
     19       : visitor_(visitor),
     20         error_(false) {
     21   }
     22 
     23   virtual void OnError(SpdyFramer* framer) OVERRIDE {
     24     error_ = true;
     25   }
     26   virtual void OnDataFrameHeader(SpdyStreamId stream_id,
     27                                  size_t length,
     28                                  bool fin) OVERRIDE {}
     29   virtual void OnStreamFrameData(SpdyStreamId stream_id,
     30                                  const char* data,
     31                                  size_t len,
     32                                  bool fin) OVERRIDE {}
     33   virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
     34                                         const char* header_data,
     35                                         size_t len) OVERRIDE;
     36   virtual void OnSynStream(SpdyStreamId stream_id,
     37                            SpdyStreamId associated_stream_id,
     38                            SpdyPriority priority,
     39                            uint8 credential_slot,
     40                            bool fin,
     41                            bool unidirectional) OVERRIDE {}
     42   virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {}
     43   virtual void OnRstStream(SpdyStreamId stream_id,
     44                            SpdyRstStreamStatus status) OVERRIDE {}
     45   virtual void OnSetting(SpdySettingsIds id,
     46                          uint8 flags,
     47                          uint32 value) OVERRIDE {}
     48   virtual void OnPing(uint32 unique_id) OVERRIDE {}
     49   virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
     50                         SpdyGoAwayStatus status) OVERRIDE {}
     51   virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE {}
     52   virtual void OnWindowUpdate(SpdyStreamId stream_id,
     53                               uint32 delta_window_size) OVERRIDE {}
     54   virtual bool OnCredentialFrameData(const char* credential_data,
     55                                      size_t len) OVERRIDE {
     56     return false;
     57   }
     58   virtual void OnPushPromise(SpdyStreamId stream_id,
     59                              SpdyStreamId promised_stream_id) OVERRIDE {}
     60   void set_visitor(QuicSpdyDecompressor::Visitor* visitor) {
     61     DCHECK(visitor);
     62     visitor_ = visitor;
     63   }
     64 
     65  private:
     66   QuicSpdyDecompressor::Visitor* visitor_;
     67   bool error_;
     68 };
     69 
     70 bool SpdyFramerVisitor::OnControlFrameHeaderData(SpdyStreamId stream_id,
     71                                                  const char* header_data,
     72                                                  size_t len) {
     73   DCHECK(visitor_);
     74   return visitor_->OnDecompressedData(StringPiece(header_data, len));
     75 }
     76 
     77 QuicSpdyDecompressor::QuicSpdyDecompressor()
     78     : spdy_framer_(SPDY3),
     79       spdy_visitor_(new SpdyFramerVisitor(NULL)),
     80       current_header_id_(1),
     81       has_current_compressed_size_(false),
     82       current_compressed_size_(0),
     83       compressed_bytes_consumed_(0) {
     84   spdy_framer_.set_visitor(spdy_visitor_.get());
     85 }
     86 
     87 QuicSpdyDecompressor::~QuicSpdyDecompressor() {
     88 }
     89 
     90 size_t QuicSpdyDecompressor::DecompressData(StringPiece data,
     91                                             Visitor* visitor) {
     92   spdy_visitor_->set_visitor(visitor);
     93   size_t bytes_consumed = 0;
     94 
     95   if (!has_current_compressed_size_) {
     96     const size_t kCompressedBufferSizeSize = sizeof(uint32);
     97     DCHECK_GT(kCompressedBufferSizeSize, compressed_size_buffer_.length());
     98     size_t missing_size =
     99         kCompressedBufferSizeSize - compressed_size_buffer_.length();
    100     if (data.length() < missing_size) {
    101       data.AppendToString(&compressed_size_buffer_);
    102       return data.length();
    103     }
    104     bytes_consumed += missing_size;
    105     data.substr(0, missing_size).AppendToString(&compressed_size_buffer_);
    106     DCHECK_EQ(kCompressedBufferSizeSize, compressed_size_buffer_.length());
    107     memcpy(&current_compressed_size_, compressed_size_buffer_.data(),
    108            kCompressedBufferSizeSize);
    109     compressed_size_buffer_.clear();
    110     has_current_compressed_size_ = true;
    111     data = data.substr(missing_size);
    112     compressed_bytes_consumed_ = 0;
    113   }
    114 
    115   size_t bytes_to_consume =
    116       min(current_compressed_size_ - compressed_bytes_consumed_,
    117           static_cast<uint32>(data.length()));
    118   if (bytes_to_consume > 0) {
    119     if (!spdy_framer_.IncrementallyDecompressControlFrameHeaderData(
    120             current_header_id_, data.data(), bytes_to_consume)) {
    121       visitor->OnDecompressionError();
    122       return bytes_consumed;
    123     }
    124     compressed_bytes_consumed_ += bytes_to_consume;
    125     bytes_consumed += bytes_to_consume;
    126   }
    127   if (current_compressed_size_ - compressed_bytes_consumed_ == 0) {
    128     ResetForNextHeaders();
    129   }
    130   return bytes_consumed;
    131 }
    132 
    133 void QuicSpdyDecompressor::ResetForNextHeaders() {
    134   has_current_compressed_size_ = false;
    135   current_compressed_size_ = 0;
    136   compressed_bytes_consumed_ = 0;
    137   ++current_header_id_;
    138 }
    139 
    140 }  // namespace net
    141