Coverage Report

Created: 2026-05-21 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/trafficserver/lib/ls-hpack/lshpack.cc
Line
Count
Source
1
/** @file
2
3
  Implementations of LiteSpeed functions used by ATS for hpack.
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
/*
25
MIT License
26
27
Copyright (c) 2018 - 2023 LiteSpeed Technologies Inc
28
29
Permission is hereby granted, free of charge, to any person obtaining a copy
30
of this software and associated documentation files (the "Software"), to deal
31
in the Software without restriction, including without limitation the rights
32
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
33
copies of the Software, and to permit persons to whom the Software is
34
furnished to do so, subject to the following conditions:
35
36
The above copyright notice and this permission notice shall be included in all
37
copies or substantial portions of the Software.
38
39
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
42
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
43
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
44
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
45
SOFTWARE.
46
*/
47
48
/** ATS
49
 * This is the minimal implementation from lshpack.c, lshpack.h, and
50
 * lsxpack_header.h required from LiteSpeed to perform hpack given the ATS API
51
 * needs.
52
 */
53
54
#include "huff-tables.h"
55
#include <cstdint>
56
#include <cstring>
57
58
59
namespace litespeed {
60
61
namespace
62
{
63
64
constexpr int64_t LSHPACK_ERR_MORE_BUF = -3;
65
66
struct decode_status {
67
  uint8_t state;
68
  uint8_t eos;
69
};
70
71
enum {
72
  HPACK_HUFFMAN_FLAG_ACCEPTED = 0x01,
73
  HPACK_HUFFMAN_FLAG_SYM      = 0x02,
74
  HPACK_HUFFMAN_FLAG_FAIL     = 0x04,
75
};
76
77
char *
78
hdec_huff_dec4bits(uint8_t src_4bits, char *dst, struct decode_status *status)
79
0
{
80
0
  const struct decode_el cur_dec_code = decode_tables[status->state][src_4bits];
81
0
  if (cur_dec_code.flags & HPACK_HUFFMAN_FLAG_FAIL) {
82
0
    return nullptr; // failed
83
0
  }
84
0
  if (cur_dec_code.flags & HPACK_HUFFMAN_FLAG_SYM) {
85
0
    *dst = cur_dec_code.sym;
86
0
    dst++;
87
0
  }
88
89
0
  status->state = cur_dec_code.state;
90
0
  status->eos   = ((cur_dec_code.flags & HPACK_HUFFMAN_FLAG_ACCEPTED) != 0);
91
0
  return dst;
92
0
}
93
94
} // anonymous namespace
95
96
int64_t
97
lshpack_enc_huff_encode(uint8_t const *src, uint8_t const *const src_end, uint8_t *dst, uint32_t dst_len)
98
0
{
99
0
  uint8_t           *p_dst   = dst;
100
0
  uint8_t           *dst_end = p_dst + dst_len;
101
0
  uintptr_t          bits = 0;
102
0
  unsigned           bits_used = 0, adj;
103
0
  struct encode_el   cur_enc_code;
104
0
  const struct henc *henc;
105
0
  uint16_t           idx;
106
107
0
  while (src + sizeof(bits) * 8 / 5 + sizeof(idx) < src_end && p_dst + sizeof(bits) <= dst_end) {
108
0
    memcpy(&idx, src, 2);
109
0
    henc = &hencs[idx];
110
0
    src  += 2;
111
0
    while (bits_used + henc->lens < sizeof(bits) * 8) {
112
0
      bits      <<= henc->lens;
113
0
      bits       |= henc->code;
114
0
      bits_used  += henc->lens;
115
0
      memcpy(&idx, src, 2);
116
0
      henc = &hencs[idx];
117
0
      src  += 2;
118
0
    }
119
0
    if (henc->lens < 64) {
120
      // Prevent undefined behavior of shifting the full number of bits.
121
0
      if (bits_used > 0) {
122
0
          bits <<= sizeof(bits) * 8 - bits_used;
123
0
      }
124
0
      bits_used   = henc->lens - (sizeof(bits) * 8 - bits_used);
125
0
      bits       |= henc->code >> bits_used;
126
0
#if UINTPTR_MAX == 18446744073709551615ull
127
0
      *p_dst++ = bits >> 56;
128
0
      *p_dst++ = bits >> 48;
129
0
      *p_dst++ = bits >> 40;
130
0
      *p_dst++ = bits >> 32;
131
0
#endif
132
0
      *p_dst++ = bits >> 24;
133
0
      *p_dst++ = bits >> 16;
134
0
      *p_dst++ = bits >> 8;
135
0
      *p_dst++ = bits;
136
0
      bits     = henc->code; /* OK not to clear high bits */
137
0
    } else {
138
0
      src -= 2;
139
0
      break;
140
0
    }
141
0
  }
142
143
0
  while (src != src_end) {
144
0
    cur_enc_code = encode_table[*src++];
145
0
    if (bits_used + cur_enc_code.bits < sizeof(bits) * 8) {
146
0
      bits      <<= cur_enc_code.bits;
147
0
      bits       |= cur_enc_code.code;
148
0
      bits_used  += cur_enc_code.bits;
149
0
      continue;
150
0
    } else if (p_dst + sizeof(bits) <= dst_end) {
151
      // Prevent undefined behavior of shifting the full number of bits.
152
0
      if (bits_used > 0) {
153
0
          bits <<= sizeof(bits) * 8 - bits_used;
154
0
      }
155
0
      bits_used   = cur_enc_code.bits - (sizeof(bits) * 8 - bits_used);
156
0
      bits       |= cur_enc_code.code >> bits_used;
157
0
#if UINTPTR_MAX == 18446744073709551615ull
158
0
      *p_dst++ = bits >> 56;
159
0
      *p_dst++ = bits >> 48;
160
0
      *p_dst++ = bits >> 40;
161
0
      *p_dst++ = bits >> 32;
162
0
#endif
163
0
      *p_dst++ = bits >> 24;
164
0
      *p_dst++ = bits >> 16;
165
0
      *p_dst++ = bits >> 8;
166
0
      *p_dst++ = bits;
167
0
      bits     = cur_enc_code.code; /* OK not to clear high bits */
168
0
    } else {
169
0
      return -1;
170
0
    }
171
0
  }
172
173
0
  adj = bits_used + (-bits_used & 7); /* Round up to 8 */
174
0
  if (bits_used && p_dst + (adj >> 3) <= dst_end) {
175
0
    bits <<= -bits_used & 7;                /* Align to byte boundary */
176
0
    bits  |= ((1 << (-bits_used & 7)) - 1); /* EOF */
177
0
    switch (adj >> 3) {                     /* Write out */
178
0
#if UINTPTR_MAX == 18446744073709551615ull
179
0
    case 8:
180
0
      *p_dst++ = bits >> 56;
181
0
      [[fallthrough]];
182
0
    case 7:
183
0
      *p_dst++ = bits >> 48;
184
0
      [[fallthrough]];
185
0
    case 6:
186
0
      *p_dst++ = bits >> 40;
187
0
      [[fallthrough]];
188
0
    case 5:
189
0
      *p_dst++ = bits >> 32;
190
0
      [[fallthrough]];
191
0
#endif
192
0
    case 4:
193
0
      *p_dst++ = bits >> 24;
194
0
      [[fallthrough]];
195
0
    case 3:
196
0
      *p_dst++ = bits >> 16;
197
0
      [[fallthrough]];
198
0
    case 2:
199
0
      *p_dst++ = bits >> 8;
200
0
      [[fallthrough]];
201
0
    default:
202
0
      *p_dst++ = bits;
203
0
    }
204
0
    return p_dst - dst;
205
0
  } else if (p_dst + (adj >> 3) <= dst_end) {
206
0
    return p_dst - dst;
207
0
  } else {
208
0
    return -1;
209
0
  }
210
0
}
211
212
// Implementation taken from LiteSpeed:
213
// lshpack_dec_huff_decode_full
214
int64_t
215
lshpack_dec_huff_decode_full(uint8_t const *src, uint32_t src_len, char *dst, uint32_t dst_len)
216
0
{
217
0
  const uint8_t       *p_src   = src;
218
0
  const uint8_t *const src_end = src + src_len;
219
0
  char                      *p_dst   = dst;
220
0
  char                      *dst_end = dst + dst_len;
221
0
  struct decode_status       status  = {0, 1};
222
223
0
  while (p_src != src_end) {
224
0
    if (p_dst == dst_end) {
225
0
      return LSHPACK_ERR_MORE_BUF;
226
0
    }
227
0
    if ((p_dst = hdec_huff_dec4bits(*p_src >> 4, p_dst, &status)) == nullptr) {
228
0
      return -1;
229
0
    }
230
0
    if (p_dst == dst_end) {
231
0
      return LSHPACK_ERR_MORE_BUF;
232
0
    }
233
0
    if ((p_dst = hdec_huff_dec4bits(*p_src & 0xf, p_dst, &status)) == nullptr) {
234
0
      return -1;
235
0
    }
236
0
    ++p_src;
237
0
  }
238
239
0
  if (!status.eos) {
240
0
    return -1;
241
0
  }
242
243
0
  return p_dst - dst;
244
0
}
245
246
} // namespace litespeed