Coverage Report

Created: 2025-03-11 06:06

/src/brpc/src/brpc/details/hpack.cpp
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
19
#include "brpc/details/hpack.h"
20
21
#include <limits>                                       // std::numeric_limits
22
#include <vector>
23
#include "butil/containers/bounded_queue.h"              // butil::BoundedQueue
24
#include "butil/containers/flat_map.h"                   // butil::FlatMap
25
#include "butil/containers/case_ignored_flat_map.h"      // butil::FlatMap
26
#include "brpc/details/hpack-static-table.h"       // s_static_headers
27
28
29
namespace brpc {
30
31
// Options to initialize a IndexTable
32
struct IndexTableOptions {
33
    size_t max_size;
34
    uint64_t start_index;
35
    const HeaderCstr* static_table;
36
    size_t static_table_size;
37
    bool need_indexes;
38
    IndexTableOptions()
39
1.37k
        : max_size(0)
40
1.37k
        , start_index(0)
41
        , static_table(NULL)
42
1.37k
        , static_table_size(0)
43
1.37k
        , need_indexes(false)
44
1.37k
    {}
45
};
46
47
struct HeaderAndHashCode {
48
    size_t hash_code;
49
    const HPacker::Header* header;
50
};
51
52
struct HeaderHasher {
53
14
    size_t operator()(const HPacker::Header& h) const {
54
14
        return butil::CaseIgnoredHasher()(h.name)
55
14
            * 101 + butil::DefaultHasher<std::string>()(h.value);
56
14
    }
57
0
    size_t operator()(const HeaderAndHashCode& h) const {
58
0
        return h.hash_code;
59
0
    }
60
};
61
62
struct HeaderEqualTo {
63
1
    bool operator()(const HPacker::Header& h1, const HPacker::Header& h2) const {
64
1
        return butil::CaseIgnoredEqual()(h1.name, h2.name)
65
1
            && butil::DefaultEqualTo<std::string>()(h1.value, h2.value);
66
1
    }
67
0
    bool operator()(const HPacker::Header& h1, const HeaderAndHashCode& h2) const {
68
0
        return operator()(h1, *h2.header);
69
0
    }
70
};
71
72
class BAIDU_CACHELINE_ALIGNMENT IndexTable {
73
DISALLOW_COPY_AND_ASSIGN(IndexTable);
74
    typedef HPacker::Header Header;
75
public:
76
    IndexTable()
77
1.37k
        : _start_index(0)
78
1.37k
        , _add_times(0)
79
1.37k
        , _size(0)
80
1.37k
    {}
81
1.37k
    ~IndexTable() {}
82
    int Init(const IndexTableOptions& options);
83
84
273
    const Header* HeaderAt(int index) const {
85
273
        if (BAIDU_UNLIKELY(index < _start_index)) {
86
2
            return NULL;
87
2
        }
88
271
        return _header_queue.bottom(index - _start_index);
89
273
    };
90
91
0
    int GetIndexOfHeader(const HeaderAndHashCode& h) {
92
0
        DCHECK(_need_indexes);
93
0
        const uint64_t* v = _header_index.seek(h);
94
0
        if (!v) {
95
0
            return 0;
96
0
        }
97
0
        DCHECK_LE(_add_times - *v, _header_queue.size());
98
        // The latest added entry has the smallest index
99
0
        return _start_index + (_add_times - *v) - 1;
100
0
    }
101
102
0
    int GetIndexOfName(const std::string& name) {
103
0
        DCHECK(_need_indexes);
104
0
        const uint64_t* v = _name_index.seek(name);
105
0
        if (!v) {
106
0
            return 0;
107
0
        }
108
0
        DCHECK_LE(_add_times - *v, _header_queue.size());
109
        // The latest added entry has the smallest index
110
0
        return _start_index + (_add_times - *v) - 1;
111
0
    }
112
113
406
    bool empty() const { return _size == 0; }
114
1.64k
    int start_index() const { return _start_index; }
115
1.37k
    int end_index() const { return start_index() + _header_queue.size(); }
116
117
282
    static inline size_t HeaderSize(const Header& h) {
118
        // https://tools.ietf.org/html/rfc7541#section-4.1
119
282
        return h.name.size() + h.value.size() + 32;
120
282
    }
121
122
0
    void PopHeader() {
123
0
        DCHECK(!empty());
124
0
        const Header* h = _header_queue.top();
125
0
        const size_t entry_size = HeaderSize(*h);
126
0
        DCHECK_LE(entry_size, _size);
127
0
        const uint64_t id = _add_times - _header_queue.size();
128
0
        if (_need_indexes) {
129
0
            RemoveHeaderFromIndexes(*h, id);
130
0
        }
131
0
        _size -= entry_size;
132
0
        _header_queue.pop();
133
0
    }
134
135
0
    void RemoveHeaderFromIndexes(const Header& h, uint64_t expected_id) {
136
0
        if (!h.value.empty()) {
137
0
            const uint64_t* v = _header_index.seek(h);
138
0
            DCHECK(v);
139
0
            if (*v == expected_id) {
140
0
                _header_index.erase(h);
141
0
            }
142
0
        }
143
0
        const uint64_t* v = _name_index.seek(h.name);
144
0
        DCHECK(v);
145
0
        if (*v == expected_id) {
146
0
            _name_index.erase(h.name);
147
0
        }
148
0
    }
149
150
282
    void AddHeader(const Header& h) {
151
282
        CHECK(!h.name.empty());
152
282
        const size_t entry_size = HeaderSize(h);
153
154
282
        while (!empty() && (_size + entry_size) > _max_size) {
155
0
            PopHeader();
156
0
        }
157
158
282
        if (entry_size > _max_size) {
159
            // https://tools.ietf.org/html/rfc7541#section-4.1
160
            // If this header is larger than the max size, clear the table only.
161
124
            DCHECK(empty());
162
124
            return;
163
124
        }
164
165
158
        _size += entry_size;
166
158
        CHECK(!_header_queue.full());
167
158
        _header_queue.push(h);
168
169
158
        const int id = _add_times++;
170
158
        if (_need_indexes) {
171
            // Overwrite existance value.
172
61
            if (!h.value.empty()) {
173
14
                _header_index[h] = id;
174
14
            }
175
61
            _name_index[h.name] = id;
176
61
        }
177
158
    }
178
179
16.8k
    void ResetMaxSize(size_t new_max_size) {
180
16.8k
        LOG(INFO) << this << ".size=" << _size << " new_max_size=" << new_max_size
181
16.8k
                  << " max_size=" << _max_size;
182
16.8k
        if (new_max_size > _max_size) {
183
            //LOG(ERROR) << "Invalid new_max_size=" << new_max_size;
184
            //return -1;
185
4.17k
            _max_size = new_max_size;
186
4.17k
            return;
187
4.17k
        }
188
12.6k
        if (new_max_size < _max_size) {
189
4.18k
            _max_size = new_max_size;
190
4.18k
            while (_size > _max_size) {
191
0
                PopHeader();
192
0
            }
193
4.18k
        }
194
12.6k
        return;
195
16.8k
    }
196
197
    void Print(std::ostream& os) const;
198
199
private:
200
201
    int _start_index;
202
    bool _need_indexes;
203
    uint64_t _add_times;  // Increase when adding a new entry.
204
    size_t _max_size;
205
    size_t _size;
206
    butil::BoundedQueue<Header> _header_queue;
207
208
    // -----------------------  Encoder only ----------------------------
209
    // Indexes that map entry to the latest time it was added.
210
    // Note that duplicated entries are allowed in index table, which indicates
211
    // that the same header is possibly added/removed for multiple times,
212
    // requiring a costly multimap to index all the header entries.
213
    // Since the encoder just cares whether this header is in the index table
214
    // rather than which the index number is, only the latest entry of the same
215
    // header is indexed here, which is definitely the last one to be removed.
216
    butil::FlatMap<Header, uint64_t, HeaderHasher, HeaderEqualTo> _header_index;
217
    butil::CaseIgnoredFlatMap<uint64_t> _name_index;
218
};
219
220
1.37k
int IndexTable::Init(const IndexTableOptions& options) {
221
1.37k
    size_t num_headers = 0;
222
1.37k
    if (options.static_table_size > 0) {
223
1
        num_headers = options.static_table_size;
224
1
        _max_size = UINT_MAX;
225
1.37k
    } else {
226
1.37k
        num_headers = options.max_size / (32 + 2);
227
        //                                     ^
228
        // name and value both have at least one byte in.
229
1.37k
        _max_size = options.max_size;
230
1.37k
    }
231
1.37k
    void *header_queue_storage = malloc(num_headers * sizeof(Header));
232
1.37k
    if (!header_queue_storage) {
233
0
        LOG(ERROR) << "Fail to malloc space for " << num_headers << " headers";
234
0
        return -1;
235
0
    }
236
1.37k
    butil::BoundedQueue<Header> tmp(
237
1.37k
        header_queue_storage, num_headers * sizeof(Header),
238
1.37k
        butil::OWNS_STORAGE);
239
1.37k
    _header_queue.swap(tmp);
240
1.37k
    _start_index = options.start_index;
241
1.37k
    _need_indexes = options.need_indexes;
242
1.37k
    if (_need_indexes) {
243
686
        if (_name_index.init(num_headers * 2) != 0) {
244
0
            LOG(WARNING) << "Fail to init _name_index";
245
0
        }
246
686
        if (_header_index.init(num_headers * 2) != 0) {
247
0
            LOG(WARNING) << "Fail to init _name_index";
248
0
        }
249
686
    }
250
1.37k
    if (options.static_table_size > 0) {
251
        // Add header in the reverse order
252
62
        for (int i = options.static_table_size - 1; i >= 0; --i) {
253
61
            Header h;
254
61
            h.name = options.static_table[i].name;
255
61
            h.value = options.static_table[i].value;
256
61
            AddHeader(h);
257
61
        }
258
1
    }
259
1.37k
    return 0;
260
1.37k
}
261
262
0
void IndexTable::Print(std::ostream& os) const {
263
0
    os << "{start_index=" << _start_index
264
0
       << " need_indexes=" << _need_indexes
265
0
       << " add_times=" << _add_times
266
0
       << " max_size=" << _max_size
267
0
       << " size=" << _size
268
0
       << " header_queue.size=" << _header_queue.size()
269
0
       << " header_index.size=" << _header_index.size()
270
0
       << " name_index.size=" << _name_index.size()
271
0
       << '}';
272
0
}
273
274
struct HuffmanNode {
275
    uint16_t left_child;
276
    uint16_t right_child;
277
    int32_t value;
278
};
279
280
class BAIDU_CACHELINE_ALIGNMENT HuffmanTree {
281
DISALLOW_COPY_AND_ASSIGN(HuffmanTree);
282
public:
283
    typedef uint16_t NodeId;
284
    enum ConstValue {
285
        NULL_NODE = 0,
286
        ROOT_NODE = 1,
287
        INVALID_VALUE = INT_MAX
288
    };
289
290
1
    HuffmanTree() {
291
        // Allocate memory for root
292
1
        HuffmanNode root = { NULL_NODE, NULL_NODE, INVALID_VALUE };
293
1
        _node_memory.push_back(root);
294
1
    }
295
296
257
    void AddLeafNode(int32_t value, const HuffmanCode& code) {
297
257
        NodeId cur = ROOT_NODE;
298
4.94k
        for (int i = code.bit_len; i > 0; i--) {
299
4.68k
            CHECK_EQ(node(cur).value, INVALID_VALUE) << "value=" << value << "cur=" << cur;
300
4.68k
            if (code.code & (1u << (i - 1))) {
301
3.99k
                if (node(cur).right_child == NULL_NODE) {
302
256
                    NodeId new_id = AllocNode();
303
256
                    node(cur).right_child = new_id;
304
256
                }
305
3.99k
                cur = node(cur).right_child;
306
3.99k
            } else {
307
692
                if (node(cur).left_child == NULL_NODE) {
308
256
                    NodeId new_id = AllocNode();
309
256
                    node(cur).left_child = new_id;
310
256
                }
311
692
                cur = node(cur).left_child;
312
692
            }
313
4.68k
        }
314
257
        CHECK_EQ(INVALID_VALUE, node(cur).value) << "value=" << value << " cur=" << cur;
315
257
        CHECK_EQ(NULL_NODE, node(cur).left_child);
316
257
        CHECK_EQ(NULL_NODE, node(cur).right_child);
317
257
        node(cur).value = value;
318
257
    }
319
320
151k
    const HuffmanNode* node(NodeId id) const {
321
151k
        if (id == 0u) {
322
0
            return NULL;
323
0
        }
324
151k
        if (id > _node_memory.size()) {
325
0
            return NULL;
326
0
        }
327
151k
        return &_node_memory[id - 1];
328
151k
    }
329
330
private:
331
332
15.6k
    HuffmanNode& node(NodeId id) {
333
15.6k
        return _node_memory[id - 1];
334
15.6k
    }
335
336
512
    NodeId AllocNode() {
337
512
        const NodeId id = _node_memory.size() + 1;
338
512
        HuffmanNode node = { NULL_NODE, NULL_NODE, INVALID_VALUE };
339
512
        _node_memory.push_back(node);
340
512
        return id;
341
512
    }
342
    std::vector<HuffmanNode> _node_memory;
343
344
};
345
346
class HuffmanEncoder {
347
DISALLOW_COPY_AND_ASSIGN(HuffmanEncoder);
348
public:
349
    HuffmanEncoder(butil::IOBufAppender* out, const HuffmanCode* table)
350
0
        : _out(out)
351
0
        , _table(table)
352
0
        , _partial_byte(0)
353
0
        , _remain_bit(8)
354
0
        , _out_bytes(0)
355
0
    {}
356
357
0
    void Encode(unsigned char byte) {
358
0
        const HuffmanCode code = _table[byte];
359
0
        uint16_t bits_left = code.bit_len;
360
0
        while (bits_left) {
361
0
            const uint16_t adding_bits_len = std::min(_remain_bit, bits_left);
362
0
            const uint8_t adding_bits = static_cast<uint8_t>(
363
0
                    (code.code & ((1u << bits_left) - 1))   // clear leading bits
364
0
                            >> (bits_left - adding_bits_len));  // align to LSB
365
0
            _partial_byte |= adding_bits << (_remain_bit - adding_bits_len);
366
0
            _remain_bit -= adding_bits_len;
367
0
            bits_left -= adding_bits_len;
368
0
            if (!_remain_bit) {
369
0
                ++_out_bytes;
370
0
                _out->push_back(_partial_byte);
371
0
                _remain_bit = 8;
372
0
                _partial_byte = 0;
373
0
            }
374
0
        }
375
0
    }
376
377
0
    void EndStream() {
378
0
        if (_remain_bit == 8u) {
379
0
            return;
380
0
        }
381
0
        DCHECK_LT(_remain_bit, 8u);
382
        // Add padding `1's to lsb to make _out aligned
383
0
        _partial_byte |= (1 << _remain_bit) - 1;
384
        // TODO: push_back is probably costly since it acquires tls everytime it
385
        // is invoked.
386
0
        _out->push_back(_partial_byte);
387
0
        _partial_byte = 0;
388
0
        _remain_bit = 0;
389
0
        _out = NULL;
390
0
        ++_out_bytes;
391
0
    }
392
393
0
    uint32_t out_bytes() const { return _out_bytes; }
394
395
private:
396
    butil::IOBufAppender* _out;
397
    const HuffmanCode* _table;
398
    uint8_t  _partial_byte;
399
    uint16_t _remain_bit;
400
    uint32_t _out_bytes;
401
};
402
403
class HuffmanDecoder {
404
DISALLOW_COPY_AND_ASSIGN(HuffmanDecoder);
405
public:
406
    HuffmanDecoder(std::string* out, const HuffmanTree* tree)
407
        // FIXME: resizing of out is costly
408
249
        : _out(out)
409
249
        , _tree(tree)
410
249
        , _cur_node(tree->node(HuffmanTree::ROOT_NODE))
411
249
        , _cur_depth(0)  // Depth of root node is 0
412
249
        , _padding(true)
413
249
    {}
414
15.9k
    int Decode(uint8_t byte) {
415
143k
        for (int i = 7; i >= 0; --i) {
416
127k
            if (byte & (1u << i)) {
417
24.4k
                _cur_node = _tree->node(_cur_node->right_child);
418
24.4k
                if (BAIDU_UNLIKELY(!_cur_node)) {
419
0
                    LOG(ERROR) << "Decoder stream reaches NULL_NODE";
420
0
                    return -1;
421
0
                }
422
24.4k
                if (_cur_node->value != HuffmanTree::INVALID_VALUE) {
423
3.71k
                    if (BAIDU_UNLIKELY(_cur_node->value == HPACK_HUFFMAN_EOS)) {
424
7
                        LOG(ERROR) << "Decoder stream reaches EOS";
425
7
                        return -1;
426
7
                    }
427
3.70k
                    _out->push_back(static_cast<uint8_t>(_cur_node->value));
428
3.70k
                    _cur_node = _tree->node(HuffmanTree::ROOT_NODE);
429
3.70k
                    _cur_depth = 0;
430
3.70k
                    _padding = true;
431
3.70k
                    continue;
432
3.71k
                }
433
20.7k
                _padding &= 1;
434
102k
            } else {
435
102k
                _cur_node = _tree->node(_cur_node->left_child);
436
102k
                if (BAIDU_UNLIKELY(!_cur_node)) {
437
0
                    LOG(ERROR) << "Decoder stream reaches NULL_NODE";
438
0
                    return -1;
439
0
                }
440
102k
                if (_cur_node->value != HuffmanTree::INVALID_VALUE) {
441
19.8k
                    if (BAIDU_UNLIKELY(_cur_node->value == HPACK_HUFFMAN_EOS)) {
442
0
                        LOG(ERROR) << "Decoder stream reaches EOS";
443
0
                        return -1;
444
0
                    }
445
19.8k
                    _out->push_back(static_cast<uint8_t>(_cur_node->value));
446
19.8k
                    _cur_node = _tree->node(HuffmanTree::ROOT_NODE);
447
19.8k
                    _cur_depth = 0;
448
19.8k
                    _padding = true;
449
19.8k
                    continue;
450
19.8k
                }
451
83.1k
                _padding &= 0;
452
83.1k
            }
453
103k
            ++_cur_depth;
454
103k
        }
455
15.9k
        return 0;
456
15.9k
    }
457
242
    int EndStream() {
458
242
        if (_cur_depth == 0) {
459
148
            return 0;
460
148
        }
461
94
        if (_cur_depth <= 7 && _padding) {
462
46
            return 0;
463
46
        }
464
        // Invalid stream, the padding is not corresponding to MSB of EOS
465
        // https://tools.ietf.org/html/rfc7541#section-5.2
466
48
        return -1;
467
94
    }
468
private:
469
    std::string* _out;
470
    const HuffmanTree* _tree;
471
    const HuffmanNode* _cur_node;
472
    uint16_t _cur_depth;
473
    bool _padding;
474
};
475
476
// Primitive Type Representations
477
478
// Encode variant intger and return the size
479
inline void EncodeInteger(butil::IOBufAppender* out, uint8_t msb,
480
0
                          uint8_t prefix_size, uint32_t value) {
481
0
    uint8_t max_prefix_value = (1 << prefix_size) - 1;
482
0
    if (value < max_prefix_value) {
483
0
        msb |= value;
484
0
        out->push_back(msb);
485
0
        return;
486
0
    }
487
0
    value -= max_prefix_value;
488
0
    msb |= max_prefix_value;
489
0
    out->push_back(msb);
490
0
    for (; value >= 128; ) {
491
0
        const uint8_t c = (value & 0x7f) | 0x80;
492
0
        value >>= 7;
493
0
        out->push_back(c);
494
0
    }
495
0
    out->push_back(static_cast<uint8_t>(value));
496
0
}
497
498
// Static variables
499
static HuffmanTree* s_huffman_tree = NULL;
500
static IndexTable* s_static_table = NULL;
501
static pthread_once_t s_create_once = PTHREAD_ONCE_INIT;
502
503
1
static void CreateStaticTableOrDie() {
504
1
    s_huffman_tree = new HuffmanTree;
505
258
    for (size_t i = 0; i < ARRAY_SIZE(s_huffman_table); ++i) {
506
257
        s_huffman_tree->AddLeafNode(i, s_huffman_table[i]);
507
257
    }
508
1
    IndexTableOptions options;
509
1
    options.max_size = UINT_MAX;
510
1
    options.static_table = s_static_headers;
511
1
    options.static_table_size = ARRAY_SIZE(s_static_headers);
512
1
    options.start_index = 1;
513
1
    options.need_indexes = true;
514
1
    s_static_table = new IndexTable;
515
1
    if (s_static_table->Init(options) != 0) {
516
0
        LOG(ERROR) << "Fail to init static table";
517
0
        exit(1);
518
0
    }
519
1
}
520
521
685
static void CreateStaticTableOnceOrDie() {
522
685
    if (pthread_once(&s_create_once, CreateStaticTableOrDie) != 0) {
523
0
        PLOG(ERROR) << "Fail to pthread_once";
524
0
        exit(1);
525
0
    }
526
685
}
527
528
// Assume that no header would be larger than 10MB
529
static const size_t MAX_HPACK_INTEGER = 10 * 1024 * 1024ul;
530
531
inline ssize_t DecodeInteger(butil::IOBufBytesIterator& iter,
532
18.1k
                             uint8_t prefix_size, uint32_t* value) {
533
18.1k
    if (iter == NULL) {
534
0
        return 0; // No enough data
535
0
    }
536
18.1k
    uint8_t first_byte = *iter;
537
18.1k
    uint64_t tmp = first_byte & ((1 << prefix_size) - 1);
538
18.1k
    ++iter;
539
18.1k
    if (tmp < ((1u << prefix_size) - 1)) {
540
17.4k
        *value = static_cast<uint32_t>(tmp);
541
17.4k
        return 1;
542
17.4k
    }
543
635
    uint8_t cur_byte = 0;
544
635
    int m = 0;
545
635
    ssize_t in_bytes = 1;
546
10.3k
    do {
547
10.3k
        if (!iter) {
548
18
            return 0;
549
18
        }
550
10.3k
        cur_byte = *iter;
551
10.3k
        in_bytes++;
552
10.3k
        tmp += static_cast<uint64_t>(cur_byte & 0x7f) << m;
553
10.3k
        m += 7;
554
10.3k
        ++iter;
555
10.3k
    } while ((cur_byte & 0x80) && (tmp < MAX_HPACK_INTEGER));
556
557
617
    if (tmp >= MAX_HPACK_INTEGER) {
558
27
        LOG(ERROR) << "Source stream is likely malformed";
559
27
        return -1;
560
27
    }
561
562
590
    *value = static_cast<uint32_t>(tmp);
563
564
590
    return in_bytes;
565
617
}
566
567
template <bool LOWERCASE> // use template to remove dead branches.
568
inline void EncodeString(butil::IOBufAppender* out, const std::string& s,
569
0
                         bool huffman_encoding) {
570
0
    if (!huffman_encoding) {
571
0
        EncodeInteger(out, 0x00, 7, s.size());
572
0
        if (LOWERCASE) {
573
0
            for (size_t i = 0; i < s.size(); ++i) {
574
0
                out->push_back(butil::ascii_tolower(s[i]));
575
0
            }
576
0
        } else {
577
0
            out->append(s);
578
0
        }
579
0
        return;
580
0
    }
581
    // Calculate length of encoded string
582
0
    uint32_t bit_len = 0;
583
0
    if (LOWERCASE) {
584
0
        for (size_t i = 0; i < s.size(); ++i) {
585
0
            bit_len += s_huffman_table[(uint8_t)butil::ascii_tolower(s[i])].bit_len;
586
0
        }
587
0
    } else {
588
0
        for (size_t i = 0; i < s.size(); ++i) {
589
0
            bit_len += s_huffman_table[(uint8_t)s[i]].bit_len;
590
0
        }
591
0
    }
592
0
    EncodeInteger(out, 0x80, 7, (bit_len >> 3) + !!(bit_len & 7));
593
0
    HuffmanEncoder e(out, s_huffman_table);
594
0
    if (LOWERCASE) {
595
0
        for (size_t i = 0; i < s.size(); ++i) {
596
0
            e.Encode(butil::ascii_tolower(s[i]));
597
0
        }
598
0
    } else {
599
0
        for (size_t i = 0; i < s.size(); ++i) {
600
0
            e.Encode(s[i]);
601
0
        }
602
0
    }
603
0
    e.EndStream();
604
0
}
Unexecuted instantiation: void brpc::EncodeString<true>(butil::IOBufAppender*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)
Unexecuted instantiation: void brpc::EncodeString<false>(butil::IOBufAppender*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)
605
606
697
inline ssize_t DecodeString(butil::IOBufBytesIterator& iter, std::string* out) {
607
697
    if (iter == NULL) {
608
85
        return 0;
609
85
    }
610
612
    const bool huffman = *iter & 0x80;
611
612
    uint32_t length = 0;
612
612
    ssize_t in_bytes = DecodeInteger(iter, 7, &length);
613
612
    if (in_bytes <= 0) {
614
5
        return -1;
615
5
    }
616
607
    if (length > iter.bytes_left()) {
617
47
        return 0;
618
47
    }
619
560
    in_bytes += length;
620
560
    out->clear();
621
560
    if (!huffman) {
622
311
        iter.copy_and_forward(out, length);
623
311
        return in_bytes;
624
311
    }
625
249
    HuffmanDecoder d(out, s_huffman_tree);
626
16.1k
    for (; iter != NULL && length; ++iter, --length) {
627
15.9k
        if (d.Decode(*iter) != 0) {
628
7
            return -1;
629
7
        }
630
15.9k
    }
631
242
    if (d.EndStream() != 0) {
632
48
        return -1;
633
48
    }
634
194
    return in_bytes;
635
242
}
636
637
HPacker::HPacker()
638
    : _encode_table(NULL)
639
685
    , _decode_table(NULL) {
640
685
    CreateStaticTableOnceOrDie();
641
685
}
642
643
685
HPacker::~HPacker() {
644
685
    if (_encode_table) {
645
685
        delete _encode_table;
646
685
        _encode_table = NULL;
647
685
    }
648
685
    if (_decode_table) {
649
685
        delete _decode_table;
650
685
        _decode_table = NULL;
651
685
    }
652
685
}
653
654
685
int HPacker::Init(size_t max_table_size) {
655
685
    CHECK(!_encode_table);
656
685
    CHECK(!_decode_table);
657
685
    IndexTableOptions encode_table_options;
658
685
    encode_table_options.max_size = max_table_size;
659
685
    encode_table_options.start_index = s_static_table->end_index();
660
685
    encode_table_options.need_indexes = true;
661
685
    _encode_table = new IndexTable;
662
685
    if (_encode_table->Init(encode_table_options) != 0) {
663
0
        LOG(ERROR) << "Fail to init encode table";
664
0
        return -1;
665
0
    }
666
685
    IndexTableOptions decode_table_options;
667
685
    decode_table_options.max_size = max_table_size;
668
685
    decode_table_options.start_index = s_static_table->end_index();
669
685
    decode_table_options.need_indexes = false;
670
685
    _decode_table = new IndexTable;
671
685
    if (_decode_table->Init(decode_table_options) != 0) {
672
0
        LOG(ERROR) << "Fail to init decode table";
673
0
        return -1;
674
0
    }
675
685
    return 0;
676
685
}
677
678
0
inline int HPacker::FindHeaderFromIndexTable(const Header& h) const {
679
    // saves a hash (which is a hotspot) for ones missing s_static_table
680
0
    const HeaderAndHashCode hhc = { HeaderHasher()(h), &h };
681
0
    int index = s_static_table->GetIndexOfHeader(hhc);
682
0
    if (index > 0) {
683
0
        return index;
684
0
    }
685
0
    return _encode_table->GetIndexOfHeader(hhc);
686
0
}
687
688
0
inline int HPacker::FindNameFromIndexTable(const std::string& name) const {
689
0
    int index = s_static_table->GetIndexOfName(name);
690
0
    if (index > 0) {
691
0
        return index;
692
0
    }
693
0
    return _encode_table->GetIndexOfName(name);
694
0
}
695
696
void HPacker::Encode(butil::IOBufAppender* out, const Header& header,
697
0
                     const HPackOptions& options) {
698
0
    if (options.index_policy != HPACK_NEVER_INDEX_HEADER) {
699
0
        const int index = FindHeaderFromIndexTable(header);
700
0
        if (index > 0) {
701
            // This header is already in the index table
702
0
            return EncodeInteger(out, 0x80, 7, index);
703
0
        }
704
0
    } // The header can't be indexed or the header wasn't in the index table
705
    
706
0
    const int name_index = FindNameFromIndexTable(header.name);
707
0
    if (options.index_policy == HPACK_INDEX_HEADER) {
708
        // TODO: Add Options that indexes name independently
709
0
        _encode_table->AddHeader(header);
710
0
    }
711
0
    switch (options.index_policy) {
712
0
    case HPACK_INDEX_HEADER:
713
0
        EncodeInteger(out, 0x40, 6, name_index);
714
0
        break;
715
0
    case HPACK_NOT_INDEX_HEADER:
716
0
        EncodeInteger(out, 0x00, 4, name_index);
717
0
        break;
718
0
    case HPACK_NEVER_INDEX_HEADER:
719
0
        EncodeInteger(out, 0x10, 4, name_index);
720
0
        break;
721
0
    }
722
0
    if (name_index == 0) {
723
0
        EncodeString<true>(out, header.name, options.encode_name);
724
0
    }
725
0
    EncodeString<false>(out, header.value, options.encode_value);
726
0
}
727
728
273
inline const HPacker::Header* HPacker::HeaderAt(int index) const {
729
273
    return (index >= _decode_table->start_index())
730
273
            ? _decode_table->HeaderAt(index) : s_static_table->HeaderAt(index);
731
273
}
732
733
inline ssize_t HPacker::DecodeWithKnownPrefix(
734
516
    butil::IOBufBytesIterator& iter, Header* h, uint8_t prefix_size) const {
735
516
    int index = 0;
736
516
    ssize_t index_bytes = DecodeInteger(iter, prefix_size, (uint32_t*)&index);
737
516
    ssize_t name_bytes = 0;
738
516
    if (index_bytes <= 0) {
739
12
        LOG(ERROR) << "Fail to decode index";
740
12
        return -1;
741
12
    }
742
504
    if (index != 0) {
743
200
        const Header* indexed_header = HeaderAt(index);
744
200
        if (indexed_header == NULL) {
745
56
            LOG(ERROR) << "No header at index=" << index;
746
56
            return -1;
747
56
        }
748
144
        h->name = indexed_header->name;
749
304
    } else {
750
304
        name_bytes = DecodeString(iter, &h->name);
751
304
        if (name_bytes <= 0) {
752
55
            LOG(ERROR) << "Fail to decode name";
753
55
            return -1;
754
55
        }
755
249
        tolower(&h->name);
756
249
    }
757
393
    ssize_t value_bytes = DecodeString(iter, &h->value);
758
393
    if (value_bytes <= 0) {
759
137
        LOG(ERROR) << "Fail to decode value";
760
137
        return -1;
761
137
    }
762
256
    return index_bytes + name_bytes + value_bytes;
763
393
}
764
765
17.5k
ssize_t HPacker::Decode(butil::IOBufBytesIterator& iter, Header* h) {
766
17.5k
    if (iter == NULL) {
767
51
        return 0;
768
51
    }
769
17.4k
    const uint8_t first_byte = *iter;
770
    // Check the leading 4 bits to determin the entry type
771
17.4k
    switch (first_byte >> 4) {
772
56
    case 15:
773
57
    case 14:
774
60
    case 13:
775
62
    case 12:
776
68
    case 11:
777
71
    case 10:
778
77
    case 9:
779
87
    case 8:
780
        // (1xxx) Indexed Header Field Representation
781
        // https://tools.ietf.org/html/rfc7541#section-6.1
782
87
        {
783
87
            int index = 0;
784
87
            ssize_t index_bytes = DecodeInteger(iter, 7, (uint32_t*)&index);
785
87
            if (index_bytes <= 0) {
786
14
                return index_bytes;
787
14
            }
788
73
            const Header* indexed_header = HeaderAt(index);
789
73
            if (indexed_header == NULL) {
790
51
                LOG(ERROR) << "No header at index=" << index;
791
51
                return -1;
792
51
            }
793
22
            *h = *indexed_header;
794
22
            return index_bytes;
795
73
        }
796
0
        break;
797
59
    case 7:
798
95
    case 5:
799
109
    case 6:
800
357
    case 4:
801
        // (01xx) Literal Header Field with Incremental Indexing
802
        // https://tools.ietf.org/html/rfc7541#section-6.2.1
803
357
        {
804
357
            const ssize_t bytes_consumed = DecodeWithKnownPrefix(iter, h, 6);
805
357
            if (bytes_consumed <= 0) {
806
136
                return -1;
807
136
            }
808
221
            _decode_table->AddHeader(*h);
809
221
            return bytes_consumed;
810
357
        }
811
0
        break;
812
11.0k
    case 3:
813
16.8k
    case 2:
814
        // (001x) Dynamic Table Size Update
815
        // https://tools.ietf.org/html/rfc7541#section-6.3
816
16.8k
        {
817
16.8k
            uint32_t max_size = 0;
818
16.8k
            ssize_t read_bytes = DecodeInteger(iter, 5, &max_size);
819
16.8k
            if (read_bytes <= 0) {
820
14
                return read_bytes;
821
14
            }
822
16.8k
            if (max_size > H2Settings::DEFAULT_HEADER_TABLE_SIZE) {
823
17
                LOG(ERROR) << "Invalid max_size=" << max_size;
824
17
                return -1;
825
17
            }
826
16.8k
            _decode_table->ResetMaxSize(max_size);
827
16.8k
            return Decode(iter, h);
828
16.8k
        }
829
61
    case 1:
830
        // (0001) Literal Header Field Never Indexed
831
        // https://tools.ietf.org/html/rfc7541#section-6.2.3
832
61
        return DecodeWithKnownPrefix(iter, h, 4);
833
        // TODO: Expose NeverIndex to the caller.
834
98
    case 0:
835
        // (0000) Literal Header Field without Indexing
836
        // https://tools.ietf.org/html/rfc7541#section-6.2.1
837
98
        return DecodeWithKnownPrefix(iter, h, 4);
838
        // TODO: Expose NeverIndex to the caller.
839
0
    default:
840
0
        CHECK(false) << "Can't reach here";
841
0
        return -1;
842
17.4k
    }
843
17.4k
}
844
845
0
void HPacker::Describe(std::ostream& os, const DescribeOptions& opt) const {
846
0
    if (opt.verbose) {
847
0
        os << '\n';
848
0
    }
849
0
    const char sep = (opt.verbose ? '\n' : ' ');
850
0
    os << "encode_table=";
851
0
    if (_encode_table) {
852
0
        _encode_table->Print(os);
853
0
    } else {
854
0
        os << "null";
855
0
    }
856
0
    os << sep << "decode_table=";
857
0
    if (_decode_table) {
858
0
        _decode_table->Print(os);
859
0
    } else {
860
0
        os << "null";
861
0
    }
862
0
    if (opt.verbose) {
863
0
        os << '\n';
864
0
    }
865
0
}
866
867
249
void tolower(std::string* s) {
868
249
    const char* d = s->c_str();
869
21.5k
    for (size_t i = 0; i < s->size(); ++i) {
870
21.3k
        const char c = d[i];
871
21.3k
        const char c2 = butil::ascii_tolower(c);
872
21.3k
        if (c2 != c) {
873
1.21k
            (*s)[i] = c2;
874
1.21k
        }
875
21.3k
    }
876
249
}
877
878
} // namespace brpc