xref: /trafficserver/proxy/http2/HPACK.h (revision e3212f14)
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 {
59   uint32_t index        = 0;
60   HpackIndex index_type = HpackIndex::NONE;
61   HpackMatch match_type = HpackMatch::NONE;
62 };
63 
64 class MIMEFieldWrapper
65 {
66 public:
MIMEFieldWrapper(MIMEField * f,HdrHeap * hh,MIMEHdrImpl * impl)67   MIMEFieldWrapper(MIMEField *f, HdrHeap *hh, MIMEHdrImpl *impl) : _field(f), _heap(hh), _mh(impl) {}
68   void
name_set(const char * name,int name_len)69   name_set(const char *name, int name_len)
70   {
71     _field->name_set(_heap, _mh, name, name_len);
72   }
73 
74   void
value_set(const char * value,int value_len)75   value_set(const char *value, int value_len)
76   {
77     _field->value_set(_heap, _mh, value, value_len);
78   }
79 
80   const char *
name_get(int * length) const81   name_get(int *length) const
82   {
83     return _field->name_get(length);
84   }
85 
86   const char *
value_get(int * length) const87   value_get(int *length) const
88   {
89     return _field->value_get(length);
90   }
91 
92   const MIMEField *
field_get() const93   field_get() const
94   {
95     return _field;
96   }
97 
98 private:
99   MIMEField *_field;
100   HdrHeap *_heap;
101   MIMEHdrImpl *_mh;
102 };
103 
104 // [RFC 7541] 2.3.2. Dynamic Table
105 class HpackDynamicTable
106 {
107 public:
108   explicit HpackDynamicTable(uint32_t size);
109   ~HpackDynamicTable();
110 
111   // noncopyable
112   HpackDynamicTable(HpackDynamicTable &) = delete;
113   HpackDynamicTable &operator=(const HpackDynamicTable &) = delete;
114 
115   const MIMEField *get_header_field(uint32_t index) const;
116   void add_header_field(const MIMEField *field);
117 
118   HpackLookupResult lookup(const char *name, int name_len, const char *value, int value_len) const;
119   uint32_t maximum_size() const;
120   uint32_t size() const;
121   void update_maximum_size(uint32_t new_size);
122 
123   uint32_t length() const;
124 
125 private:
126   void _evict_overflowed_entries();
127   void _mime_hdr_gc();
128 
129   uint32_t _current_size = 0;
130   uint32_t _maximum_size = 0;
131 
132   MIMEHdr *_mhdr     = nullptr;
133   MIMEHdr *_mhdr_old = nullptr;
134   std::deque<MIMEField *> _headers;
135 };
136 
137 // [RFC 7541] 2.3. Indexing Table
138 class HpackIndexingTable
139 {
140 public:
HpackIndexingTable(uint32_t size)141   explicit HpackIndexingTable(uint32_t size) : _dynamic_table(size){};
~HpackIndexingTable()142   ~HpackIndexingTable() {}
143 
144   // noncopyable
145   HpackIndexingTable(HpackIndexingTable &) = delete;
146   HpackIndexingTable &operator=(const HpackIndexingTable &) = delete;
147 
148   HpackLookupResult lookup(const MIMEFieldWrapper &field) const;
149   HpackLookupResult lookup(const char *name, int name_len, const char *value, int value_len) const;
150   int get_header_field(uint32_t index, MIMEFieldWrapper &header_field) const;
151 
152   void add_header_field(const MIMEField *field);
153   uint32_t maximum_size() const;
154   uint32_t size() const;
155   void update_maximum_size(uint32_t new_size);
156 
157 private:
158   HpackDynamicTable _dynamic_table;
159 };
160 
161 // Low level interfaces
162 int64_t encode_indexed_header_field(uint8_t *buf_start, const uint8_t *buf_end, uint32_t index);
163 int64_t encode_literal_header_field_with_indexed_name(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper &header,
164                                                       uint32_t index, HpackIndexingTable &indexing_table, HpackField type);
165 int64_t encode_literal_header_field_with_new_name(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper &header,
166                                                   HpackIndexingTable &indexing_table, HpackField type);
167 int64_t decode_indexed_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, const uint8_t *buf_end,
168                                     HpackIndexingTable &indexing_table);
169 int64_t decode_literal_header_field(MIMEFieldWrapper &header, const uint8_t *buf_start, const uint8_t *buf_end,
170                                     HpackIndexingTable &indexing_table);
171 int64_t update_dynamic_table_size(const uint8_t *buf_start, const uint8_t *buf_end, HpackIndexingTable &indexing_table,
172                                   uint32_t maximum_table_size);
173 
174 // High level interfaces
175 typedef HpackIndexingTable HpackHandle;
176 int64_t hpack_decode_header_block(HpackHandle &handle, HTTPHdr *hdr, const uint8_t *in_buf, const size_t in_buf_len,
177                                   uint32_t max_header_size, uint32_t maximum_table_size);
178 int64_t hpack_encode_header_block(HpackHandle &handle, uint8_t *out_buf, const size_t out_buf_len, HTTPHdr *hdr,
179                                   int32_t maximum_table_size = -1);
180 int32_t hpack_get_maximum_table_size(HpackHandle &handle);
181