xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/spdy/core/hpack/hpack_encoder.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 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_HPACK_HPACK_ENCODER_H_
6 #define QUICHE_SPDY_CORE_HPACK_HPACK_ENCODER_H_
7 
8 #include <stddef.h>
9 
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include "absl/strings/string_view.h"
16 #include "quiche/common/platform/api/quiche_export.h"
17 #include "quiche/common/quiche_callbacks.h"
18 #include "quiche/spdy/core/hpack/hpack_header_table.h"
19 #include "quiche/spdy/core/hpack/hpack_output_stream.h"
20 #include "quiche/spdy/core/http2_header_block.h"
21 
22 // An HpackEncoder encodes header sets as outlined in
23 // http://tools.ietf.org/html/rfc7541.
24 
25 namespace spdy {
26 
27 namespace test {
28 class HpackEncoderPeer;
29 }  // namespace test
30 
31 class QUICHE_EXPORT HpackEncoder {
32  public:
33   using Representation = std::pair<absl::string_view, absl::string_view>;
34   using Representations = std::vector<Representation>;
35 
36   // Callers may provide a HeaderListener to be informed of header name-value
37   // pairs processed by this encoder.
38   using HeaderListener =
39       quiche::MultiUseCallback<void(absl::string_view, absl::string_view)>;
40 
41   // An indexing policy should return true if the provided header name-value
42   // pair should be inserted into the HPACK dynamic table.
43   using IndexingPolicy =
44       quiche::MultiUseCallback<bool(absl::string_view, absl::string_view)>;
45 
46   HpackEncoder();
47   HpackEncoder(const HpackEncoder&) = delete;
48   HpackEncoder& operator=(const HpackEncoder&) = delete;
49   ~HpackEncoder();
50 
51   // Encodes and returns the given header set as a string.
52   std::string EncodeHeaderBlock(const Http2HeaderBlock& header_set);
53 
54   class QUICHE_EXPORT ProgressiveEncoder {
55    public:
~ProgressiveEncoder()56     virtual ~ProgressiveEncoder() {}
57 
58     // Returns true iff more remains to encode.
59     virtual bool HasNext() const = 0;
60 
61     // Encodes and returns up to max_encoded_bytes of the current header block.
62     virtual std::string Next(size_t max_encoded_bytes) = 0;
63   };
64 
65   // Returns a ProgressiveEncoder which must be outlived by both the given
66   // Http2HeaderBlock and this object.
67   std::unique_ptr<ProgressiveEncoder> EncodeHeaderSet(
68       const Http2HeaderBlock& header_set);
69   // Returns a ProgressiveEncoder which must be outlived by this HpackEncoder.
70   // The encoder will not attempt to split any \0-delimited values in
71   // |representations|. If such splitting is desired, it must be performed by
72   // the caller when constructing the list of representations.
73   std::unique_ptr<ProgressiveEncoder> EncodeRepresentations(
74       const Representations& representations);
75 
76   // Called upon a change to SETTINGS_HEADER_TABLE_SIZE. Specifically, this
77   // is to be called after receiving (and sending an acknowledgement for) a
78   // SETTINGS_HEADER_TABLE_SIZE update from the remote decoding endpoint.
79   void ApplyHeaderTableSizeSetting(size_t size_setting);
80 
81   // TODO(birenroy): Rename this GetDynamicTableCapacity().
CurrentHeaderTableSizeSetting()82   size_t CurrentHeaderTableSizeSetting() const {
83     return header_table_.settings_size_bound();
84   }
85 
86   // This HpackEncoder will use |policy| to determine whether to insert header
87   // name-value pairs into the dynamic table.
SetIndexingPolicy(IndexingPolicy policy)88   void SetIndexingPolicy(IndexingPolicy policy) {
89     should_index_ = std::move(policy);
90   }
91 
92   // |listener| will be invoked for each header name-value pair processed by
93   // this encoder.
SetHeaderListener(HeaderListener listener)94   void SetHeaderListener(HeaderListener listener) {
95     listener_ = std::move(listener);
96   }
97 
DisableCompression()98   void DisableCompression() { enable_compression_ = false; }
99 
100   // Disables the deconstruction of Cookie header values into individual
101   // components, as described in
102   // https://httpwg.org/specs/rfc9113.html#CompressCookie. The deconstructed
103   // representation can cause problems for some HTTP/2 endpoints.
DisableCookieCrumbling()104   void DisableCookieCrumbling() { crumble_cookies_ = false; }
105 
106   // Returns the current dynamic table size, including the 32 bytes per entry
107   // overhead mentioned in RFC 7541 section 4.1.
GetDynamicTableSize()108   size_t GetDynamicTableSize() const { return header_table_.size(); }
109 
110  private:
111   friend class test::HpackEncoderPeer;
112 
113   class RepresentationIterator;
114   class Encoderator;
115 
116   // Encodes a sequence of header name-value pairs as a single header block.
117   std::string EncodeRepresentations(RepresentationIterator* iter);
118 
119   // Emits a static/dynamic indexed representation (Section 7.1).
120   void EmitIndex(size_t index);
121 
122   // Emits a literal representation (Section 7.2).
123   void EmitIndexedLiteral(const Representation& representation);
124   void EmitNonIndexedLiteral(const Representation& representation,
125                              bool enable_compression);
126   void EmitLiteral(const Representation& representation);
127 
128   // Emits a Huffman or identity string (whichever is smaller).
129   void EmitString(absl::string_view str);
130 
131   // Emits the current dynamic table size if the table size was recently
132   // updated and we have not yet emitted it (Section 6.3).
133   void MaybeEmitTableSize();
134 
135   // Crumbles a cookie header into ";" delimited crumbs.
136   static void CookieToCrumbs(const Representation& cookie,
137                              Representations* crumbs_out);
138 
139   // Crumbles other header field values at \0 delimiters.
140   static void DecomposeRepresentation(const Representation& header_field,
141                                       Representations* out);
142 
143   HpackHeaderTable header_table_;
144   HpackOutputStream output_stream_;
145 
146   size_t min_table_size_setting_received_;
147   HeaderListener listener_;
148   IndexingPolicy should_index_;
149   bool enable_compression_;
150   bool should_emit_table_size_;
151   bool crumble_cookies_;
152 };
153 
154 }  // namespace spdy
155 
156 #endif  // QUICHE_SPDY_CORE_HPACK_HPACK_ENCODER_H_
157