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