blob: f8bd4c142a81153358da2d2e6f992c113852c29e [file] [log] [blame]
// 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