• 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 <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   // Returns the current dynamic table size, including the 32 bytes per entry
101   // overhead mentioned in RFC 7541 section 4.1.
GetDynamicTableSize()102   size_t GetDynamicTableSize() const { return header_table_.size(); }
103 
104  private:
105   friend class test::HpackEncoderPeer;
106 
107   class RepresentationIterator;
108   class Encoderator;
109 
110   // Encodes a sequence of header name-value pairs as a single header block.
111   std::string EncodeRepresentations(RepresentationIterator* iter);
112 
113   // Emits a static/dynamic indexed representation (Section 7.1).
114   void EmitIndex(size_t index);
115 
116   // Emits a literal representation (Section 7.2).
117   void EmitIndexedLiteral(const Representation& representation);
118   void EmitNonIndexedLiteral(const Representation& representation,
119                              bool enable_compression);
120   void EmitLiteral(const Representation& representation);
121 
122   // Emits a Huffman or identity string (whichever is smaller).
123   void EmitString(absl::string_view str);
124 
125   // Emits the current dynamic table size if the table size was recently
126   // updated and we have not yet emitted it (Section 6.3).
127   void MaybeEmitTableSize();
128 
129   // Crumbles a cookie header into ";" delimited crumbs.
130   static void CookieToCrumbs(const Representation& cookie,
131                              Representations* crumbs_out);
132 
133   // Crumbles other header field values at \0 delimiters.
134   static void DecomposeRepresentation(const Representation& header_field,
135                                       Representations* out);
136 
137   HpackHeaderTable header_table_;
138   HpackOutputStream output_stream_;
139 
140   size_t min_table_size_setting_received_;
141   HeaderListener listener_;
142   IndexingPolicy should_index_;
143   bool enable_compression_;
144   bool should_emit_table_size_;
145 };
146 
147 }  // namespace spdy
148 
149 #endif  // QUICHE_SPDY_CORE_HPACK_HPACK_ENCODER_H_
150