#ifndef QUICHE_COMMON_HTTP_HTTP_HEADER_BLOCK_H_
#define QUICHE_COMMON_HTTP_HTTP_HEADER_BLOCK_H_
#include <stddef.h>
#include <functional>
#include <list>
#include <string>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/container/inlined_vector.h"
#include "absl/strings/string_view.h"
#include "quiche/common/http/http_header_storage.h"
#include "quiche/common/platform/api/quiche_export.h"
#include "quiche/common/platform/api/quiche_logging.h"
#include "quiche/common/quiche_linked_hash_map.h"
#include "quiche/common/quiche_text_utils.h"
namespace quiche {
namespace test {
class HttpHeaderBlockPeer;
class ValueProxyPeer;
}
#ifndef SPDY_HEADER_DEBUG
#if !defined(NDEBUG) || defined(ADDRESS_SANITIZER)
#define SPDY_HEADER_DEBUG 1
#else
#define SPDY_HEADER_DEBUG 0
#endif
#endif
class QUICHE_EXPORT HttpHeaderBlock {
private:
class QUICHE_EXPORT HeaderValue {
public:
HeaderValue(HttpHeaderStorage* storage, absl::string_view key,
absl::string_view initial_value);
HeaderValue(HeaderValue&& other);
HeaderValue& operator=(HeaderValue&& other);
void set_storage(HttpHeaderStorage* storage);
HeaderValue(const HeaderValue& other) = delete;
HeaderValue& operator=(const HeaderValue& other) = delete;
~HeaderValue();
void Append(absl::string_view fragment);
absl::string_view value() const { return as_pair().second; }
const std::pair<absl::string_view, absl::string_view>& as_pair() const;
size_t SizeEstimate() const { return size_; }
private:
absl::string_view ConsolidatedValue() const;
mutable HttpHeaderStorage* storage_;
mutable Fragments fragments_;
mutable std::pair<absl::string_view, absl::string_view> pair_;
size_t size_ = 0;
size_t separator_size_ = 0;
};
typedef quiche::QuicheLinkedHashMap<absl::string_view, HeaderValue,
quiche::StringPieceCaseHash,
quiche::StringPieceCaseEqual>
MapType;
public:
typedef std::pair<absl::string_view, absl::string_view> value_type;
enum class InsertResult {
kInserted,
kReplaced,
};
class QUICHE_EXPORT iterator {
public:
typedef std::pair<absl::string_view, absl::string_view> value_type;
typedef value_type& reference;
typedef value_type* pointer;
typedef std::forward_iterator_tag iterator_category;
typedef MapType::iterator::difference_type difference_type;
typedef const value_type& const_reference;
typedef const value_type* const_pointer;
explicit iterator(MapType::const_iterator it);
iterator(const iterator& other);
~iterator();
const_reference operator*() const {
#if SPDY_HEADER_DEBUG
QUICHE_CHECK(!dereference_forbidden_);
#endif
return it_->second.as_pair();
}
const_pointer operator->() const { return &(this->operator*()); }
bool operator==(const iterator& it) const { return it_ == it.it_; }
bool operator!=(const iterator& it) const { return !(*this == it); }
iterator& operator++() {
it_++;
return *this;
}
iterator operator++(int) {
auto ret = *this;
this->operator++();
return ret;
}
#if SPDY_HEADER_DEBUG
void forbid_dereference() { dereference_forbidden_ = true; }
#endif
private:
MapType::const_iterator it_;
#if SPDY_HEADER_DEBUG
bool dereference_forbidden_ = false;
#endif
};
typedef iterator const_iterator;
HttpHeaderBlock();
HttpHeaderBlock(const HttpHeaderBlock& other) = delete;
HttpHeaderBlock(HttpHeaderBlock&& other);
~HttpHeaderBlock();
HttpHeaderBlock& operator=(const HttpHeaderBlock& other) = delete;
HttpHeaderBlock& operator=(HttpHeaderBlock&& other);
HttpHeaderBlock Clone() const;
bool operator==(const HttpHeaderBlock& other) const;
bool operator!=(const HttpHeaderBlock& other) const;
std::string DebugString() const;
iterator begin() { return wrap_iterator(map_.begin()); }
iterator end() { return wrap_iterator(map_.end()); }
const_iterator begin() const { return wrap_const_iterator(map_.begin()); }
const_iterator end() const { return wrap_const_iterator(map_.end()); }
bool empty() const { return map_.empty(); }
size_t size() const { return map_.size(); }
iterator find(absl::string_view key) { return wrap_iterator(map_.find(key)); }
const_iterator find(absl::string_view key) const {
return wrap_const_iterator(map_.find(key));
}
bool contains(absl::string_view key) const { return find(key) != end(); }
void erase(absl::string_view key);
void clear();
InsertResult insert(const value_type& value);
void AppendValueOrAddHeader(const absl::string_view key,
const absl::string_view value);
class QUICHE_EXPORT ValueProxy {
public:
~ValueProxy();
ValueProxy(ValueProxy&& other);
ValueProxy& operator=(ValueProxy&& other);
ValueProxy(const ValueProxy& other) = delete;
ValueProxy& operator=(const ValueProxy& other) = delete;
ValueProxy& operator=(absl::string_view value);
bool operator==(absl::string_view value) const;
std::string as_string() const;
private:
friend class HttpHeaderBlock;
friend class test::ValueProxyPeer;
ValueProxy(HttpHeaderBlock* block,
HttpHeaderBlock::MapType::iterator lookup_result,
const absl::string_view key,
size_t* spdy_header_block_value_size);
HttpHeaderBlock* block_;
HttpHeaderBlock::MapType::iterator lookup_result_;
absl::string_view key_;
size_t* spdy_header_block_value_size_;
bool valid_;
};
ABSL_MUST_USE_RESULT ValueProxy operator[](const absl::string_view key);
size_t TotalBytesUsed() const { return key_size_ + value_size_; }
private:
friend class test::HttpHeaderBlockPeer;
inline iterator wrap_iterator(MapType::const_iterator inner_iterator) const {
#if SPDY_HEADER_DEBUG
iterator outer_iterator(inner_iterator);
if (inner_iterator == map_.end()) {
outer_iterator.forbid_dereference();
}
return outer_iterator;
#else
return iterator(inner_iterator);
#endif
}
inline const_iterator wrap_const_iterator(
MapType::const_iterator inner_iterator) const {
#if SPDY_HEADER_DEBUG
const_iterator outer_iterator(inner_iterator);
if (inner_iterator == map_.end()) {
outer_iterator.forbid_dereference();
}
return outer_iterator;
#else
return iterator(inner_iterator);
#endif
}
void AppendHeader(const absl::string_view key, const absl::string_view value);
absl::string_view WriteKey(const absl::string_view key);
size_t bytes_allocated() const;
MapType map_;
HttpHeaderStorage storage_;
size_t key_size_ = 0;
size_t value_size_ = 0;
};
inline bool operator==(absl::string_view lhs,
const HttpHeaderBlock::ValueProxy& rhs) {
return rhs == lhs;
}
}
#endif