blob: 465841914614d7d95c6792cbea83a8088593a31e [file] [log] [blame]
QUICHE team82dee2f2019-01-18 12:35:12 -05001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef QUICHE_SPDY_CORE_SPDY_HEADER_BLOCK_H_
6#define QUICHE_SPDY_CORE_SPDY_HEADER_BLOCK_H_
7
8#include <stddef.h>
9
QUICHE teambbce6032020-01-03 07:42:10 -080010#include <functional>
QUICHE team82dee2f2019-01-18 12:35:12 -050011#include <list>
bnc44712912019-08-15 18:58:14 -070012#include <string>
QUICHE team82dee2f2019-01-18 12:35:12 -050013#include <utility>
14#include <vector>
15
vasilvv50465ab2021-02-08 05:50:01 -080016#include "absl/base/attributes.h"
bnc60cef582021-03-24 10:25:37 -070017#include "absl/hash/hash.h"
18#include "absl/strings/ascii.h"
19#include "absl/strings/match.h"
vasilvvc8ccdb22020-10-12 16:42:34 -070020#include "absl/strings/string_view.h"
QUICHE team5be974e2020-12-29 18:35:24 -050021#include "common/platform/api/quiche_export.h"
vasilvved4f3082021-02-01 14:29:40 -080022#include "common/platform/api/quiche_logging.h"
QUICHE team5be974e2020-12-29 18:35:24 -050023#include "spdy/core/spdy_header_storage.h"
24#include "spdy/platform/api/spdy_containers.h"
QUICHE team82dee2f2019-01-18 12:35:12 -050025
26namespace spdy {
27
28namespace test {
QUICHE team1bd18d12020-10-21 08:36:48 -070029class Http2HeaderBlockPeer;
QUICHE team82dee2f2019-01-18 12:35:12 -050030class ValueProxyPeer;
31} // namespace test
32
dschinazib2b26152020-07-01 10:17:25 -070033#ifndef SPDY_HEADER_DEBUG
34#if !defined(NDEBUG) || defined(ADDRESS_SANITIZER)
35#define SPDY_HEADER_DEBUG 1
36#else // !defined(NDEBUG) || defined(ADDRESS_SANITIZER)
37#define SPDY_HEADER_DEBUG 0
38#endif // !defined(NDEBUG) || defined(ADDRESS_SANITIZER)
39#endif // SPDY_HEADER_DEBUG
40
QUICHE team82dee2f2019-01-18 12:35:12 -050041// This class provides a key-value map that can be used to store SPDY header
42// names and values. This data structure preserves insertion order.
43//
44// Under the hood, this data structure uses large, contiguous blocks of memory
vasilvvc8ccdb22020-10-12 16:42:34 -070045// to store names and values. Lookups may be performed with absl::string_view
46// keys, and values are returned as absl::string_views (via ValueProxy, below).
QUICHE team557dfbc2020-10-20 10:52:30 -070047// Value absl::string_views are valid as long as the Http2HeaderBlock exists;
48// allocated memory is never freed until Http2HeaderBlock's destruction.
QUICHE team82dee2f2019-01-18 12:35:12 -050049//
50// This implementation does not make much of an effort to minimize wasted space.
QUICHE team557dfbc2020-10-20 10:52:30 -070051// It's expected that keys are rarely deleted from a Http2HeaderBlock.
52class QUICHE_EXPORT_PRIVATE Http2HeaderBlock {
QUICHE team82dee2f2019-01-18 12:35:12 -050053 private:
QUICHE team82dee2f2019-01-18 12:35:12 -050054 // Stores a list of value fragments that can be joined later with a
55 // key-dependent separator.
bnc45ccf4b2020-01-21 19:05:27 -080056 class QUICHE_EXPORT_PRIVATE HeaderValue {
QUICHE team82dee2f2019-01-18 12:35:12 -050057 public:
QUICHE team6b297002019-12-09 09:37:56 -080058 HeaderValue(SpdyHeaderStorage* storage,
vasilvvc8ccdb22020-10-12 16:42:34 -070059 absl::string_view key,
60 absl::string_view initial_value);
QUICHE team82dee2f2019-01-18 12:35:12 -050061
62 // Moves are allowed.
63 HeaderValue(HeaderValue&& other);
64 HeaderValue& operator=(HeaderValue&& other);
65
QUICHE team0b745502019-12-10 11:02:08 -080066 void set_storage(SpdyHeaderStorage* storage);
67
QUICHE team82dee2f2019-01-18 12:35:12 -050068 // Copies are not.
69 HeaderValue(const HeaderValue& other) = delete;
70 HeaderValue& operator=(const HeaderValue& other) = delete;
71
72 ~HeaderValue();
73
74 // Consumes at most |fragment.size()| bytes of memory.
vasilvvc8ccdb22020-10-12 16:42:34 -070075 void Append(absl::string_view fragment);
QUICHE team82dee2f2019-01-18 12:35:12 -050076
vasilvvc8ccdb22020-10-12 16:42:34 -070077 absl::string_view value() const { return as_pair().second; }
78 const std::pair<absl::string_view, absl::string_view>& as_pair() const;
QUICHE team82dee2f2019-01-18 12:35:12 -050079
80 // Size estimate including separators. Used when keys are erased from
QUICHE team557dfbc2020-10-20 10:52:30 -070081 // Http2HeaderBlock.
QUICHE team82dee2f2019-01-18 12:35:12 -050082 size_t SizeEstimate() const { return size_; }
83
84 private:
85 // May allocate a large contiguous region of memory to hold the concatenated
86 // fragments and separators.
vasilvvc8ccdb22020-10-12 16:42:34 -070087 absl::string_view ConsolidatedValue() const;
QUICHE team82dee2f2019-01-18 12:35:12 -050088
QUICHE team6b297002019-12-09 09:37:56 -080089 mutable SpdyHeaderStorage* storage_;
vasilvvc8ccdb22020-10-12 16:42:34 -070090 mutable std::vector<absl::string_view> fragments_;
QUICHE team82dee2f2019-01-18 12:35:12 -050091 // The first element is the key; the second is the consolidated value.
vasilvvc8ccdb22020-10-12 16:42:34 -070092 mutable std::pair<absl::string_view, absl::string_view> pair_;
QUICHE team82dee2f2019-01-18 12:35:12 -050093 size_t size_ = 0;
94 size_t separator_size_ = 0;
95 };
96
bnc60cef582021-03-24 10:25:37 -070097 struct StringPieceCaseHash {
98 size_t operator()(absl::string_view data) const {
99 std::string lower = absl::AsciiStrToLower(data);
100 absl::Hash<absl::string_view> hasher;
101 return hasher(lower);
102 }
103 };
104
105 struct StringPieceCaseEqual {
106 bool operator()(absl::string_view piece1, absl::string_view piece2) const {
107 return absl::EqualsIgnoreCase(piece1, piece2);
108 }
109 };
110
vasilvvc8ccdb22020-10-12 16:42:34 -0700111 typedef SpdyLinkedHashMap<absl::string_view,
QUICHE teambbce6032020-01-03 07:42:10 -0800112 HeaderValue,
bnc60cef582021-03-24 10:25:37 -0700113 StringPieceCaseHash,
114 StringPieceCaseEqual>
QUICHE team82dee2f2019-01-18 12:35:12 -0500115 MapType;
116
117 public:
vasilvvc8ccdb22020-10-12 16:42:34 -0700118 typedef std::pair<absl::string_view, absl::string_view> value_type;
QUICHE team82dee2f2019-01-18 12:35:12 -0500119
vasilvvc8ccdb22020-10-12 16:42:34 -0700120 // Provides iteration over a sequence of std::pair<absl::string_view,
121 // absl::string_view>, even though the underlying MapType::value_type is
QUICHE team82dee2f2019-01-18 12:35:12 -0500122 // different. Dereferencing the iterator will result in memory allocation for
123 // multi-value headers.
bnc45ccf4b2020-01-21 19:05:27 -0800124 class QUICHE_EXPORT_PRIVATE iterator {
QUICHE team82dee2f2019-01-18 12:35:12 -0500125 public:
126 // The following type definitions fulfill the requirements for iterator
127 // implementations.
vasilvvc8ccdb22020-10-12 16:42:34 -0700128 typedef std::pair<absl::string_view, absl::string_view> value_type;
QUICHE team82dee2f2019-01-18 12:35:12 -0500129 typedef value_type& reference;
130 typedef value_type* pointer;
131 typedef std::forward_iterator_tag iterator_category;
132 typedef MapType::iterator::difference_type difference_type;
133
134 // In practice, this iterator only offers access to const value_type.
135 typedef const value_type& const_reference;
136 typedef const value_type* const_pointer;
137
138 explicit iterator(MapType::const_iterator it);
139 iterator(const iterator& other);
140 ~iterator();
141
142 // This will result in memory allocation if the value consists of multiple
143 // fragments.
dschinazib2b26152020-07-01 10:17:25 -0700144 const_reference operator*() const {
145#if SPDY_HEADER_DEBUG
vasilvved4f3082021-02-01 14:29:40 -0800146 QUICHE_CHECK(!dereference_forbidden_);
dschinazib2b26152020-07-01 10:17:25 -0700147#endif // SPDY_HEADER_DEBUG
148 return it_->second.as_pair();
149 }
QUICHE team82dee2f2019-01-18 12:35:12 -0500150
151 const_pointer operator->() const { return &(this->operator*()); }
152 bool operator==(const iterator& it) const { return it_ == it.it_; }
153 bool operator!=(const iterator& it) const { return !(*this == it); }
154
155 iterator& operator++() {
156 it_++;
157 return *this;
158 }
159
160 iterator operator++(int) {
161 auto ret = *this;
162 this->operator++();
163 return ret;
164 }
165
dschinazib2b26152020-07-01 10:17:25 -0700166#if SPDY_HEADER_DEBUG
167 void forbid_dereference() { dereference_forbidden_ = true; }
168#endif // SPDY_HEADER_DEBUG
169
QUICHE team82dee2f2019-01-18 12:35:12 -0500170 private:
171 MapType::const_iterator it_;
dschinazib2b26152020-07-01 10:17:25 -0700172#if SPDY_HEADER_DEBUG
173 bool dereference_forbidden_ = false;
174#endif // SPDY_HEADER_DEBUG
QUICHE team82dee2f2019-01-18 12:35:12 -0500175 };
176 typedef iterator const_iterator;
177
QUICHE team557dfbc2020-10-20 10:52:30 -0700178 Http2HeaderBlock();
179 Http2HeaderBlock(const Http2HeaderBlock& other) = delete;
180 Http2HeaderBlock(Http2HeaderBlock&& other);
181 ~Http2HeaderBlock();
QUICHE team82dee2f2019-01-18 12:35:12 -0500182
QUICHE team557dfbc2020-10-20 10:52:30 -0700183 Http2HeaderBlock& operator=(const Http2HeaderBlock& other) = delete;
184 Http2HeaderBlock& operator=(Http2HeaderBlock&& other);
185 Http2HeaderBlock Clone() const;
QUICHE team82dee2f2019-01-18 12:35:12 -0500186
QUICHE team557dfbc2020-10-20 10:52:30 -0700187 bool operator==(const Http2HeaderBlock& other) const;
188 bool operator!=(const Http2HeaderBlock& other) const;
QUICHE team82dee2f2019-01-18 12:35:12 -0500189
190 // Provides a human readable multi-line representation of the stored header
191 // keys and values.
bnc44712912019-08-15 18:58:14 -0700192 std::string DebugString() const;
QUICHE team82dee2f2019-01-18 12:35:12 -0500193
dschinazib2b26152020-07-01 10:17:25 -0700194 iterator begin() { return wrap_iterator(map_.begin()); }
195 iterator end() { return wrap_iterator(map_.end()); }
196 const_iterator begin() const { return wrap_const_iterator(map_.begin()); }
197 const_iterator end() const { return wrap_const_iterator(map_.end()); }
QUICHE team8e3bb9d2019-12-06 16:03:22 -0800198 bool empty() const { return map_.empty(); }
199 size_t size() const { return map_.size(); }
vasilvvc8ccdb22020-10-12 16:42:34 -0700200 iterator find(absl::string_view key) { return wrap_iterator(map_.find(key)); }
201 const_iterator find(absl::string_view key) const {
dschinazib2b26152020-07-01 10:17:25 -0700202 return wrap_const_iterator(map_.find(key));
QUICHE team82dee2f2019-01-18 12:35:12 -0500203 }
vasilvvc8ccdb22020-10-12 16:42:34 -0700204 void erase(absl::string_view key);
QUICHE team82dee2f2019-01-18 12:35:12 -0500205
206 // Clears both our MapType member and the memory used to hold headers.
207 void clear();
208
209 // The next few methods copy data into our backing storage.
210
211 // If key already exists in the block, replaces the value of that key. Else
212 // adds a new header to the end of the block.
213 void insert(const value_type& value);
214
215 // If a header with the key is already present, then append the value to the
216 // existing header value, NUL ("\0") separated unless the key is cookie, in
217 // which case the separator is "; ".
218 // If there is no such key, a new header with the key and value is added.
vasilvvc8ccdb22020-10-12 16:42:34 -0700219 void AppendValueOrAddHeader(const absl::string_view key,
220 const absl::string_view value);
QUICHE team82dee2f2019-01-18 12:35:12 -0500221
QUICHE team557dfbc2020-10-20 10:52:30 -0700222 // This object provides automatic conversions that allow Http2HeaderBlock to
223 // be nearly a drop-in replacement for
bnc44712912019-08-15 18:58:14 -0700224 // SpdyLinkedHashMap<std::string, std::string>.
QUICHE team6b297002019-12-09 09:37:56 -0800225 // It reads data from or writes data to a SpdyHeaderStorage.
bnc45ccf4b2020-01-21 19:05:27 -0800226 class QUICHE_EXPORT_PRIVATE ValueProxy {
QUICHE team82dee2f2019-01-18 12:35:12 -0500227 public:
228 ~ValueProxy();
229
230 // Moves are allowed.
231 ValueProxy(ValueProxy&& other);
232 ValueProxy& operator=(ValueProxy&& other);
233
234 // Copies are not.
235 ValueProxy(const ValueProxy& other) = delete;
236 ValueProxy& operator=(const ValueProxy& other) = delete;
237
QUICHE team557dfbc2020-10-20 10:52:30 -0700238 // Assignment modifies the underlying Http2HeaderBlock.
vasilvvc8ccdb22020-10-12 16:42:34 -0700239 ValueProxy& operator=(absl::string_view value);
QUICHE team3f57c752019-12-16 14:09:53 -0800240
vasilvvc8ccdb22020-10-12 16:42:34 -0700241 // Provides easy comparison against absl::string_view.
242 bool operator==(absl::string_view value) const;
QUICHE team82dee2f2019-01-18 12:35:12 -0500243
bnc44712912019-08-15 18:58:14 -0700244 std::string as_string() const;
QUICHE team82dee2f2019-01-18 12:35:12 -0500245
246 private:
QUICHE team557dfbc2020-10-20 10:52:30 -0700247 friend class Http2HeaderBlock;
QUICHE team82dee2f2019-01-18 12:35:12 -0500248 friend class test::ValueProxyPeer;
249
QUICHE team557dfbc2020-10-20 10:52:30 -0700250 ValueProxy(Http2HeaderBlock* block,
251 Http2HeaderBlock::MapType::iterator lookup_result,
vasilvvc8ccdb22020-10-12 16:42:34 -0700252 const absl::string_view key,
QUICHE team82dee2f2019-01-18 12:35:12 -0500253 size_t* spdy_header_block_value_size);
254
QUICHE team557dfbc2020-10-20 10:52:30 -0700255 Http2HeaderBlock* block_;
256 Http2HeaderBlock::MapType::iterator lookup_result_;
vasilvvc8ccdb22020-10-12 16:42:34 -0700257 absl::string_view key_;
QUICHE team82dee2f2019-01-18 12:35:12 -0500258 size_t* spdy_header_block_value_size_;
259 bool valid_;
260 };
261
QUICHE team8e3bb9d2019-12-06 16:03:22 -0800262 // Allows either lookup or mutation of the value associated with a key.
vasilvv50465ab2021-02-08 05:50:01 -0800263 ABSL_MUST_USE_RESULT ValueProxy operator[](const absl::string_view key);
QUICHE team8e3bb9d2019-12-06 16:03:22 -0800264
QUICHE team82dee2f2019-01-18 12:35:12 -0500265 // Returns the estimate of dynamically allocated memory in bytes.
266 size_t EstimateMemoryUsage() const;
267
268 size_t TotalBytesUsed() const { return key_size_ + value_size_; }
269
270 private:
QUICHE team1bd18d12020-10-21 08:36:48 -0700271 friend class test::Http2HeaderBlockPeer;
QUICHE team82dee2f2019-01-18 12:35:12 -0500272
dschinazib2b26152020-07-01 10:17:25 -0700273 inline iterator wrap_iterator(MapType::const_iterator inner_iterator) const {
274#if SPDY_HEADER_DEBUG
275 iterator outer_iterator(inner_iterator);
276 if (inner_iterator == map_.end()) {
277 outer_iterator.forbid_dereference();
278 }
279 return outer_iterator;
280#else // SPDY_HEADER_DEBUG
281 return iterator(inner_iterator);
282#endif // SPDY_HEADER_DEBUG
283 }
284
285 inline const_iterator wrap_const_iterator(
286 MapType::const_iterator inner_iterator) const {
287#if SPDY_HEADER_DEBUG
288 const_iterator outer_iterator(inner_iterator);
289 if (inner_iterator == map_.end()) {
290 outer_iterator.forbid_dereference();
291 }
292 return outer_iterator;
293#else // SPDY_HEADER_DEBUG
294 return iterator(inner_iterator);
295#endif // SPDY_HEADER_DEBUG
296 }
297
vasilvvc8ccdb22020-10-12 16:42:34 -0700298 void AppendHeader(const absl::string_view key, const absl::string_view value);
299 absl::string_view WriteKey(const absl::string_view key);
QUICHE team82dee2f2019-01-18 12:35:12 -0500300 size_t bytes_allocated() const;
301
vasilvvc8ccdb22020-10-12 16:42:34 -0700302 // absl::string_views held by |map_| point to memory owned by |storage_|.
QUICHE team8e3bb9d2019-12-06 16:03:22 -0800303 MapType map_;
QUICHE team0b745502019-12-10 11:02:08 -0800304 SpdyHeaderStorage storage_;
QUICHE team82dee2f2019-01-18 12:35:12 -0500305
306 size_t key_size_ = 0;
307 size_t value_size_ = 0;
308};
309
QUICHE team557dfbc2020-10-20 10:52:30 -0700310// TODO(b/156770486): Remove this alias when the rename is complete.
311using SpdyHeaderBlock = Http2HeaderBlock;
312
QUICHE team82dee2f2019-01-18 12:35:12 -0500313} // namespace spdy
314
315#endif // QUICHE_SPDY_CORE_SPDY_HEADER_BLOCK_H_