xref: /trafficserver/proxy/http2/HPACK.h (revision 3376d438)
1 /** @file
2 
3   [RFC 7541] HPACK: Header Compression for HTTP/2
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 #pragma once
25 
26 #include "tscore/ink_platform.h"
27 #include "tscore/Diags.h"
28 #include "HTTP.h"
29 #include "../hdrs/XPACK.h"
30 
31 #include <deque>
32 
33 // It means that any header field can be compressed/decompressed by ATS
34 const static int HPACK_ERROR_COMPRESSION_ERROR   = -1;
35 const static int HPACK_ERROR_SIZE_EXCEEDED_ERROR = -2;
36 
37 enum class HpackField {
38   INDEX,              // [RFC 7541] 6.1. Indexed Header Field Representation
39   INDEXED_LITERAL,    // [RFC 7541] 6.2.1. Literal Header Field with Incremental Indexing
40   NOINDEX_LITERAL,    // [RFC 7541] 6.2.2. Literal Header Field without Indexing
41   NEVERINDEX_LITERAL, // [RFC 7541] 6.2.3. Literal Header Field never Indexed
42   TABLESIZE_UPDATE,   // [RFC 7541] 6.3. Dynamic Table Size Update
43 };
44 
45 enum class HpackIndex {
46   NONE,
47   STATIC,
48   DYNAMIC,
49 };
50 
51 enum class HpackMatch {
52   NONE,
53   NAME,
54   EXACT,
55 };
56 
57 // Result of looking for a header field in IndexingTable
58 struct HpackLookupResult {
HpackLookupResultHpackLookupResult59   HpackLookupResult() {}
60   int index             = 0;
61   HpackIndex index_type = HpackIndex::NONE;
62   HpackMatch match_type = HpackMatch::NONE;
63 };
64 
65 class MIMEFieldWrapper
66 {
67 public:
MIMEFieldWrapper(MIMEField * f,HdrHeap * hh,MIMEHdrImpl * impl)68   MIMEFieldWrapper(MIMEField *f, HdrHeap *hh, MIMEHdrImpl *impl) : _field(f), _heap(hh), _mh(impl) {}
69   void
name_set(const char * name,int name_len)70   name_set(const char *name, int name_len)
71   {
72     _field->name_set(_heap, _mh, name, name_len);
73   }
74 
75   void
value_set(const char * value,int value_len)76   value_set(const char *value, int value_len)
77   {
78     _field->value_set(_heap, _mh, value, value_len);
79   }
80 
81   const char *
name_get(int * length) const82   name_get(int *length) const
83   {
84     return _field->name_get(length);
85   }
86 
87   const char *
value_get(int * length) const88   value_get(int *length) const
89   {
90     return _field->value_get(length);
91   }
92 
93   const MIMEField *
field_get() const94   field_get() const
95   {
96     return _field;
97   }
98 
99 private:
100   MIMEField *_field;
101   HdrHeap *_heap;
102   MIMEHdrImpl *_mh;
103 };
104 
105 // [RFC 7541] 2.3.2. Dynamic Table
106 class HpackDynamicTable
107 {
108 public:
HpackDynamicTable(uint32_t size)109   explicit HpackDynamicTable(uint32_t size) : _current_size(0), _maximum_size(size)
110   {
111     _mhdr = new MIMEHdr();
112     _mhdr->create();
113   }
114 
115   ~HpackDynamicTable();
116 
117   // noncopyable
118   HpackDynamicTable(HpackDynamicTable &) = delete;
119   HpackDynamicTable &operator=(const HpackDynamicTable &) = delete;
120 
121   const MIMEField *get_header_field(uint32_t index) const;
122   void add_header_field(const MIMEField *field);
123 
124   uint32_t maximum_size() const;
125   uint32_t size() const;
126   void update_maximum_size(uint32_t new_size);
127 
128   uint32_t length() const;
129 
130 private:
131   void _evict_overflowed_entries();
132   void _mime_hdr_gc();
133 
134   uint32_t _current_size = 0;
135   uint32_t _maximum_size = 0;
136 
137   MIMEHdr *_mhdr     = nullptr;
138   MIMEHdr *_mhdr_old = nullptr;
139   std::deque<MIMEField *> _headers;
140 };
141 
142 // [RFC 7541] 2.3. Indexing Table
143 class HpackIndexingTable
144 {
145 public:
HpackIndexingTable(uint32_t size)146   explicit HpackIndexingTable(uint32_t size) { _dynamic_table = new HpackDynamicTable(size); }
~HpackIndexingTable()147   ~HpackIndexingTable() { delete _dynamic_table; }
148 
149   // noncopyable
150   HpackIndexingTable(HpackIndexingTable &) = delete;
151   HpackIndexingTable &operator=(const HpackIndexingTable &) = delete;
152 
153   HpackLookupResult lookup(const MIMEFieldWrapper &field) const;
154   HpackLookupResult lookup(const char *name, int name_len, const char *value, int value_len) const;
155   int get_header_field(uint32_t index, MIMEFieldWrapper &header_field) const;
156 
157   void add_header_field(const MIMEField *field);
158   uint32_t maximum_size() const;
159   uint32_t size() const;
160   void update_maximum_size(uint32_t new_size);
161 
162 private:
163   HpackDynamicTable *_dynamic_table;
164 };
165 
166 // Low level interfaces
167 int64_t encode_indexed_header_field(uint8_t *buf_start, const uint8_t *buf_end, uint32_t index);
168 int64_t encode_literal_header_field_with_indexed_name(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper &header,
169                                                       uint32_t index, HpackIndexingTable &indexing_table, HpackField type);
170 int64_t encode_literal_header_field_with_new_name(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper &header,
171                                                   HpackIndexingTable &indexing_table, HpackField type);
172 int64_t decode_indexed_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, const uint8_t *buf_end,
173                                     HpackIndexingTable &indexing_table);
174 int64_t decode_literal_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, const uint8_t *buf_end,
175                                     HpackIndexingTable &indexing_table);
176 int64_t update_dynamic_table_size(const uint8_t *buf_start, const uint8_t *buf_end, HpackIndexingTable &indexing_table,
177                                   uint32_t maximum_table_size);
178 
179 // High level interfaces
180 typedef HpackIndexingTable HpackHandle;
181 int64_t hpack_decode_header_block(HpackHandle &handle, HTTPHdr *hdr, const uint8_t *in_buf, const size_t in_buf_len,
182                                   uint32_t max_header_size, uint32_t maximum_table_size);
183 int64_t hpack_encode_header_block(HpackHandle &handle, uint8_t *out_buf, const size_t out_buf_len, HTTPHdr *hdr,
184                                   int32_t maximum_table_size = -1);
185 int32_t hpack_get_maximum_table_size(HpackHandle &handle);
186