普通文本  |  141行  |  5.02 KB

// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/quic/quic_spdy_decompressor.h"

#include <algorithm>

#include "base/logging.h"

using base::StringPiece;
using std::min;

namespace net {

class SpdyFramerVisitor : public SpdyFramerVisitorInterface {
 public:
  explicit SpdyFramerVisitor(QuicSpdyDecompressor::Visitor* visitor)
      : visitor_(visitor),
        error_(false) {
  }

  virtual void OnError(SpdyFramer* framer) OVERRIDE {
    error_ = true;
  }
  virtual void OnDataFrameHeader(SpdyStreamId stream_id,
                                 size_t length,
                                 bool fin) OVERRIDE {}
  virtual void OnStreamFrameData(SpdyStreamId stream_id,
                                 const char* data,
                                 size_t len,
                                 bool fin) OVERRIDE {}
  virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id,
                                        const char* header_data,
                                        size_t len) OVERRIDE;
  virtual void OnSynStream(SpdyStreamId stream_id,
                           SpdyStreamId associated_stream_id,
                           SpdyPriority priority,
                           uint8 credential_slot,
                           bool fin,
                           bool unidirectional) OVERRIDE {}
  virtual void OnSynReply(SpdyStreamId stream_id, bool fin) OVERRIDE {}
  virtual void OnRstStream(SpdyStreamId stream_id,
                           SpdyRstStreamStatus status) OVERRIDE {}
  virtual void OnSetting(SpdySettingsIds id,
                         uint8 flags,
                         uint32 value) OVERRIDE {}
  virtual void OnPing(uint32 unique_id) OVERRIDE {}
  virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
                        SpdyGoAwayStatus status) OVERRIDE {}
  virtual void OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE {}
  virtual void OnWindowUpdate(SpdyStreamId stream_id,
                              uint32 delta_window_size) OVERRIDE {}
  virtual bool OnCredentialFrameData(const char* credential_data,
                                     size_t len) OVERRIDE {
    return false;
  }
  virtual void OnPushPromise(SpdyStreamId stream_id,
                             SpdyStreamId promised_stream_id) OVERRIDE {}
  void set_visitor(QuicSpdyDecompressor::Visitor* visitor) {
    DCHECK(visitor);
    visitor_ = visitor;
  }

 private:
  QuicSpdyDecompressor::Visitor* visitor_;
  bool error_;
};

bool SpdyFramerVisitor::OnControlFrameHeaderData(SpdyStreamId stream_id,
                                                 const char* header_data,
                                                 size_t len) {
  DCHECK(visitor_);
  return visitor_->OnDecompressedData(StringPiece(header_data, len));
}

QuicSpdyDecompressor::QuicSpdyDecompressor()
    : spdy_framer_(SPDY3),
      spdy_visitor_(new SpdyFramerVisitor(NULL)),
      current_header_id_(1),
      has_current_compressed_size_(false),
      current_compressed_size_(0),
      compressed_bytes_consumed_(0) {
  spdy_framer_.set_visitor(spdy_visitor_.get());
}

QuicSpdyDecompressor::~QuicSpdyDecompressor() {
}

size_t QuicSpdyDecompressor::DecompressData(StringPiece data,
                                            Visitor* visitor) {
  spdy_visitor_->set_visitor(visitor);
  size_t bytes_consumed = 0;

  if (!has_current_compressed_size_) {
    const size_t kCompressedBufferSizeSize = sizeof(uint32);
    DCHECK_GT(kCompressedBufferSizeSize, compressed_size_buffer_.length());
    size_t missing_size =
        kCompressedBufferSizeSize - compressed_size_buffer_.length();
    if (data.length() < missing_size) {
      data.AppendToString(&compressed_size_buffer_);
      return data.length();
    }
    bytes_consumed += missing_size;
    data.substr(0, missing_size).AppendToString(&compressed_size_buffer_);
    DCHECK_EQ(kCompressedBufferSizeSize, compressed_size_buffer_.length());
    memcpy(&current_compressed_size_, compressed_size_buffer_.data(),
           kCompressedBufferSizeSize);
    compressed_size_buffer_.clear();
    has_current_compressed_size_ = true;
    data = data.substr(missing_size);
    compressed_bytes_consumed_ = 0;
  }

  size_t bytes_to_consume =
      min(current_compressed_size_ - compressed_bytes_consumed_,
          static_cast<uint32>(data.length()));
  if (bytes_to_consume > 0) {
    if (!spdy_framer_.IncrementallyDecompressControlFrameHeaderData(
            current_header_id_, data.data(), bytes_to_consume)) {
      visitor->OnDecompressionError();
      return bytes_consumed;
    }
    compressed_bytes_consumed_ += bytes_to_consume;
    bytes_consumed += bytes_to_consume;
  }
  if (current_compressed_size_ - compressed_bytes_consumed_ == 0) {
    ResetForNextHeaders();
  }
  return bytes_consumed;
}

void QuicSpdyDecompressor::ResetForNextHeaders() {
  has_current_compressed_size_ = false;
  current_compressed_size_ = 0;
  compressed_bytes_consumed_ = 0;
  ++current_header_id_;
}

}  // namespace net