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