1 // Copyright 2022 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 // A lightweight implementation for storing HTTP headers.
6
7 #ifndef QUICHE_BALSA_BALSA_HEADERS_H_
8 #define QUICHE_BALSA_BALSA_HEADERS_H_
9
10 #include <cstddef>
11 #include <cstring>
12 #include <functional>
13 #include <iterator>
14 #include <memory>
15 #include <optional>
16 #include <ostream>
17 #include <string>
18 #include <utility>
19 #include <vector>
20
21 #include "absl/container/flat_hash_map.h"
22 #include "absl/container/flat_hash_set.h"
23 #include "absl/memory/memory.h"
24 #include "absl/strings/ascii.h"
25 #include "absl/strings/match.h"
26 #include "absl/strings/string_view.h"
27 #include "quiche/balsa/balsa_enums.h"
28 #include "quiche/balsa/header_api.h"
29 #include "quiche/balsa/standard_header_map.h"
30 #include "quiche/common/platform/api/quiche_bug_tracker.h"
31 #include "quiche/common/platform/api/quiche_export.h"
32 #include "quiche/common/platform/api/quiche_logging.h"
33 #include "quiche/common/quiche_callbacks.h"
34
35 namespace gfe2 {
36 class Http2HeaderValidator;
37 } // namespace gfe2
38
39 namespace quiche {
40
41 namespace test {
42 class BalsaHeadersTestPeer;
43 } // namespace test
44
45 // WARNING:
46 // Note that -no- char* returned by any function in this
47 // file is null-terminated.
48
49 // This class exists to service the specific needs of BalsaHeaders.
50 //
51 // Functional goals:
52 // 1) provide a backing-store for all of the StringPieces that BalsaHeaders
53 // returns. Every StringPiece returned from BalsaHeaders should remain
54 // valid until the BalsaHeader's object is cleared, or the header-line is
55 // erased.
56 // 2) provide a backing-store for BalsaFrame, which requires contiguous memory
57 // for its fast-path parsing functions. Note that the cost of copying is
58 // less than the cost of requiring the parser to do slow-path parsing, as
59 // it would have to check for bounds every byte, instead of every 16 bytes.
60 //
61 // This class is optimized for the case where headers are stored in one of two
62 // buffers. It doesn't make a lot of effort to densely pack memory-- in fact,
63 // it -may- be somewhat memory inefficient. This possible inefficiency allows a
64 // certain simplicity of implementation and speed which makes it worthwhile.
65 // If, in the future, better memory density is required, it should be possible
66 // to reuse the abstraction presented by this object to achieve those goals.
67 //
68 // In the most common use-case, this memory inefficiency should be relatively
69 // small.
70 //
71 // Alternate implementations of BalsaBuffer may include:
72 // - vector of strings, one per header line (similar to HTTPHeaders)
73 // - densely packed strings:
74 // - keep a sorted array/map of free-space linked lists or numbers.
75 // - use the entry that most closely first your needs.
76 // - at this point, perhaps just use a vector of strings, and let
77 // the allocator do the right thing.
78 //
79 class QUICHE_EXPORT BalsaBuffer {
80 public:
81 static constexpr size_t kDefaultBlocksize = 4096;
82
83 // The BufferBlock is a structure used internally by the
84 // BalsaBuffer class to store the base buffer pointers to
85 // each block, as well as the important metadata for buffer
86 // sizes and bytes free. It *may* be possible to replace this
87 // with a vector<char>, but it's unclear whether moving a vector
88 // can invalidate pointers into it. LWG issue 2321 proposes to fix this.
89 struct QUICHE_EXPORT BufferBlock {
90 public:
91 std::unique_ptr<char[]> buffer;
92 size_t buffer_size = 0;
93 size_t bytes_free = 0;
94
bytes_usedBufferBlock95 size_t bytes_used() const { return buffer_size - bytes_free; }
start_of_unused_bytesBufferBlock96 char* start_of_unused_bytes() const { return buffer.get() + bytes_used(); }
97
BufferBlockBufferBlock98 BufferBlock() {}
99
BufferBlockBufferBlock100 BufferBlock(std::unique_ptr<char[]> buf, size_t size, size_t free)
101 : buffer(std::move(buf)), buffer_size(size), bytes_free(free) {}
102
103 BufferBlock(const BufferBlock&) = delete;
104 BufferBlock& operator=(const BufferBlock&) = delete;
105 BufferBlock(BufferBlock&&) = default;
106 BufferBlock& operator=(BufferBlock&&) = default;
107
108 // Note: allocating a fresh buffer even if we could reuse an old one may let
109 // us shed memory, and invalidates old StringPieces (making them easier to
110 // catch with asan).
CopyFromBufferBlock111 void CopyFrom(const BufferBlock& rhs) {
112 QUICHE_DCHECK(this != &rhs);
113 buffer_size = rhs.buffer_size;
114 bytes_free = rhs.bytes_free;
115 if (rhs.buffer == nullptr) {
116 buffer = nullptr;
117 } else {
118 buffer = std::make_unique<char[]>(buffer_size);
119 memcpy(buffer.get(), rhs.buffer.get(), rhs.bytes_used());
120 }
121 }
122 };
123
124 typedef std::vector<BufferBlock> Blocks;
125
BalsaBuffer()126 BalsaBuffer()
127 : blocksize_(kDefaultBlocksize), can_write_to_contiguous_buffer_(true) {}
128
BalsaBuffer(size_t blocksize)129 explicit BalsaBuffer(size_t blocksize)
130 : blocksize_(blocksize), can_write_to_contiguous_buffer_(true) {}
131
132 BalsaBuffer(const BalsaBuffer&) = delete;
133 BalsaBuffer& operator=(const BalsaBuffer&) = delete;
134 BalsaBuffer(BalsaBuffer&&) = default;
135 BalsaBuffer& operator=(BalsaBuffer&&) = default;
136
137 // Returns the total amount of memory reserved by the buffer blocks.
GetTotalBufferBlockSize()138 size_t GetTotalBufferBlockSize() const {
139 size_t buffer_size = 0;
140 for (Blocks::const_iterator iter = blocks_.begin(); iter != blocks_.end();
141 ++iter) {
142 buffer_size += iter->buffer_size;
143 }
144 return buffer_size;
145 }
146
147 // Returns the total amount of memory used by the buffer blocks.
GetTotalBytesUsed()148 size_t GetTotalBytesUsed() const {
149 size_t bytes_used = 0;
150 for (const auto& b : blocks_) {
151 bytes_used += b.bytes_used();
152 }
153 return bytes_used;
154 }
155
GetPtr(Blocks::size_type block_idx)156 const char* GetPtr(Blocks::size_type block_idx) const {
157 QUICHE_DCHECK_LT(block_idx, blocks_.size())
158 << block_idx << ", " << blocks_.size();
159 return block_idx >= blocks_.size() ? nullptr
160 : blocks_[block_idx].buffer.get();
161 }
162
GetPtr(Blocks::size_type block_idx)163 char* GetPtr(Blocks::size_type block_idx) {
164 QUICHE_DCHECK_LT(block_idx, blocks_.size())
165 << block_idx << ", " << blocks_.size();
166 return block_idx >= blocks_.size() ? nullptr
167 : blocks_[block_idx].buffer.get();
168 }
169
170 // This function is different from Reserve(), as it ensures that the data
171 // stored via subsequent calls to this function are all contiguous (and in
172 // the order in which these writes happened). This is essentially the same
173 // as a string append.
174 //
175 // You may call this function at any time between object
176 // construction/Clear(), and the calling of the
177 // NoMoreWriteToContiguousBuffer() function.
178 //
179 // You must not call this function after the NoMoreWriteToContiguousBuffer()
180 // function is called, unless a Clear() has been called since.
181 // If you do, the program will abort().
182 //
183 // This condition is placed upon this code so that calls to Reserve() can
184 // append to the buffer in the first block safely, and without invaliding
185 // the StringPiece which it returns.
186 //
187 // This function's main intended user is the BalsaFrame class, which,
188 // for reasons of efficiency, requires that the buffer from which it parses
189 // the headers be contiguous.
190 //
WriteToContiguousBuffer(absl::string_view sp)191 void WriteToContiguousBuffer(absl::string_view sp) {
192 if (sp.empty()) {
193 return;
194 }
195 QUICHE_CHECK(can_write_to_contiguous_buffer_);
196
197 if (blocks_.empty()) {
198 blocks_.push_back(AllocBlock());
199 }
200
201 QUICHE_DCHECK_GE(blocks_.size(), 1u);
202 if (blocks_[0].buffer == nullptr && sp.size() <= blocksize_) {
203 blocks_[0] = AllocBlock();
204 memcpy(blocks_[0].start_of_unused_bytes(), sp.data(), sp.size());
205 } else if (blocks_[0].bytes_free < sp.size()) {
206 // the first block isn't big enough, resize it.
207 const size_t old_storage_size_used = blocks_[0].bytes_used();
208 // Increase to at least 2*old_storage_size_used; if sp.size() is larger,
209 // we'll increase by that amount.
210 const size_t new_storage_size =
211 old_storage_size_used + (old_storage_size_used < sp.size()
212 ? sp.size()
213 : old_storage_size_used);
214 std::unique_ptr<char[]> new_storage{new char[new_storage_size]};
215 char* old_storage = blocks_[0].buffer.get();
216 if (old_storage_size_used != 0u) {
217 memcpy(new_storage.get(), old_storage, old_storage_size_used);
218 }
219 memcpy(new_storage.get() + old_storage_size_used, sp.data(), sp.size());
220 blocks_[0].buffer = std::move(new_storage);
221 blocks_[0].bytes_free = new_storage_size - old_storage_size_used;
222 blocks_[0].buffer_size = new_storage_size;
223 } else {
224 memcpy(blocks_[0].start_of_unused_bytes(), sp.data(), sp.size());
225 }
226 blocks_[0].bytes_free -= sp.size();
227 }
228
NoMoreWriteToContiguousBuffer()229 void NoMoreWriteToContiguousBuffer() {
230 can_write_to_contiguous_buffer_ = false;
231 }
232
233 // Reserves "permanent" storage of the size indicated. Returns a pointer to
234 // the beginning of that storage, and assigns the index of the block used to
235 // block_buffer_idx. This function uses the first block IFF the
236 // NoMoreWriteToContiguousBuffer function has been called since the last
237 // Clear/Construction.
Reserve(size_t size,Blocks::size_type * block_buffer_idx)238 char* Reserve(size_t size, Blocks::size_type* block_buffer_idx) {
239 if (blocks_.empty()) {
240 blocks_.push_back(AllocBlock());
241 }
242
243 // There should always be a 'first_block', even if it
244 // contains nothing.
245 QUICHE_DCHECK_GE(blocks_.size(), 1u);
246 BufferBlock* block = nullptr;
247 Blocks::size_type block_idx = can_write_to_contiguous_buffer_ ? 1 : 0;
248 for (; block_idx < blocks_.size(); ++block_idx) {
249 if (blocks_[block_idx].bytes_free >= size) {
250 block = &blocks_[block_idx];
251 break;
252 }
253 }
254 if (block == nullptr) {
255 if (blocksize_ < size) {
256 blocks_.push_back(AllocCustomBlock(size));
257 } else {
258 blocks_.push_back(AllocBlock());
259 }
260 block = &blocks_.back();
261 }
262
263 char* storage = block->start_of_unused_bytes();
264 block->bytes_free -= size;
265 if (block_buffer_idx != nullptr) {
266 *block_buffer_idx = block_idx;
267 }
268 return storage;
269 }
270
Clear()271 void Clear() {
272 blocks_.clear();
273 blocks_.shrink_to_fit();
274 can_write_to_contiguous_buffer_ = true;
275 }
276
CopyFrom(const BalsaBuffer & b)277 void CopyFrom(const BalsaBuffer& b) {
278 blocks_.resize(b.blocks_.size());
279 for (Blocks::size_type i = 0; i < blocks_.size(); ++i) {
280 blocks_[i].CopyFrom(b.blocks_[i]);
281 }
282 blocksize_ = b.blocksize_;
283 can_write_to_contiguous_buffer_ = b.can_write_to_contiguous_buffer_;
284 }
285
StartOfFirstBlock()286 const char* StartOfFirstBlock() const {
287 QUICHE_BUG_IF(bug_if_1182_1, blocks_.empty())
288 << "First block not allocated yet!";
289 return blocks_.empty() ? nullptr : blocks_[0].buffer.get();
290 }
291
EndOfFirstBlock()292 const char* EndOfFirstBlock() const {
293 QUICHE_BUG_IF(bug_if_1182_2, blocks_.empty())
294 << "First block not allocated yet!";
295 return blocks_.empty() ? nullptr : blocks_[0].start_of_unused_bytes();
296 }
297
GetReadableBytesOfFirstBlock()298 size_t GetReadableBytesOfFirstBlock() const {
299 return blocks_.empty() ? 0 : blocks_[0].bytes_used();
300 }
301
can_write_to_contiguous_buffer()302 bool can_write_to_contiguous_buffer() const {
303 return can_write_to_contiguous_buffer_;
304 }
blocksize()305 size_t blocksize() const { return blocksize_; }
num_blocks()306 Blocks::size_type num_blocks() const { return blocks_.size(); }
buffer_size(size_t idx)307 size_t buffer_size(size_t idx) const { return blocks_[idx].buffer_size; }
bytes_used(size_t idx)308 size_t bytes_used(size_t idx) const { return blocks_[idx].bytes_used(); }
309
310 private:
AllocBlock()311 BufferBlock AllocBlock() { return AllocCustomBlock(blocksize_); }
312
AllocCustomBlock(size_t blocksize)313 BufferBlock AllocCustomBlock(size_t blocksize) {
314 return BufferBlock{std::make_unique<char[]>(blocksize), blocksize,
315 blocksize};
316 }
317
318 // A container of BufferBlocks
319 Blocks blocks_;
320
321 // The default allocation size for a block.
322 // In general, blocksize_ bytes will be allocated for
323 // each buffer.
324 size_t blocksize_;
325
326 // If set to true, then the first block cannot be used for Reserve() calls as
327 // the WriteToContiguous... function will modify the base pointer for this
328 // block, and the Reserve() calls need to be sure that the base pointer will
329 // not be changing in order to provide the user with StringPieces which
330 // continue to be valid.
331 bool can_write_to_contiguous_buffer_;
332 };
333
334 ////////////////////////////////////////////////////////////////////////////////
335
336 // All of the functions in the BalsaHeaders class use string pieces, by either
337 // using the StringPiece class, or giving an explicit size and char* (as these
338 // are the native representation for these string pieces).
339 // This is done for several reasons.
340 // 1) This minimizes copying/allocation/deallocation as compared to using
341 // string parameters
342 // 2) This reduces the number of strlen() calls done (as the length of any
343 // string passed in is relatively likely to be known at compile time, and for
344 // those strings passed back we obviate the need for a strlen() to determine
345 // the size of new storage allocations if a new allocation is required.
346 // 3) This class attempts to store all of its data in two linear buffers in
347 // order to enhance the speed of parsing and writing out to a buffer. As a
348 // result, many string pieces are -not- terminated by '\0', and are not
349 // c-strings. Since this is the case, we must delineate the length of the
350 // string explicitly via a length.
351 //
352 // WARNING: The side effect of using StringPiece is that if the underlying
353 // buffer changes (due to modifying the headers) the StringPieces which point
354 // to the data which was modified, may now contain "garbage", and should not
355 // be dereferenced.
356 // For example, If you fetch some component of the first-line, (request or
357 // response), and then you modify the first line, the StringPieces you
358 // originally received from the original first-line may no longer be valid).
359 //
360 // StringPieces pointing to pieces of header lines which have not been
361 // erased() or modified should be valid until the object is cleared or
362 // destroyed.
363 //
364 // Key comparisons are case-insensitive.
365
366 class QUICHE_EXPORT BalsaHeaders : public HeaderApi {
367 public:
368 // Each header line is parsed into a HeaderLineDescription, which maintains
369 // pointers into the BalsaBuffer.
370 //
371 // Succinctly describes one header line as indices into a buffer.
372 struct QUICHE_EXPORT HeaderLineDescription {
HeaderLineDescriptionHeaderLineDescription373 HeaderLineDescription(size_t first_character_index, size_t key_end_index,
374 size_t value_begin_index, size_t last_character_index,
375 size_t buffer_base_index)
376 : first_char_idx(first_character_index),
377 key_end_idx(key_end_index),
378 value_begin_idx(value_begin_index),
379 last_char_idx(last_character_index),
380 buffer_base_idx(buffer_base_index),
381 skip(false) {}
382
HeaderLineDescriptionHeaderLineDescription383 HeaderLineDescription()
384 : first_char_idx(0),
385 key_end_idx(0),
386 value_begin_idx(0),
387 last_char_idx(0),
388 buffer_base_idx(0),
389 skip(false) {}
390
KeyLengthHeaderLineDescription391 size_t KeyLength() const {
392 QUICHE_DCHECK_GE(key_end_idx, first_char_idx);
393 return key_end_idx - first_char_idx;
394 }
ValuesLengthHeaderLineDescription395 size_t ValuesLength() const {
396 QUICHE_DCHECK_GE(last_char_idx, value_begin_idx);
397 return last_char_idx - value_begin_idx;
398 }
399
400 size_t first_char_idx;
401 size_t key_end_idx;
402 size_t value_begin_idx;
403 size_t last_char_idx;
404 BalsaBuffer::Blocks::size_type buffer_base_idx;
405 bool skip;
406 };
407
408 using HeaderTokenList = std::vector<absl::string_view>;
409
410 // An iterator for walking through all the header lines.
411 class const_header_lines_iterator;
412
413 // An iterator that only stops at lines with a particular key
414 // (case-insensitive). See also GetIteratorForKey.
415 //
416 // Check against header_lines_key_end() to determine when iteration is
417 // finished. lines().end() will also work.
418 class const_header_lines_key_iterator;
419
420 // A simple class that can be used in a range-based for loop.
421 template <typename IteratorType>
422 class QUICHE_EXPORT iterator_range {
423 public:
424 using iterator = IteratorType;
425 using const_iterator = IteratorType;
426 using value_type = typename std::iterator_traits<IteratorType>::value_type;
427
iterator_range(IteratorType begin_iterator,IteratorType end_iterator)428 iterator_range(IteratorType begin_iterator, IteratorType end_iterator)
429 : begin_iterator_(std::move(begin_iterator)),
430 end_iterator_(std::move(end_iterator)) {}
431
begin()432 IteratorType begin() const { return begin_iterator_; }
end()433 IteratorType end() const { return end_iterator_; }
434
435 private:
436 IteratorType begin_iterator_, end_iterator_;
437 };
438
439 // Set of names of headers that might have multiple values.
440 // CoalesceOption::kCoalesce can be used to match Envoy behavior in
441 // WriteToBuffer().
442 using MultivaluedHeadersSet =
443 absl::flat_hash_set<absl::string_view, StringPieceCaseHash,
444 StringPieceCaseEqual>;
445
446 // Map of key => vector<value>, where vector contains ordered list of all
447 // values for |key| (ignoring the casing).
448 using MultivaluedHeadersValuesMap =
449 absl::flat_hash_map<absl::string_view, std::vector<absl::string_view>,
450 StringPieceCaseHash, StringPieceCaseEqual>;
451
BalsaHeaders()452 BalsaHeaders()
453 : balsa_buffer_(4096),
454 content_length_(0),
455 content_length_status_(BalsaHeadersEnums::NO_CONTENT_LENGTH),
456 parsed_response_code_(0),
457 firstline_buffer_base_idx_(0),
458 whitespace_1_idx_(0),
459 non_whitespace_1_idx_(0),
460 whitespace_2_idx_(0),
461 non_whitespace_2_idx_(0),
462 whitespace_3_idx_(0),
463 non_whitespace_3_idx_(0),
464 whitespace_4_idx_(0),
465 transfer_encoding_is_chunked_(false) {}
466
BalsaHeaders(size_t bufsize)467 explicit BalsaHeaders(size_t bufsize)
468 : balsa_buffer_(bufsize),
469 content_length_(0),
470 content_length_status_(BalsaHeadersEnums::NO_CONTENT_LENGTH),
471 parsed_response_code_(0),
472 firstline_buffer_base_idx_(0),
473 whitespace_1_idx_(0),
474 non_whitespace_1_idx_(0),
475 whitespace_2_idx_(0),
476 non_whitespace_2_idx_(0),
477 whitespace_3_idx_(0),
478 non_whitespace_3_idx_(0),
479 whitespace_4_idx_(0),
480 transfer_encoding_is_chunked_(false) {}
481
482 // Copying BalsaHeaders is expensive, so require that it be visible.
483 BalsaHeaders(const BalsaHeaders&) = delete;
484 BalsaHeaders& operator=(const BalsaHeaders&) = delete;
485 BalsaHeaders(BalsaHeaders&&) = default;
486 BalsaHeaders& operator=(BalsaHeaders&&) = default;
487
488 // Returns a range that represents all of the header lines.
489 iterator_range<const_header_lines_iterator> lines() const;
490
491 // Returns an iterator range consisting of the header lines matching key.
492 // String backing 'key' must remain valid for lifetime of range.
493 iterator_range<const_header_lines_key_iterator> lines(
494 absl::string_view key) const;
495
496 // Returns a forward-only iterator that only stops at lines matching key.
497 // String backing 'key' must remain valid for lifetime of iterator.
498 //
499 // Check returned iterator against header_lines_key_end() to determine when
500 // iteration is finished.
501 //
502 // Consider calling lines(key)--it may be more readable.
503 const_header_lines_key_iterator GetIteratorForKey(
504 absl::string_view key) const;
505
506 const_header_lines_key_iterator header_lines_key_end() const;
507
508 void erase(const const_header_lines_iterator& it);
509
510 void Clear();
511
512 // Explicit copy functions to avoid risk of accidental copies.
Copy()513 BalsaHeaders Copy() const {
514 BalsaHeaders copy;
515 copy.CopyFrom(*this);
516 return copy;
517 }
518 void CopyFrom(const BalsaHeaders& other);
519
520 // Replaces header entries with key 'key' if they exist, or appends
521 // a new header if none exist. See 'AppendHeader' below for additional
522 // comments about ContentLength and TransferEncoding headers. Note that this
523 // will allocate new storage every time that it is called.
524 void ReplaceOrAppendHeader(absl::string_view key,
525 absl::string_view value) override;
526
527 // Append a new header entry to the header object. Clients who wish to append
528 // Content-Length header should use SetContentLength() method instead of
529 // adding the content length header using AppendHeader (manually adding the
530 // content length header will not update the content_length_ and
531 // content_length_status_ values).
532 // Similarly, clients who wish to add or remove the transfer encoding header
533 // in order to apply or remove chunked encoding should use
534 // SetTransferEncodingToChunkedAndClearContentLength() or
535 // SetNoTransferEncoding() instead.
536 void AppendHeader(absl::string_view key, absl::string_view value) override;
537
538 // Appends ',value' to an existing header named 'key'. If no header with the
539 // correct key exists, it will call AppendHeader(key, value). Calling this
540 // function on a key which exists several times in the headers will produce
541 // unpredictable results.
542 void AppendToHeader(absl::string_view key, absl::string_view value) override;
543
544 // Appends ', value' to an existing header named 'key'. If no header with the
545 // correct key exists, it will call AppendHeader(key, value). Calling this
546 // function on a key which exists several times in the headers will produce
547 // unpredictable results.
548 void AppendToHeaderWithCommaAndSpace(absl::string_view key,
549 absl::string_view value) override;
550
551 // Returns the value corresponding to the given header key. Returns an empty
552 // string if the header key does not exist. For headers that may consist of
553 // multiple lines, use GetAllOfHeader() instead.
554 // Make the QuicheLowerCaseString overload visible,
555 // and only override the absl::string_view one.
556 using HeaderApi::GetHeader;
557 absl::string_view GetHeader(absl::string_view key) const override;
558
559 // Iterates over all currently valid header lines, appending their
560 // values into the vector 'out', in top-to-bottom order.
561 // Header-lines which have been erased are not currently valid, and
562 // will not have their values appended. Empty values will be
563 // represented as empty string. If 'key' doesn't exist in the headers at
564 // all, out will not be changed. We do not clear the vector out
565 // before adding new entries. If there are header lines with matching
566 // key but empty value then they are also added to the vector out.
567 // (Basically empty values are not treated in any special manner).
568 //
569 // Example:
570 // Input header:
571 // "GET / HTTP/1.0\r\n"
572 // "key1: v1\r\n"
573 // "key1: \r\n"
574 // "key1:\r\n"
575 // "key1: v1\r\n"
576 // "key1:v2\r\n"
577 //
578 // vector out is initially: ["foo"]
579 // vector out after GetAllOfHeader("key1", &out) is:
580 // ["foo", "v1", "", "", "v1", "v2"]
581 //
582 // See gfe::header_properties::IsMultivaluedHeader() for which headers
583 // GFE treats as being multivalued.
584
585 // Make the QuicheLowerCaseString overload visible,
586 // and only override the absl::string_view one.
587 using HeaderApi::GetAllOfHeader;
588 void GetAllOfHeader(absl::string_view key,
589 std::vector<absl::string_view>* out) const override;
590
591 // Same as above, but iterates over all header lines including removed ones.
592 // Appends their values into the vector 'out' in top-to-bottom order,
593 // first all valid headers then all that were removed.
594 void GetAllOfHeaderIncludeRemoved(absl::string_view key,
595 std::vector<absl::string_view>* out) const;
596
597 // Joins all values for `key` into a comma-separated string.
598 // Make the QuicheLowerCaseString overload visible,
599 // and only override the absl::string_view one.
600 using HeaderApi::GetAllOfHeaderAsString;
601 std::string GetAllOfHeaderAsString(absl::string_view key) const override;
602
603 // Determine if a given header is present. Case-insensitive.
HasHeader(absl::string_view key)604 inline bool HasHeader(absl::string_view key) const override {
605 return GetConstHeaderLinesIterator(key) != header_lines_.end();
606 }
607
608 // Goes through all headers with key 'key' and checks to see if one of the
609 // values is 'value'. Returns true if there are headers with the desired key
610 // and value, false otherwise. Case-insensitive for the key; case-sensitive
611 // for the value.
HeaderHasValue(absl::string_view key,absl::string_view value)612 bool HeaderHasValue(absl::string_view key,
613 absl::string_view value) const override {
614 return HeaderHasValueHelper(key, value, true);
615 }
616 // Same as above, but also case-insensitive for the value.
HeaderHasValueIgnoreCase(absl::string_view key,absl::string_view value)617 bool HeaderHasValueIgnoreCase(absl::string_view key,
618 absl::string_view value) const override {
619 return HeaderHasValueHelper(key, value, false);
620 }
621
622 // Returns true iff any header 'key' exists with non-empty value.
623 bool HasNonEmptyHeader(absl::string_view key) const override;
624
625 const_header_lines_iterator GetHeaderPosition(absl::string_view key) const;
626
627 // Removes all headers in given set |keys| at once efficiently. Keys
628 // are case insensitive.
629 //
630 // Alternatives considered:
631 //
632 // 1. Use string_hash_set<>, the caller (such as ClearHopByHopHeaders) lower
633 // cases the keys and RemoveAllOfHeaderInList just does lookup. This according
634 // to microbenchmark gives the best performance because it does not require
635 // an extra copy of the hash table. However, it is not taken because of the
636 // possible risk that caller could forget to lowercase the keys.
637 //
638 // 2. Use flat_hash_set<StringPiece, StringPieceCaseHash,StringPieceCaseEqual>
639 // or string_hash_set<StringPieceCaseHash, StringPieceCaseEqual>. Both appear
640 // to have (much) worse performance with WithoutDupToken and LongHeader case
641 // in microbenchmark.
642 void RemoveAllOfHeaderInList(const HeaderTokenList& keys) override;
643
644 void RemoveAllOfHeader(absl::string_view key) override;
645
646 // Removes all headers starting with 'key' [case insensitive]
647 void RemoveAllHeadersWithPrefix(absl::string_view prefix) override;
648
649 // Returns true if we have at least one header with given prefix
650 // [case insensitive]. Currently for test use only.
651 bool HasHeadersWithPrefix(absl::string_view prefix) const override;
652
653 // Returns the key value pairs for all headers where the header key begins
654 // with the specified prefix.
655 void GetAllOfHeaderWithPrefix(
656 absl::string_view prefix,
657 std::vector<std::pair<absl::string_view, absl::string_view>>* out)
658 const override;
659
660 void GetAllHeadersWithLimit(
661 std::vector<std::pair<absl::string_view, absl::string_view>>* out,
662 int limit) const override;
663
664 // Removes all values equal to a given value from header lines with given key.
665 // All string operations done here are case-sensitive.
666 // If a header line has only values matching the given value, the entire
667 // line is removed.
668 // If the given value is found in a multi-value header line mixed with other
669 // values, the line is edited in-place to remove the values.
670 // Returns the number of occurrences of value that were removed.
671 // This method runs in linear time.
672 size_t RemoveValue(absl::string_view key, absl::string_view value);
673
674 // Returns the upper bound on the required buffer space to fully write out
675 // the header object (this include the first line, all header lines, and the
676 // final line separator that marks the ending of the header).
677 size_t GetSizeForWriteBuffer() const override;
678
679 // Indicates if to serialize headers with lower-case header keys.
680 enum class CaseOption { kNoModification, kLowercase, kPropercase };
681
682 // Indicates if to coalesce headers with multiple values to match Envoy/GFE3.
683 enum class CoalesceOption { kNoCoalesce, kCoalesce };
684
685 // The following WriteHeader* methods are template member functions that
686 // place one requirement on the Buffer class: it must implement a Write
687 // method that takes a pointer and a length. The buffer passed in is not
688 // required to be stretchable. For non-stretchable buffers, the user must
689 // call GetSizeForWriteBuffer() to find out the upper bound on the output
690 // buffer space required to make sure that the entire header is serialized.
691 // BalsaHeaders will not check that there is adequate space in the buffer
692 // object during the write.
693
694 // Writes the entire header and the final line separator that marks the end
695 // of the HTTP header section to the buffer. After this method returns, no
696 // more header data should be written to the buffer.
697 template <typename Buffer>
WriteHeaderAndEndingToBuffer(Buffer * buffer,CaseOption case_option,CoalesceOption coalesce_option)698 void WriteHeaderAndEndingToBuffer(Buffer* buffer, CaseOption case_option,
699 CoalesceOption coalesce_option) const {
700 WriteToBuffer(buffer, case_option, coalesce_option);
701 WriteHeaderEndingToBuffer(buffer);
702 }
703
704 template <typename Buffer>
WriteHeaderAndEndingToBuffer(Buffer * buffer)705 void WriteHeaderAndEndingToBuffer(Buffer* buffer) const {
706 WriteHeaderAndEndingToBuffer(buffer, CaseOption::kNoModification,
707 CoalesceOption::kNoCoalesce);
708 }
709
710 // Writes the final line separator to the buffer to terminate the HTTP header
711 // section. After this method returns, no more header data should be written
712 // to the buffer.
713 template <typename Buffer>
WriteHeaderEndingToBuffer(Buffer * buffer)714 static void WriteHeaderEndingToBuffer(Buffer* buffer) {
715 buffer->WriteString("\r\n");
716 }
717
718 // Writes the entire header to the buffer without the line separator that
719 // terminates the HTTP header. This lets users append additional header lines
720 // using WriteHeaderLineToBuffer and then terminate the header with
721 // WriteHeaderEndingToBuffer as the header is serialized to the buffer,
722 // without having to first copy the header.
723 template <typename Buffer>
724 void WriteToBuffer(Buffer* buffer, CaseOption case_option,
725 CoalesceOption coalesce_option) const;
726
727 template <typename Buffer>
WriteToBuffer(Buffer * buffer)728 void WriteToBuffer(Buffer* buffer) const {
729 WriteToBuffer(buffer, CaseOption::kNoModification,
730 CoalesceOption::kNoCoalesce);
731 }
732
733 // Used by WriteToBuffer to coalesce multiple values of headers listed in
734 // |multivalued_headers| into a single comma-separated value. Public for test.
735 template <typename Buffer>
736 void WriteToBufferCoalescingMultivaluedHeaders(
737 Buffer* buffer, const MultivaluedHeadersSet& multivalued_headers,
738 CaseOption case_option) const;
739
740 // Populates |multivalues| with values of |header_lines_| with keys present
741 // in |multivalued_headers| set.
742 void GetValuesOfMultivaluedHeaders(
743 const MultivaluedHeadersSet& multivalued_headers,
744 MultivaluedHeadersValuesMap* multivalues) const;
745
ToPropercase(absl::string_view header)746 static std::string ToPropercase(absl::string_view header) {
747 std::string copy = std::string(header);
748 bool should_uppercase = true;
749 for (char& c : copy) {
750 if (!absl::ascii_isalnum(c)) {
751 should_uppercase = true;
752 } else if (should_uppercase) {
753 c = absl::ascii_toupper(c);
754 should_uppercase = false;
755 } else {
756 c = absl::ascii_tolower(c);
757 }
758 }
759 return copy;
760 }
761
762 template <typename Buffer>
WriteHeaderKeyToBuffer(Buffer * buffer,absl::string_view key,CaseOption case_option)763 void WriteHeaderKeyToBuffer(Buffer* buffer, absl::string_view key,
764 CaseOption case_option) const {
765 if (case_option == CaseOption::kLowercase) {
766 buffer->WriteString(absl::AsciiStrToLower(key));
767 } else if (case_option == CaseOption::kPropercase) {
768 const auto& header_set = quiche::GetStandardHeaderSet();
769 auto it = header_set.find(key);
770 if (it != header_set.end()) {
771 buffer->WriteString(*it);
772 } else {
773 buffer->WriteString(ToPropercase(key));
774 }
775 } else {
776 buffer->WriteString(key);
777 }
778 }
779
780 // Takes a header line in the form of a key/value pair and append it to the
781 // buffer. This function should be called after WriteToBuffer to
782 // append additional header lines to the header without copying the header.
783 // When the user is done with appending to the buffer,
784 // WriteHeaderEndingToBuffer must be used to terminate the HTTP
785 // header in the buffer. This method is a no-op if key is empty.
786 template <typename Buffer>
WriteHeaderLineToBuffer(Buffer * buffer,absl::string_view key,absl::string_view value,CaseOption case_option)787 void WriteHeaderLineToBuffer(Buffer* buffer, absl::string_view key,
788 absl::string_view value,
789 CaseOption case_option) const {
790 // If the key is empty, we don't want to write the rest because it
791 // will not be a well-formed header line.
792 if (!key.empty()) {
793 WriteHeaderKeyToBuffer(buffer, key, case_option);
794 buffer->WriteString(": ");
795 buffer->WriteString(value);
796 buffer->WriteString("\r\n");
797 }
798 }
799
800 // Takes a header line in the form of a key and vector of values and appends
801 // it to the buffer. This function should be called after WriteToBuffer to
802 // append additional header lines to the header without copying the header.
803 // When the user is done with appending to the buffer,
804 // WriteHeaderEndingToBuffer must be used to terminate the HTTP
805 // header in the buffer. This method is a no-op if the |key| is empty.
806 template <typename Buffer>
WriteHeaderLineValuesToBuffer(Buffer * buffer,absl::string_view key,const std::vector<absl::string_view> & values,CaseOption case_option)807 void WriteHeaderLineValuesToBuffer(
808 Buffer* buffer, absl::string_view key,
809 const std::vector<absl::string_view>& values,
810 CaseOption case_option) const {
811 // If the key is empty, we don't want to write the rest because it
812 // will not be a well-formed header line.
813 if (!key.empty()) {
814 WriteHeaderKeyToBuffer(buffer, key, case_option);
815 buffer->WriteString(": ");
816 for (auto it = values.begin();;) {
817 buffer->WriteString(*it);
818 if (++it == values.end()) {
819 break;
820 }
821 buffer->WriteString(",");
822 }
823 buffer->WriteString("\r\n");
824 }
825 }
826
827 // Dump the textural representation of the header object to a string, which
828 // is suitable for writing out to logs. All CRLF will be printed out as \n.
829 // This function can be called on a header object in any state. Raw header
830 // data will be printed out if the header object is not completely parsed,
831 // e.g., when there was an error in the middle of parsing.
832 // The header content is appended to the string; the original content is not
833 // cleared.
834 // If used in test cases, WillNotWriteFromFramer() may be of interest.
835 void DumpToString(std::string* str) const;
836 std::string DebugString() const override;
837
838 bool ForEachHeader(
839 quiche::UnretainedCallback<bool(const absl::string_view key,
840 const absl::string_view value)>
841 fn) const override;
842
843 void DumpToPrefixedString(const char* spaces, std::string* str) const;
844
first_line()845 absl::string_view first_line() const {
846 QUICHE_DCHECK_GE(whitespace_4_idx_, non_whitespace_1_idx_);
847 return whitespace_4_idx_ == non_whitespace_1_idx_
848 ? ""
849 : absl::string_view(
850 BeginningOfFirstLine() + non_whitespace_1_idx_,
851 whitespace_4_idx_ - non_whitespace_1_idx_);
852 }
first_line_of_request()853 std::string first_line_of_request() const override {
854 return std::string(first_line());
855 }
856
857 // Returns the parsed value of the response code if it has been parsed.
858 // Guaranteed to return 0 when unparsed (though it is a much better idea to
859 // verify that the BalsaFrame had no errors while parsing).
860 // This may return response codes which are outside the normal bounds of
861 // HTTP response codes-- it is up to the user of this class to ensure that
862 // the response code is one which is interpretable.
parsed_response_code()863 size_t parsed_response_code() const override { return parsed_response_code_; }
864
request_method()865 absl::string_view request_method() const override {
866 QUICHE_DCHECK_GE(whitespace_2_idx_, non_whitespace_1_idx_);
867 return whitespace_2_idx_ == non_whitespace_1_idx_
868 ? ""
869 : absl::string_view(
870 BeginningOfFirstLine() + non_whitespace_1_idx_,
871 whitespace_2_idx_ - non_whitespace_1_idx_);
872 }
873
response_version()874 absl::string_view response_version() const override {
875 // Note: There is no difference between request_method() and
876 // response_version(). They both could be called
877 // GetFirstTokenFromFirstline()... but that wouldn't be anywhere near as
878 // descriptive.
879 return request_method();
880 }
881
request_uri()882 absl::string_view request_uri() const override {
883 QUICHE_DCHECK_GE(whitespace_3_idx_, non_whitespace_2_idx_);
884 return whitespace_3_idx_ == non_whitespace_2_idx_
885 ? ""
886 : absl::string_view(
887 BeginningOfFirstLine() + non_whitespace_2_idx_,
888 whitespace_3_idx_ - non_whitespace_2_idx_);
889 }
890
response_code()891 absl::string_view response_code() const override {
892 // Note: There is no difference between request_uri() and response_code().
893 // They both could be called GetSecondtTokenFromFirstline(), but, as noted
894 // in an earlier comment, that wouldn't be as descriptive.
895 return request_uri();
896 }
897
request_version()898 absl::string_view request_version() const override {
899 QUICHE_DCHECK_GE(whitespace_4_idx_, non_whitespace_3_idx_);
900 return whitespace_4_idx_ == non_whitespace_3_idx_
901 ? ""
902 : absl::string_view(
903 BeginningOfFirstLine() + non_whitespace_3_idx_,
904 whitespace_4_idx_ - non_whitespace_3_idx_);
905 }
906
response_reason_phrase()907 absl::string_view response_reason_phrase() const override {
908 // Note: There is no difference between request_version() and
909 // response_reason_phrase(). They both could be called
910 // GetThirdTokenFromFirstline(), but, as noted in an earlier comment, that
911 // wouldn't be as descriptive.
912 return request_version();
913 }
914
SetRequestFirstlineFromStringPieces(absl::string_view method,absl::string_view uri,absl::string_view version)915 void SetRequestFirstlineFromStringPieces(absl::string_view method,
916 absl::string_view uri,
917 absl::string_view version) {
918 SetFirstlineFromStringPieces(method, uri, version);
919 }
920
921 void SetResponseFirstline(absl::string_view version,
922 size_t parsed_response_code,
923 absl::string_view reason_phrase);
924
925 // These functions are exactly the same, except that their names are
926 // different. This is done so that the code using this class is more
927 // expressive.
928 void SetRequestMethod(absl::string_view method) override;
929 void SetResponseVersion(absl::string_view version) override;
930
931 void SetRequestUri(absl::string_view uri) override;
932 void SetResponseCode(absl::string_view code) override;
set_parsed_response_code(size_t parsed_response_code)933 void set_parsed_response_code(size_t parsed_response_code) {
934 parsed_response_code_ = parsed_response_code;
935 }
936 void SetParsedResponseCodeAndUpdateFirstline(
937 size_t parsed_response_code) override;
938
939 // These functions are exactly the same, except that their names are
940 // different. This is done so that the code using this class is more
941 // expressive.
942 void SetRequestVersion(absl::string_view version) override;
943 void SetResponseReasonPhrase(absl::string_view reason_phrase) override;
944
945 // Simple accessors to some of the internal state
transfer_encoding_is_chunked()946 bool transfer_encoding_is_chunked() const {
947 return transfer_encoding_is_chunked_;
948 }
949
ResponseCodeImpliesNoBody(size_t code)950 static bool ResponseCodeImpliesNoBody(size_t code) {
951 // From HTTP spec section 6.1.1 all 1xx responses must not have a body,
952 // as well as 204 No Content and 304 Not Modified.
953 return ((code >= 100) && (code <= 199)) || (code == 204) || (code == 304);
954 }
955
956 // Note: never check this for requests. Nothing bad will happen if you do,
957 // but spec does not allow requests framed by connection close.
958 // TODO(vitaliyl): refactor.
is_framed_by_connection_close()959 bool is_framed_by_connection_close() const {
960 // We declare that response is framed by connection close if it has no
961 // content-length, no transfer encoding, and is allowed to have a body by
962 // the HTTP spec.
963 // parsed_response_code_ is 0 for requests, so ResponseCodeImpliesNoBody
964 // will return false.
965 return (content_length_status_ == BalsaHeadersEnums::NO_CONTENT_LENGTH) &&
966 !transfer_encoding_is_chunked_ &&
967 !ResponseCodeImpliesNoBody(parsed_response_code_);
968 }
969
content_length()970 size_t content_length() const override { return content_length_; }
content_length_status()971 BalsaHeadersEnums::ContentLengthStatus content_length_status() const {
972 return content_length_status_;
973 }
content_length_valid()974 bool content_length_valid() const override {
975 return content_length_status_ == BalsaHeadersEnums::VALID_CONTENT_LENGTH;
976 }
977
978 // SetContentLength, SetTransferEncodingToChunkedAndClearContentLength, and
979 // SetNoTransferEncoding modifies the header object to use
980 // content-length and transfer-encoding headers in a consistent
981 // manner. They set all internal flags and status so client can get
982 // a consistent view from various accessors.
983 void SetContentLength(size_t length) override;
984 // Sets transfer-encoding to chunked and updates internal state.
985 void SetTransferEncodingToChunkedAndClearContentLength() override;
986 // Removes transfer-encoding headers and updates internal state.
987 void SetNoTransferEncoding() override;
988
989 // If you have a response that needs framing by connection close, use this
990 // method instead of RemoveAllOfHeader("Content-Length"). Has no effect if
991 // transfer_encoding_is_chunked().
992 void ClearContentLength();
993
994 // This should be called if balsa headers are created entirely manually (not
995 // by any of the framer classes) to make sure that function calls like
996 // DumpToString will work correctly.
WillNotWriteFromFramer()997 void WillNotWriteFromFramer() {
998 balsa_buffer_.NoMoreWriteToContiguousBuffer();
999 }
1000
1001 // True if DoneWritingFromFramer or WillNotWriteFromFramer is called.
FramerIsDoneWriting()1002 bool FramerIsDoneWriting() const {
1003 return !balsa_buffer_.can_write_to_contiguous_buffer();
1004 }
1005
1006 bool IsEmpty() const override;
1007
1008 // From HeaderApi and ConstHeaderApi.
1009 absl::string_view Authority() const override;
1010 void ReplaceOrAppendAuthority(absl::string_view value) override;
1011 void RemoveAuthority() override;
1012 void ApplyToCookie(quiche::UnretainedCallback<void(absl::string_view cookie)>
1013 f) const override;
1014
set_enforce_header_policy(bool enforce)1015 void set_enforce_header_policy(bool enforce) override {
1016 enforce_header_policy_ = enforce;
1017 }
1018
1019 // Removes the last token from the header value. In the presence of multiple
1020 // header lines with given key, will remove the last token of the last line.
1021 // Can be useful if the last encoding has to be removed.
1022 void RemoveLastTokenFromHeaderValue(absl::string_view key);
1023
1024 // Gets the list of names of headers that are multivalued in Envoy.
1025 static const MultivaluedHeadersSet& multivalued_envoy_headers();
1026
1027 // Returns true if HTTP responses with this response code have bodies.
1028 static bool ResponseCanHaveBody(int response_code);
1029
1030 // Given a pointer to the beginning and the end of the header value
1031 // in some buffer, populates tokens list with beginning and end indices
1032 // of all tokens present in the value string.
1033 static void ParseTokenList(absl::string_view header_value,
1034 HeaderTokenList* tokens);
1035
1036 private:
1037 typedef std::vector<HeaderLineDescription> HeaderLines;
1038
1039 class iterator_base;
1040
1041 friend class BalsaFrame;
1042 friend class gfe2::Http2HeaderValidator;
1043 friend class SpdyPayloadFramer;
1044 friend class HTTPMessage;
1045 friend class test::BalsaHeadersTestPeer;
1046
1047 friend bool ParseHTTPFirstLine(const char* begin, const char* end,
1048 bool is_request, BalsaHeaders* headers,
1049 BalsaFrameEnums::ErrorCode* error_code);
1050
1051 // Reverse iterators have been removed for lack of use, refer to
1052 // cl/30618773 in case they are needed.
1053
BeginningOfFirstLine()1054 const char* BeginningOfFirstLine() const {
1055 return GetPtr(firstline_buffer_base_idx_);
1056 }
1057
BeginningOfFirstLine()1058 char* BeginningOfFirstLine() { return GetPtr(firstline_buffer_base_idx_); }
1059
GetPtr(BalsaBuffer::Blocks::size_type block_idx)1060 char* GetPtr(BalsaBuffer::Blocks::size_type block_idx) {
1061 return balsa_buffer_.GetPtr(block_idx);
1062 }
1063
GetPtr(BalsaBuffer::Blocks::size_type block_idx)1064 const char* GetPtr(BalsaBuffer::Blocks::size_type block_idx) const {
1065 return balsa_buffer_.GetPtr(block_idx);
1066 }
1067
WriteFromFramer(const char * ptr,size_t size)1068 void WriteFromFramer(const char* ptr, size_t size) {
1069 balsa_buffer_.WriteToContiguousBuffer(absl::string_view(ptr, size));
1070 }
1071
DoneWritingFromFramer()1072 void DoneWritingFromFramer() {
1073 balsa_buffer_.NoMoreWriteToContiguousBuffer();
1074 }
1075
OriginalHeaderStreamBegin()1076 const char* OriginalHeaderStreamBegin() const {
1077 return balsa_buffer_.StartOfFirstBlock();
1078 }
1079
OriginalHeaderStreamEnd()1080 const char* OriginalHeaderStreamEnd() const {
1081 return balsa_buffer_.EndOfFirstBlock();
1082 }
1083
GetReadableBytesFromHeaderStream()1084 size_t GetReadableBytesFromHeaderStream() const {
1085 return balsa_buffer_.GetReadableBytesOfFirstBlock();
1086 }
1087
GetReadablePtrFromHeaderStream()1088 absl::string_view GetReadablePtrFromHeaderStream() {
1089 return {OriginalHeaderStreamBegin(), GetReadableBytesFromHeaderStream()};
1090 }
1091
1092 absl::string_view GetValueFromHeaderLineDescription(
1093 const HeaderLineDescription& line) const;
1094
1095 void AddAndMakeDescription(absl::string_view key, absl::string_view value,
1096 HeaderLineDescription* d);
1097
1098 void AppendAndMakeDescription(absl::string_view key, absl::string_view value,
1099 HeaderLineDescription* d);
1100
1101 // Removes all header lines with the given key starting at start.
1102 void RemoveAllOfHeaderStartingAt(absl::string_view key,
1103 HeaderLines::iterator start);
1104
1105 HeaderLines::const_iterator GetConstHeaderLinesIterator(
1106 absl::string_view key) const;
1107
1108 HeaderLines::iterator GetHeaderLinesIterator(absl::string_view key,
1109 HeaderLines::iterator start);
1110
1111 HeaderLines::iterator GetHeaderLinesIteratorForLastMultivaluedHeader(
1112 absl::string_view key);
1113
1114 template <typename IteratorType>
1115 const IteratorType HeaderLinesBeginHelper() const;
1116
1117 template <typename IteratorType>
1118 const IteratorType HeaderLinesEndHelper() const;
1119
1120 // Helper function for HeaderHasValue and HeaderHasValueIgnoreCase that
1121 // does most of the work.
1122 bool HeaderHasValueHelper(absl::string_view key, absl::string_view value,
1123 bool case_sensitive) const;
1124
1125 // Called by header removal methods to reset internal values for transfer
1126 // encoding or content length if we're removing the corresponding headers.
1127 void MaybeClearSpecialHeaderValues(absl::string_view key);
1128
1129 void SetFirstlineFromStringPieces(absl::string_view firstline_a,
1130 absl::string_view firstline_b,
1131 absl::string_view firstline_c);
1132 BalsaBuffer balsa_buffer_;
1133
1134 size_t content_length_;
1135 BalsaHeadersEnums::ContentLengthStatus content_length_status_;
1136 size_t parsed_response_code_;
1137 // HTTP firstlines all have the following structure:
1138 // LWS NONWS LWS NONWS LWS NONWS NOTCRLF CRLF
1139 // [\t \r\n]+ [^\t ]+ [\t ]+ [^\t ]+ [\t ]+ [^\t ]+ [^\r\n]+ "\r\n"
1140 // ws1 nws1 ws2 nws2 ws3 nws3 ws4
1141 // | [-------) [-------) [----------------)
1142 // REQ: method request_uri version
1143 // RESP: version statuscode reason
1144 //
1145 // The first NONWS->LWS component we'll call firstline_a.
1146 // The second firstline_b, and the third firstline_c.
1147 //
1148 // firstline_a goes from nws1 to (but not including) ws2
1149 // firstline_b goes from nws2 to (but not including) ws3
1150 // firstline_c goes from nws3 to (but not including) ws4
1151 //
1152 // In the code:
1153 // ws1 == whitespace_1_idx_
1154 // nws1 == non_whitespace_1_idx_
1155 // ws2 == whitespace_2_idx_
1156 // nws2 == non_whitespace_2_idx_
1157 // ws3 == whitespace_3_idx_
1158 // nws3 == non_whitespace_3_idx_
1159 // ws4 == whitespace_4_idx_
1160 BalsaBuffer::Blocks::size_type firstline_buffer_base_idx_;
1161 size_t whitespace_1_idx_;
1162 size_t non_whitespace_1_idx_;
1163 size_t whitespace_2_idx_;
1164 size_t non_whitespace_2_idx_;
1165 size_t whitespace_3_idx_;
1166 size_t non_whitespace_3_idx_;
1167 size_t whitespace_4_idx_;
1168
1169 bool transfer_encoding_is_chunked_;
1170
1171 // If true, QUICHE_BUG if a header that starts with an invalid prefix is
1172 // explicitly set.
1173 bool enforce_header_policy_ = true;
1174
1175 HeaderLines header_lines_;
1176 };
1177
1178 // Base class for iterating the headers in a BalsaHeaders object, returning a
1179 // pair of string_view's for each header.
1180 class QUICHE_EXPORT BalsaHeaders::iterator_base
1181 : public std::iterator<std::forward_iterator_tag,
1182 std::pair<absl::string_view, absl::string_view>> {
1183 public:
iterator_base()1184 iterator_base() : headers_(nullptr), idx_(0) {}
1185
1186 std::pair<absl::string_view, absl::string_view>& operator*() const {
1187 return Lookup(idx_);
1188 }
1189
1190 std::pair<absl::string_view, absl::string_view>* operator->() const {
1191 return &(this->operator*());
1192 }
1193
1194 bool operator==(const BalsaHeaders::iterator_base& it) const {
1195 return idx_ == it.idx_;
1196 }
1197
1198 bool operator<(const BalsaHeaders::iterator_base& it) const {
1199 return idx_ < it.idx_;
1200 }
1201
1202 bool operator<=(const BalsaHeaders::iterator_base& it) const {
1203 return idx_ <= it.idx_;
1204 }
1205
1206 bool operator!=(const BalsaHeaders::iterator_base& it) const {
1207 return !(*this == it);
1208 }
1209
1210 bool operator>(const BalsaHeaders::iterator_base& it) const {
1211 return it < *this;
1212 }
1213
1214 bool operator>=(const BalsaHeaders::iterator_base& it) const {
1215 return it <= *this;
1216 }
1217
1218 // This mainly exists so that we can have interesting output for
1219 // unittesting. The EXPECT_EQ, EXPECT_NE functions require that
1220 // operator<< work for the classes it sees. It would be better if there
1221 // was an additional traits-like system for the gUnit output... but oh
1222 // well.
1223 friend QUICHE_EXPORT std::ostream& operator<<(std::ostream& os,
1224 const iterator_base& it) {
1225 os << "[" << it.headers_ << ", " << it.idx_ << "]";
1226 return os;
1227 }
1228
1229 private:
1230 friend class BalsaHeaders;
1231
iterator_base(const BalsaHeaders * headers,HeaderLines::size_type index)1232 iterator_base(const BalsaHeaders* headers, HeaderLines::size_type index)
1233 : headers_(headers), idx_(index) {}
1234
increment()1235 void increment() {
1236 value_.reset();
1237 const HeaderLines& header_lines = headers_->header_lines_;
1238 const HeaderLines::size_type header_lines_size = header_lines.size();
1239 const HeaderLines::size_type original_idx = idx_;
1240 do {
1241 ++idx_;
1242 } while (idx_ < header_lines_size && header_lines[idx_].skip == true);
1243 // The condition below exists so that ++(end() - 1) == end(), even
1244 // if there are only 'skip == true' elements between the end() iterator
1245 // and the end of the vector of HeaderLineDescriptions.
1246 if (idx_ == header_lines_size) {
1247 idx_ = original_idx + 1;
1248 }
1249 }
1250
Lookup(HeaderLines::size_type index)1251 std::pair<absl::string_view, absl::string_view>& Lookup(
1252 HeaderLines::size_type index) const {
1253 QUICHE_DCHECK_LT(index, headers_->header_lines_.size());
1254 if (!value_.has_value()) {
1255 const HeaderLineDescription& line = headers_->header_lines_[index];
1256 const char* stream_begin = headers_->GetPtr(line.buffer_base_idx);
1257 value_ =
1258 std::make_pair(absl::string_view(stream_begin + line.first_char_idx,
1259 line.KeyLength()),
1260 absl::string_view(stream_begin + line.value_begin_idx,
1261 line.ValuesLength()));
1262 }
1263 return *value_;
1264 }
1265
1266 const BalsaHeaders* headers_;
1267 HeaderLines::size_type idx_;
1268 mutable std::optional<std::pair<absl::string_view, absl::string_view>> value_;
1269 };
1270
1271 // A const iterator for all the header lines.
1272 class QUICHE_EXPORT BalsaHeaders::const_header_lines_iterator
1273 : public BalsaHeaders::iterator_base {
1274 public:
const_header_lines_iterator()1275 const_header_lines_iterator() : iterator_base() {}
1276
1277 const_header_lines_iterator& operator++() {
1278 iterator_base::increment();
1279 return *this;
1280 }
1281
1282 private:
1283 friend class BalsaHeaders;
1284
const_header_lines_iterator(const BalsaHeaders * headers,HeaderLines::size_type index)1285 const_header_lines_iterator(const BalsaHeaders* headers,
1286 HeaderLines::size_type index)
1287 : iterator_base(headers, index) {}
1288 };
1289
1290 // A const iterator that stops only on header lines for a particular key.
1291 class QUICHE_EXPORT BalsaHeaders::const_header_lines_key_iterator
1292 : public BalsaHeaders::iterator_base {
1293 public:
1294 const_header_lines_key_iterator& operator++() {
1295 do {
1296 iterator_base::increment();
1297 } while (!AtEnd() && !absl::EqualsIgnoreCase(key_, (**this).first));
1298 return *this;
1299 }
1300
1301 // Only forward-iteration makes sense, so no operator-- defined.
1302
1303 private:
1304 friend class BalsaHeaders;
1305
const_header_lines_key_iterator(const BalsaHeaders * headers,HeaderLines::size_type index,absl::string_view key)1306 const_header_lines_key_iterator(const BalsaHeaders* headers,
1307 HeaderLines::size_type index,
1308 absl::string_view key)
1309 : iterator_base(headers, index), key_(key) {}
1310
1311 // Should only be used for creating an end iterator.
const_header_lines_key_iterator(const BalsaHeaders * headers,HeaderLines::size_type index)1312 const_header_lines_key_iterator(const BalsaHeaders* headers,
1313 HeaderLines::size_type index)
1314 : iterator_base(headers, index) {}
1315
AtEnd()1316 bool AtEnd() const { return *this >= headers_->lines().end(); }
1317
1318 absl::string_view key_;
1319 };
1320
1321 inline BalsaHeaders::iterator_range<BalsaHeaders::const_header_lines_iterator>
lines()1322 BalsaHeaders::lines() const {
1323 return {HeaderLinesBeginHelper<const_header_lines_iterator>(),
1324 HeaderLinesEndHelper<const_header_lines_iterator>()};
1325 }
1326
1327 inline BalsaHeaders::iterator_range<
1328 BalsaHeaders::const_header_lines_key_iterator>
lines(absl::string_view key)1329 BalsaHeaders::lines(absl::string_view key) const {
1330 return {GetIteratorForKey(key), header_lines_key_end()};
1331 }
1332
1333 inline BalsaHeaders::const_header_lines_key_iterator
header_lines_key_end()1334 BalsaHeaders::header_lines_key_end() const {
1335 return HeaderLinesEndHelper<const_header_lines_key_iterator>();
1336 }
1337
erase(const const_header_lines_iterator & it)1338 inline void BalsaHeaders::erase(const const_header_lines_iterator& it) {
1339 QUICHE_DCHECK_EQ(it.headers_, this);
1340 QUICHE_DCHECK_LT(it.idx_, header_lines_.size());
1341 header_lines_[it.idx_].skip = true;
1342 }
1343
1344 template <typename Buffer>
WriteToBuffer(Buffer * buffer,CaseOption case_option,CoalesceOption coalesce_option)1345 void BalsaHeaders::WriteToBuffer(Buffer* buffer, CaseOption case_option,
1346 CoalesceOption coalesce_option) const {
1347 // write the first line.
1348 const absl::string_view firstline = first_line();
1349 if (!firstline.empty()) {
1350 buffer->WriteString(firstline);
1351 }
1352 buffer->WriteString("\r\n");
1353 if (coalesce_option != CoalesceOption::kCoalesce) {
1354 const HeaderLines::size_type end = header_lines_.size();
1355 for (HeaderLines::size_type i = 0; i < end; ++i) {
1356 const HeaderLineDescription& line = header_lines_[i];
1357 if (line.skip) {
1358 continue;
1359 }
1360 const char* line_ptr = GetPtr(line.buffer_base_idx);
1361 WriteHeaderLineToBuffer(
1362 buffer,
1363 absl::string_view(line_ptr + line.first_char_idx, line.KeyLength()),
1364 absl::string_view(line_ptr + line.value_begin_idx,
1365 line.ValuesLength()),
1366 case_option);
1367 }
1368 } else {
1369 WriteToBufferCoalescingMultivaluedHeaders(
1370 buffer, multivalued_envoy_headers(), case_option);
1371 }
1372 }
1373
GetValuesOfMultivaluedHeaders(const MultivaluedHeadersSet & multivalued_headers,MultivaluedHeadersValuesMap * multivalues)1374 inline void BalsaHeaders::GetValuesOfMultivaluedHeaders(
1375 const MultivaluedHeadersSet& multivalued_headers,
1376 MultivaluedHeadersValuesMap* multivalues) const {
1377 multivalues->reserve(header_lines_.capacity());
1378
1379 // Find lines that need to be coalesced and store them in |multivalues|.
1380 for (const auto& line : header_lines_) {
1381 if (line.skip) {
1382 continue;
1383 }
1384 const char* line_ptr = GetPtr(line.buffer_base_idx);
1385 absl::string_view header_key =
1386 absl::string_view(line_ptr + line.first_char_idx, line.KeyLength());
1387 // If this is multivalued header, it may need to be coalesced.
1388 if (multivalued_headers.contains(header_key)) {
1389 absl::string_view header_value = absl::string_view(
1390 line_ptr + line.value_begin_idx, line.ValuesLength());
1391 // Add |header_value| to the vector of values for this |header_key|,
1392 // therefore preserving the order of values for the same key.
1393 (*multivalues)[header_key].push_back(header_value);
1394 }
1395 }
1396 }
1397
1398 template <typename Buffer>
WriteToBufferCoalescingMultivaluedHeaders(Buffer * buffer,const MultivaluedHeadersSet & multivalued_headers,CaseOption case_option)1399 void BalsaHeaders::WriteToBufferCoalescingMultivaluedHeaders(
1400 Buffer* buffer, const MultivaluedHeadersSet& multivalued_headers,
1401 CaseOption case_option) const {
1402 MultivaluedHeadersValuesMap multivalues;
1403 GetValuesOfMultivaluedHeaders(multivalued_headers, &multivalues);
1404
1405 // Write out header lines while coalescing those that need to be coalesced.
1406 for (const auto& line : header_lines_) {
1407 if (line.skip) {
1408 continue;
1409 }
1410 const char* line_ptr = GetPtr(line.buffer_base_idx);
1411 absl::string_view header_key =
1412 absl::string_view(line_ptr + line.first_char_idx, line.KeyLength());
1413 auto header_multivalue = multivalues.find(header_key);
1414 // If current line doesn't need to be coalesced (as it is either not
1415 // multivalue, or has just a single value so it equals to current line),
1416 // then just write it out.
1417 if (header_multivalue == multivalues.end() ||
1418 header_multivalue->second.size() == 1) {
1419 WriteHeaderLineToBuffer(buffer, header_key,
1420 absl::string_view(line_ptr + line.value_begin_idx,
1421 line.ValuesLength()),
1422 case_option);
1423 } else {
1424 // If this line needs to be coalesced, then write all its values and clear
1425 // them, so the subsequent same header keys will not be written.
1426 if (!header_multivalue->second.empty()) {
1427 WriteHeaderLineValuesToBuffer(buffer, header_key,
1428 header_multivalue->second, case_option);
1429 // Clear the multivalue list as it is already written out, so subsequent
1430 // same header keys will not be written.
1431 header_multivalue->second.clear();
1432 }
1433 }
1434 }
1435 }
1436
1437 template <typename IteratorType>
HeaderLinesBeginHelper()1438 const IteratorType BalsaHeaders::HeaderLinesBeginHelper() const {
1439 if (header_lines_.empty()) {
1440 return IteratorType(this, 0);
1441 }
1442 const HeaderLines::size_type header_lines_size = header_lines_.size();
1443 for (HeaderLines::size_type i = 0; i < header_lines_size; ++i) {
1444 if (header_lines_[i].skip == false) {
1445 return IteratorType(this, i);
1446 }
1447 }
1448 return IteratorType(this, 0);
1449 }
1450
1451 template <typename IteratorType>
HeaderLinesEndHelper()1452 const IteratorType BalsaHeaders::HeaderLinesEndHelper() const {
1453 if (header_lines_.empty()) {
1454 return IteratorType(this, 0);
1455 }
1456 const HeaderLines::size_type header_lines_size = header_lines_.size();
1457 HeaderLines::size_type i = header_lines_size;
1458 do {
1459 --i;
1460 if (header_lines_[i].skip == false) {
1461 return IteratorType(this, i + 1);
1462 }
1463 } while (i != 0);
1464 return IteratorType(this, 0);
1465 }
1466
1467 } // namespace quiche
1468
1469 #endif // QUICHE_BALSA_BALSA_HEADERS_H_
1470