// 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 #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 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 OnHeaders(SpdyStreamId stream_id, bool fin) OVERRIDE {} virtual bool OnControlFrameHeaderData(SpdyStreamId stream_id, const char* header_data, size_t len) OVERRIDE; virtual bool OnCredentialFrameData(const char* credential_data, size_t len) OVERRIDE { return false; } 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 void OnSetting(SpdySettingsIds id, uint8 flags, uint32 value) OVERRIDE {} virtual void OnPing(uint32 unique_id) OVERRIDE {} virtual void OnRstStream(SpdyStreamId stream_id, SpdyRstStreamStatus status) OVERRIDE {} virtual void OnGoAway(SpdyStreamId last_accepted_stream_id, SpdyGoAwayStatus status) OVERRIDE {} virtual void OnWindowUpdate(SpdyStreamId stream_id, uint32 delta_window_size) OVERRIDE {} virtual void OnSynStreamCompressed(size_t uncompressed_size, size_t compressed_size) 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(¤t_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(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