blob: f79edb55bd94cf4b002b43215d17e241d474a4c0 [file] [log] [blame]
// Copyright 2016 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.
#ifndef QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_
#define QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_
// Static and dynamic tables for the HPACK decoder. See:
// http://httpwg.org/specs/rfc7541.html#indexing.tables
// Note that the Lookup methods return nullptr if the requested index was not
// found. This should be treated as a COMPRESSION error according to the HTTP/2
// spec, which is a connection level protocol error (i.e. the connection must
// be terminated). See these sections in the two RFCs:
// http://httpwg.org/specs/rfc7541.html#indexed.header.representation
// http://httpwg.org/specs/rfc7541.html#index.address.space
// http://httpwg.org/specs/rfc7540.html#HeaderBlock
#include <stddef.h>
#include <cstdint>
#include <vector>
#include "http2/hpack/hpack_string.h"
#include "http2/http2_constants.h"
#include "http2/platform/api/http2_containers.h"
#include "common/platform/api/quiche_export.h"
namespace http2 {
namespace test {
class HpackDecoderTablesPeer;
} // namespace test
// See http://httpwg.org/specs/rfc7541.html#static.table.definition for the
// contents, and http://httpwg.org/specs/rfc7541.html#index.address.space for
// info about accessing the static table.
class QUICHE_EXPORT_PRIVATE HpackDecoderStaticTable {
public:
explicit HpackDecoderStaticTable(const std::vector<HpackStringPair>* table);
// Uses a global table shared by all threads.
HpackDecoderStaticTable();
// If index is valid, returns a pointer to the entry, otherwise returns
// nullptr.
const HpackStringPair* Lookup(size_t index) const;
private:
friend class test::HpackDecoderTablesPeer;
const std::vector<HpackStringPair>* const table_;
};
// HpackDecoderDynamicTable implements HPACK compression feature "indexed
// headers"; previously sent headers may be referenced later by their index
// in the dynamic table. See these sections of the RFC:
// http://httpwg.org/specs/rfc7541.html#dynamic.table
// http://httpwg.org/specs/rfc7541.html#dynamic.table.management
class QUICHE_EXPORT_PRIVATE HpackDecoderDynamicTable {
public:
HpackDecoderDynamicTable();
~HpackDecoderDynamicTable();
HpackDecoderDynamicTable(const HpackDecoderDynamicTable&) = delete;
HpackDecoderDynamicTable& operator=(const HpackDecoderDynamicTable&) = delete;
// Sets a new size limit, received from the peer; performs evictions if
// necessary to ensure that the current size does not exceed the new limit.
// The caller needs to have validated that size_limit does not
// exceed the acknowledged value of SETTINGS_HEADER_TABLE_SIZE.
void DynamicTableSizeUpdate(size_t size_limit);
// Insert entry if possible.
// If entry is too large to insert, then dynamic table will be empty.
void Insert(const std::string& name, const std::string& value);
// If index is valid, returns a pointer to the entry, otherwise returns
// nullptr.
const HpackStringPair* Lookup(size_t index) const;
size_t size_limit() const { return size_limit_; }
size_t current_size() const { return current_size_; }
private:
friend class test::HpackDecoderTablesPeer;
// TODO(bnc): Move HpackStringPair class here.
using HpackDecoderTableEntry = HpackStringPair;
// Drop older entries to ensure the size is not greater than limit.
void EnsureSizeNoMoreThan(size_t limit);
// Removes the oldest dynamic table entry.
void RemoveLastEntry();
Http2Deque<HpackDecoderTableEntry> table_;
// The last received DynamicTableSizeUpdate value, initialized to
// SETTINGS_HEADER_TABLE_SIZE.
size_t size_limit_ = Http2SettingsInfo::DefaultHeaderTableSize();
size_t current_size_ = 0;
// insert_count_ and debug_listener_ are used by a QUIC experiment; remove
// when the experiment is done.
size_t insert_count_;
};
class QUICHE_EXPORT_PRIVATE HpackDecoderTables {
public:
HpackDecoderTables();
~HpackDecoderTables();
HpackDecoderTables(const HpackDecoderTables&) = delete;
HpackDecoderTables& operator=(const HpackDecoderTables&) = delete;
// Sets a new size limit, received from the peer; performs evictions if
// necessary to ensure that the current size does not exceed the new limit.
// The caller needs to have validated that size_limit does not
// exceed the acknowledged value of SETTINGS_HEADER_TABLE_SIZE.
void DynamicTableSizeUpdate(size_t size_limit) {
dynamic_table_.DynamicTableSizeUpdate(size_limit);
}
// Insert entry if possible.
// If entry is too large to insert, then dynamic table will be empty.
// TODO(jamessynge): Add methods for moving the string(s) into the table,
// or for otherwise avoiding unnecessary copies.
void Insert(const std::string& name, const std::string& value) {
dynamic_table_.Insert(name, value);
}
// If index is valid, returns a pointer to the entry, otherwise returns
// nullptr.
const HpackStringPair* Lookup(size_t index) const;
// The size limit that the peer (the HPACK encoder) has told the decoder it is
// currently operating with. Defaults to SETTINGS_HEADER_TABLE_SIZE, 4096.
size_t header_table_size_limit() const { return dynamic_table_.size_limit(); }
// Sum of the sizes of the dynamic table entries.
size_t current_header_table_size() const {
return dynamic_table_.current_size();
}
private:
friend class test::HpackDecoderTablesPeer;
HpackDecoderStaticTable static_table_;
HpackDecoderDynamicTable dynamic_table_;
};
} // namespace http2
#endif // QUICHE_HTTP2_HPACK_DECODER_HPACK_DECODER_TABLES_H_