Coverage Report

Created: 2026-08-08 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nghttp2/lib/nghttp2_helper.c
Line
Count
Source
1
/*
2
 * nghttp2 - HTTP/2 C Library
3
 *
4
 * Copyright (c) 2012 Tatsuhiro Tsujikawa
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining
7
 * a copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sublicense, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be
15
 * included in all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
#include "nghttp2_helper.h"
26
27
#include <assert.h>
28
#include <string.h>
29
30
#include "nghttp2_net.h"
31
32
9.07k
void nghttp2_put_uint16be(uint8_t *buf, uint16_t n) {
33
9.07k
  uint16_t x = htons(n);
34
9.07k
  memcpy(buf, &x, sizeof(uint16_t));
35
9.07k
}
36
37
76.1k
void nghttp2_put_uint32be(uint8_t *buf, uint32_t n) {
38
76.1k
  uint32_t x = htonl(n);
39
76.1k
  memcpy(buf, &x, sizeof(uint32_t));
40
76.1k
}
41
42
4.86k
uint16_t nghttp2_get_uint16(const uint8_t *data) {
43
4.86k
  uint16_t n;
44
4.86k
  memcpy(&n, data, sizeof(uint16_t));
45
4.86k
  return ntohs(n);
46
4.86k
}
47
48
71.6k
uint32_t nghttp2_get_uint32(const uint8_t *data) {
49
71.6k
  uint32_t n;
50
71.6k
  memcpy(&n, data, sizeof(uint32_t));
51
71.6k
  return ntohl(n);
52
71.6k
}
53
54
/* Generated by gendowncasetbl.py */
55
const uint8_t nghttp2_downcase_tbl[] = {
56
  0x00 /* NUL  */, 0x01 /* SOH  */, 0x02 /* STX  */, 0x03 /* ETX  */,
57
  0x04 /* EOT  */, 0x05 /* ENQ  */, 0x06 /* ACK  */, 0x07 /* BEL  */,
58
  0x08 /* BS   */, 0x09 /* HT   */, 0x0A /* LF   */, 0x0B /* VT   */,
59
  0x0C /* FF   */, 0x0D /* CR   */, 0x0E /* SO   */, 0x0F /* SI   */,
60
  0x10 /* DLE  */, 0x11 /* DC1  */, 0x12 /* DC2  */, 0x13 /* DC3  */,
61
  0x14 /* DC4  */, 0x15 /* NAK  */, 0x16 /* SYN  */, 0x17 /* ETB  */,
62
  0x18 /* CAN  */, 0x19 /* EM   */, 0x1A /* SUB  */, 0x1B /* ESC  */,
63
  0x1C /* FS   */, 0x1D /* GS   */, 0x1E /* RS   */, 0x1F /* US   */,
64
  0x20 /* SPC  */, 0x21 /* !    */, 0x22 /* "    */, 0x23 /* #    */,
65
  0x24 /* $    */, 0x25 /* %    */, 0x26 /* &    */, 0x27 /* '    */,
66
  0x28 /* (    */, 0x29 /* )    */, 0x2A /* *    */, 0x2B /* +    */,
67
  0x2C /* ,    */, 0x2D /* -    */, 0x2E /* .    */, 0x2F /* /    */,
68
  0x30 /* 0    */, 0x31 /* 1    */, 0x32 /* 2    */, 0x33 /* 3    */,
69
  0x34 /* 4    */, 0x35 /* 5    */, 0x36 /* 6    */, 0x37 /* 7    */,
70
  0x38 /* 8    */, 0x39 /* 9    */, 0x3A /* :    */, 0x3B /* ;    */,
71
  0x3C /* <    */, 0x3D /* =    */, 0x3E /* >    */, 0x3F /* ?    */,
72
  0x40 /* @    */, 0x61 /* A    */, 0x62 /* B    */, 0x63 /* C    */,
73
  0x64 /* D    */, 0x65 /* E    */, 0x66 /* F    */, 0x67 /* G    */,
74
  0x68 /* H    */, 0x69 /* I    */, 0x6A /* J    */, 0x6B /* K    */,
75
  0x6C /* L    */, 0x6D /* M    */, 0x6E /* N    */, 0x6F /* O    */,
76
  0x70 /* P    */, 0x71 /* Q    */, 0x72 /* R    */, 0x73 /* S    */,
77
  0x74 /* T    */, 0x75 /* U    */, 0x76 /* V    */, 0x77 /* W    */,
78
  0x78 /* X    */, 0x79 /* Y    */, 0x7A /* Z    */, 0x5B /* [    */,
79
  0x5C /* \    */, 0x5D /* ]    */, 0x5E /* ^    */, 0x5F /* _    */,
80
  0x60 /* `    */, 0x61 /* a    */, 0x62 /* b    */, 0x63 /* c    */,
81
  0x64 /* d    */, 0x65 /* e    */, 0x66 /* f    */, 0x67 /* g    */,
82
  0x68 /* h    */, 0x69 /* i    */, 0x6A /* j    */, 0x6B /* k    */,
83
  0x6C /* l    */, 0x6D /* m    */, 0x6E /* n    */, 0x6F /* o    */,
84
  0x70 /* p    */, 0x71 /* q    */, 0x72 /* r    */, 0x73 /* s    */,
85
  0x74 /* t    */, 0x75 /* u    */, 0x76 /* v    */, 0x77 /* w    */,
86
  0x78 /* x    */, 0x79 /* y    */, 0x7A /* z    */, 0x7B /* {    */,
87
  0x7C /* |    */, 0x7D /* }    */, 0x7E /* ~    */, 0x7F /* DEL  */,
88
  0x80 /* 0x80 */, 0x81 /* 0x81 */, 0x82 /* 0x82 */, 0x83 /* 0x83 */,
89
  0x84 /* 0x84 */, 0x85 /* 0x85 */, 0x86 /* 0x86 */, 0x87 /* 0x87 */,
90
  0x88 /* 0x88 */, 0x89 /* 0x89 */, 0x8A /* 0x8A */, 0x8B /* 0x8B */,
91
  0x8C /* 0x8C */, 0x8D /* 0x8D */, 0x8E /* 0x8E */, 0x8F /* 0x8F */,
92
  0x90 /* 0x90 */, 0x91 /* 0x91 */, 0x92 /* 0x92 */, 0x93 /* 0x93 */,
93
  0x94 /* 0x94 */, 0x95 /* 0x95 */, 0x96 /* 0x96 */, 0x97 /* 0x97 */,
94
  0x98 /* 0x98 */, 0x99 /* 0x99 */, 0x9A /* 0x9A */, 0x9B /* 0x9B */,
95
  0x9C /* 0x9C */, 0x9D /* 0x9D */, 0x9E /* 0x9E */, 0x9F /* 0x9F */,
96
  0xA0 /* 0xA0 */, 0xA1 /* 0xA1 */, 0xA2 /* 0xA2 */, 0xA3 /* 0xA3 */,
97
  0xA4 /* 0xA4 */, 0xA5 /* 0xA5 */, 0xA6 /* 0xA6 */, 0xA7 /* 0xA7 */,
98
  0xA8 /* 0xA8 */, 0xA9 /* 0xA9 */, 0xAA /* 0xAA */, 0xAB /* 0xAB */,
99
  0xAC /* 0xAC */, 0xAD /* 0xAD */, 0xAE /* 0xAE */, 0xAF /* 0xAF */,
100
  0xB0 /* 0xB0 */, 0xB1 /* 0xB1 */, 0xB2 /* 0xB2 */, 0xB3 /* 0xB3 */,
101
  0xB4 /* 0xB4 */, 0xB5 /* 0xB5 */, 0xB6 /* 0xB6 */, 0xB7 /* 0xB7 */,
102
  0xB8 /* 0xB8 */, 0xB9 /* 0xB9 */, 0xBA /* 0xBA */, 0xBB /* 0xBB */,
103
  0xBC /* 0xBC */, 0xBD /* 0xBD */, 0xBE /* 0xBE */, 0xBF /* 0xBF */,
104
  0xC0 /* 0xC0 */, 0xC1 /* 0xC1 */, 0xC2 /* 0xC2 */, 0xC3 /* 0xC3 */,
105
  0xC4 /* 0xC4 */, 0xC5 /* 0xC5 */, 0xC6 /* 0xC6 */, 0xC7 /* 0xC7 */,
106
  0xC8 /* 0xC8 */, 0xC9 /* 0xC9 */, 0xCA /* 0xCA */, 0xCB /* 0xCB */,
107
  0xCC /* 0xCC */, 0xCD /* 0xCD */, 0xCE /* 0xCE */, 0xCF /* 0xCF */,
108
  0xD0 /* 0xD0 */, 0xD1 /* 0xD1 */, 0xD2 /* 0xD2 */, 0xD3 /* 0xD3 */,
109
  0xD4 /* 0xD4 */, 0xD5 /* 0xD5 */, 0xD6 /* 0xD6 */, 0xD7 /* 0xD7 */,
110
  0xD8 /* 0xD8 */, 0xD9 /* 0xD9 */, 0xDA /* 0xDA */, 0xDB /* 0xDB */,
111
  0xDC /* 0xDC */, 0xDD /* 0xDD */, 0xDE /* 0xDE */, 0xDF /* 0xDF */,
112
  0xE0 /* 0xE0 */, 0xE1 /* 0xE1 */, 0xE2 /* 0xE2 */, 0xE3 /* 0xE3 */,
113
  0xE4 /* 0xE4 */, 0xE5 /* 0xE5 */, 0xE6 /* 0xE6 */, 0xE7 /* 0xE7 */,
114
  0xE8 /* 0xE8 */, 0xE9 /* 0xE9 */, 0xEA /* 0xEA */, 0xEB /* 0xEB */,
115
  0xEC /* 0xEC */, 0xED /* 0xED */, 0xEE /* 0xEE */, 0xEF /* 0xEF */,
116
  0xF0 /* 0xF0 */, 0xF1 /* 0xF1 */, 0xF2 /* 0xF2 */, 0xF3 /* 0xF3 */,
117
  0xF4 /* 0xF4 */, 0xF5 /* 0xF5 */, 0xF6 /* 0xF6 */, 0xF7 /* 0xF7 */,
118
  0xF8 /* 0xF8 */, 0xF9 /* 0xF9 */, 0xFA /* 0xFA */, 0xFB /* 0xFB */,
119
  0xFC /* 0xFC */, 0xFD /* 0xFD */, 0xFE /* 0xFE */, 0xFF /* 0xFF */,
120
};
121
122
0
void nghttp2_downcase(uint8_t *s, size_t len) {
123
0
  size_t i;
124
0
  for (i = 0; i < len; ++i) {
125
0
    s[i] = nghttp2_downcase_byte(s[i]);
126
0
  }
127
0
}
128
129
/*
130
 *   local_window_size
131
 *   ^  *
132
 *   |  *    recv_window_size
133
 *   |  *  * ^
134
 *   |  *  * |
135
 *  0+++++++++
136
 *   |  *  *   \
137
 *   |  *  *   | This rage is hidden in flow control.  But it must be
138
 *   v  *  *   / kept in order to restore it when window size is enlarged.
139
 *   recv_reduction
140
 *   (+ for negative direction)
141
 *
142
 *   recv_window_size could be negative if we decrease
143
 *   local_window_size more than recv_window_size:
144
 *
145
 *   local_window_size
146
 *   ^  *
147
 *   |  *
148
 *   |  *
149
 *   0++++++++
150
 *   |  *    ^ recv_window_size (negative)
151
 *   |  *    |
152
 *   v  *  *
153
 *   recv_reduction
154
 */
155
int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
156
                                     int32_t *recv_window_size_ptr,
157
                                     int32_t *recv_reduction_ptr,
158
0
                                     int32_t *delta_ptr) {
159
0
  if (*delta_ptr > 0) {
160
0
    int32_t recv_reduction_delta;
161
0
    int32_t delta;
162
0
    int32_t new_recv_window_size =
163
0
      nghttp2_max_int32(0, *recv_window_size_ptr) - *delta_ptr;
164
165
0
    if (new_recv_window_size >= 0) {
166
0
      *recv_window_size_ptr = new_recv_window_size;
167
0
      return 0;
168
0
    }
169
170
0
    delta = -new_recv_window_size;
171
172
    /* The delta size is strictly more than received bytes. Increase
173
       local_window_size by that difference |delta|. */
174
0
    if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) {
175
0
      return NGHTTP2_ERR_FLOW_CONTROL;
176
0
    }
177
0
    *local_window_size_ptr += delta;
178
    /* If there is recv_reduction due to earlier window_size
179
       reduction, we have to adjust it too. */
180
0
    recv_reduction_delta = nghttp2_min_int32(*recv_reduction_ptr, delta);
181
0
    *recv_reduction_ptr -= recv_reduction_delta;
182
0
    if (*recv_window_size_ptr < 0) {
183
0
      *recv_window_size_ptr += recv_reduction_delta;
184
0
    } else {
185
      /* If *recv_window_size_ptr > 0, then those bytes are going to
186
         be returned to the remote peer (by WINDOW_UPDATE with the
187
         adjusted *delta_ptr), so it is effectively 0 now.  We set to
188
         *recv_reduction_delta, because caller does not take into
189
         account it in *delta_ptr. */
190
0
      *recv_window_size_ptr = recv_reduction_delta;
191
0
    }
192
    /* recv_reduction_delta must be paid from *delta_ptr, since it was
193
       added in window size reduction (see below). */
194
0
    *delta_ptr -= recv_reduction_delta;
195
196
0
    return 0;
197
0
  }
198
199
0
  if (*local_window_size_ptr + *delta_ptr < 0 ||
200
0
      *recv_window_size_ptr < INT32_MIN - *delta_ptr ||
201
0
      *recv_reduction_ptr > INT32_MAX + *delta_ptr) {
202
0
    return NGHTTP2_ERR_FLOW_CONTROL;
203
0
  }
204
  /* Decreasing local window size. Note that we achieve this without
205
     noticing to the remote peer. To do this, we cut
206
     recv_window_size by -delta. This means that we don't send
207
     WINDOW_UPDATE for -delta bytes. */
208
0
  *local_window_size_ptr += *delta_ptr;
209
0
  *recv_window_size_ptr += *delta_ptr;
210
0
  *recv_reduction_ptr -= *delta_ptr;
211
0
  *delta_ptr = 0;
212
213
0
  return 0;
214
0
}
215
216
int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
217
                                       int32_t *recv_window_size_ptr,
218
                                       int32_t *recv_reduction_ptr,
219
0
                                       int32_t *delta_ptr) {
220
0
  int32_t recv_reduction_delta;
221
0
  int32_t delta;
222
223
0
  delta = *delta_ptr;
224
225
0
  assert(delta >= 0);
226
227
  /* The delta size is strictly more than received bytes. Increase
228
     local_window_size by that difference |delta|. */
229
0
  if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) {
230
0
    return NGHTTP2_ERR_FLOW_CONTROL;
231
0
  }
232
233
0
  *local_window_size_ptr += delta;
234
  /* If there is recv_reduction due to earlier window_size
235
     reduction, we have to adjust it too. */
236
0
  recv_reduction_delta = nghttp2_min_int32(*recv_reduction_ptr, delta);
237
0
  *recv_reduction_ptr -= recv_reduction_delta;
238
239
0
  *recv_window_size_ptr += recv_reduction_delta;
240
241
  /* recv_reduction_delta must be paid from *delta_ptr, since it was
242
     added in window size reduction (see below). */
243
0
  *delta_ptr -= recv_reduction_delta;
244
245
0
  return 0;
246
0
}
247
248
int nghttp2_should_send_window_update(int32_t local_window_size,
249
1.68k
                                      int32_t recv_window_size) {
250
1.68k
  return recv_window_size > 0 && recv_window_size >= local_window_size / 2;
251
1.68k
}
252
253
0
const char *nghttp2_strerror(int error_code) {
254
0
  switch (error_code) {
255
0
  case 0:
256
0
    return "Success";
257
0
  case NGHTTP2_ERR_INVALID_ARGUMENT:
258
0
    return "Invalid argument";
259
0
  case NGHTTP2_ERR_BUFFER_ERROR:
260
0
    return "Out of buffer space";
261
0
  case NGHTTP2_ERR_UNSUPPORTED_VERSION:
262
0
    return "Unsupported SPDY version";
263
0
  case NGHTTP2_ERR_WOULDBLOCK:
264
0
    return "Operation would block";
265
0
  case NGHTTP2_ERR_PROTO:
266
0
    return "Protocol error";
267
0
  case NGHTTP2_ERR_INVALID_FRAME:
268
0
    return "Invalid frame octets";
269
0
  case NGHTTP2_ERR_EOF:
270
0
    return "EOF";
271
0
  case NGHTTP2_ERR_DEFERRED:
272
0
    return "Data transfer deferred";
273
0
  case NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE:
274
0
    return "No more Stream ID available";
275
0
  case NGHTTP2_ERR_STREAM_CLOSED:
276
0
    return "Stream was already closed or invalid";
277
0
  case NGHTTP2_ERR_STREAM_CLOSING:
278
0
    return "Stream is closing";
279
0
  case NGHTTP2_ERR_STREAM_SHUT_WR:
280
0
    return "The transmission is not allowed for this stream";
281
0
  case NGHTTP2_ERR_INVALID_STREAM_ID:
282
0
    return "Stream ID is invalid";
283
0
  case NGHTTP2_ERR_INVALID_STREAM_STATE:
284
0
    return "Invalid stream state";
285
0
  case NGHTTP2_ERR_DEFERRED_DATA_EXIST:
286
0
    return "Another DATA frame has already been deferred";
287
0
  case NGHTTP2_ERR_START_STREAM_NOT_ALLOWED:
288
0
    return "request HEADERS is not allowed";
289
0
  case NGHTTP2_ERR_GOAWAY_ALREADY_SENT:
290
0
    return "GOAWAY has already been sent";
291
0
  case NGHTTP2_ERR_INVALID_HEADER_BLOCK:
292
0
    return "Invalid header block";
293
0
  case NGHTTP2_ERR_INVALID_STATE:
294
0
    return "Invalid state";
295
0
  case NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE:
296
0
    return "The user callback function failed due to the temporal error";
297
0
  case NGHTTP2_ERR_FRAME_SIZE_ERROR:
298
0
    return "The length of the frame is invalid";
299
0
  case NGHTTP2_ERR_HEADER_COMP:
300
0
    return "Header compression/decompression error";
301
0
  case NGHTTP2_ERR_FLOW_CONTROL:
302
0
    return "Flow control error";
303
0
  case NGHTTP2_ERR_INSUFF_BUFSIZE:
304
0
    return "Insufficient buffer size given to function";
305
0
  case NGHTTP2_ERR_PAUSE:
306
0
    return "Callback was paused by the application";
307
0
  case NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS:
308
0
    return "Too many inflight SETTINGS";
309
0
  case NGHTTP2_ERR_PUSH_DISABLED:
310
0
    return "Server push is disabled by peer";
311
0
  case NGHTTP2_ERR_DATA_EXIST:
312
0
    return "DATA or HEADERS frame has already been submitted for the stream";
313
0
  case NGHTTP2_ERR_SESSION_CLOSING:
314
0
    return "The current session is closing";
315
0
  case NGHTTP2_ERR_HTTP_HEADER:
316
0
    return "Invalid HTTP header field was received";
317
0
  case NGHTTP2_ERR_HTTP_MESSAGING:
318
0
    return "Violation in HTTP messaging rule";
319
0
  case NGHTTP2_ERR_REFUSED_STREAM:
320
0
    return "Stream was refused";
321
0
  case NGHTTP2_ERR_INTERNAL:
322
0
    return "Internal error";
323
0
  case NGHTTP2_ERR_CANCEL:
324
0
    return "Cancel";
325
0
  case NGHTTP2_ERR_SETTINGS_EXPECTED:
326
0
    return "When a local endpoint expects to receive SETTINGS frame, it "
327
0
           "receives an other type of frame";
328
0
  case NGHTTP2_ERR_NOMEM:
329
0
    return "Out of memory";
330
0
  case NGHTTP2_ERR_CALLBACK_FAILURE:
331
0
    return "The user callback function failed";
332
0
  case NGHTTP2_ERR_BAD_CLIENT_MAGIC:
333
0
    return "Received bad client magic byte string";
334
0
  case NGHTTP2_ERR_FLOODED:
335
0
    return "Flooding was detected in this HTTP/2 session, and it must be "
336
0
           "closed";
337
0
  case NGHTTP2_ERR_TOO_MANY_SETTINGS:
338
0
    return "SETTINGS frame contained more than the maximum allowed entries";
339
0
  case NGHTTP2_ERR_TOO_MANY_CONTINUATIONS:
340
0
    return "Too many CONTINUATION frames following a HEADER frame";
341
0
  default:
342
0
    return "Unknown error code";
343
0
  }
344
0
}
345
346
static const uint8_t VALID_HD_NAME_CHARS[256] = {
347
  ['!'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['*'] = 1,
348
  ['+'] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1,  ['3'] = 1,
349
  ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,  ['A'] = 2,
350
  ['B'] = 2, ['C'] = 2, ['D'] = 2, ['E'] = 2, ['F'] = 2, ['G'] = 2,  ['H'] = 2,
351
  ['I'] = 2, ['J'] = 2, ['K'] = 2, ['L'] = 2, ['M'] = 2, ['N'] = 2,  ['O'] = 2,
352
  ['P'] = 2, ['Q'] = 2, ['R'] = 2, ['S'] = 2, ['T'] = 2, ['U'] = 2,  ['V'] = 2,
353
  ['W'] = 2, ['X'] = 2, ['Y'] = 2, ['Z'] = 2, ['^'] = 1, ['_'] = 1,  ['`'] = 1,
354
  ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1,  ['g'] = 1,
355
  ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1,  ['n'] = 1,
356
  ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1,  ['u'] = 1,
357
  ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['|'] = 1,  ['~'] = 1,
358
};
359
360
0
int nghttp2_check_header_name(const uint8_t *name, size_t len) {
361
0
  const uint8_t *last;
362
0
  if (len == 0) {
363
0
    return 0;
364
0
  }
365
0
  if (*name == ':') {
366
0
    if (len == 1) {
367
0
      return 0;
368
0
    }
369
0
    ++name;
370
0
    --len;
371
0
  }
372
0
  for (last = name + len; name != last; ++name) {
373
0
    if (VALID_HD_NAME_CHARS[*name] != 1) {
374
0
      return 0;
375
0
    }
376
0
  }
377
0
  return 1;
378
0
}
379
380
30.9k
int nghttp2_check_nonempty_header_name(const uint8_t *name, size_t len) {
381
30.9k
  const uint8_t *last;
382
30.9k
  int rv;
383
384
318k
  for (last = name + len; name != last; ++name) {
385
290k
    rv = VALID_HD_NAME_CHARS[*name];
386
290k
    if (rv != 1) {
387
3.06k
      return rv;
388
3.06k
    }
389
290k
  }
390
391
27.9k
  return 1;
392
30.9k
}
393
394
static const uint8_t VALID_HD_VALUE_CHARS[256] = {
395
  ['\t'] = 1, [' '] = 1,  ['!'] = 1,  ['"'] = 1,  ['#'] = 1,  ['$'] = 1,
396
  ['%'] = 1,  ['&'] = 1,  ['\''] = 1, ['('] = 1,  [')'] = 1,  ['*'] = 1,
397
  ['+'] = 1,  [','] = 1,  ['-'] = 1,  ['.'] = 1,  ['/'] = 1,  ['0'] = 1,
398
  ['1'] = 1,  ['2'] = 1,  ['3'] = 1,  ['4'] = 1,  ['5'] = 1,  ['6'] = 1,
399
  ['7'] = 1,  ['8'] = 1,  ['9'] = 1,  [':'] = 1,  [';'] = 1,  ['<'] = 1,
400
  ['='] = 1,  ['>'] = 1,  ['?'] = 1,  ['@'] = 1,  ['A'] = 1,  ['B'] = 1,
401
  ['C'] = 1,  ['D'] = 1,  ['E'] = 1,  ['F'] = 1,  ['G'] = 1,  ['H'] = 1,
402
  ['I'] = 1,  ['J'] = 1,  ['K'] = 1,  ['L'] = 1,  ['M'] = 1,  ['N'] = 1,
403
  ['O'] = 1,  ['P'] = 1,  ['Q'] = 1,  ['R'] = 1,  ['S'] = 1,  ['T'] = 1,
404
  ['U'] = 1,  ['V'] = 1,  ['W'] = 1,  ['X'] = 1,  ['Y'] = 1,  ['Z'] = 1,
405
  ['['] = 1,  ['\\'] = 1, [']'] = 1,  ['^'] = 1,  ['_'] = 1,  ['`'] = 1,
406
  ['a'] = 1,  ['b'] = 1,  ['c'] = 1,  ['d'] = 1,  ['e'] = 1,  ['f'] = 1,
407
  ['g'] = 1,  ['h'] = 1,  ['i'] = 1,  ['j'] = 1,  ['k'] = 1,  ['l'] = 1,
408
  ['m'] = 1,  ['n'] = 1,  ['o'] = 1,  ['p'] = 1,  ['q'] = 1,  ['r'] = 1,
409
  ['s'] = 1,  ['t'] = 1,  ['u'] = 1,  ['v'] = 1,  ['w'] = 1,  ['x'] = 1,
410
  ['y'] = 1,  ['z'] = 1,  ['{'] = 1,  ['|'] = 1,  ['}'] = 1,  ['~'] = 1,
411
  [0x80] = 1, [0x81] = 1, [0x82] = 1, [0x83] = 1, [0x84] = 1, [0x85] = 1,
412
  [0x86] = 1, [0x87] = 1, [0x88] = 1, [0x89] = 1, [0x8A] = 1, [0x8B] = 1,
413
  [0x8C] = 1, [0x8D] = 1, [0x8E] = 1, [0x8F] = 1, [0x90] = 1, [0x91] = 1,
414
  [0x92] = 1, [0x93] = 1, [0x94] = 1, [0x95] = 1, [0x96] = 1, [0x97] = 1,
415
  [0x98] = 1, [0x99] = 1, [0x9A] = 1, [0x9B] = 1, [0x9C] = 1, [0x9D] = 1,
416
  [0x9E] = 1, [0x9F] = 1, [0xA0] = 1, [0xA1] = 1, [0xA2] = 1, [0xA3] = 1,
417
  [0xA4] = 1, [0xA5] = 1, [0xA6] = 1, [0xA7] = 1, [0xA8] = 1, [0xA9] = 1,
418
  [0xAA] = 1, [0xAB] = 1, [0xAC] = 1, [0xAD] = 1, [0xAE] = 1, [0xAF] = 1,
419
  [0xB0] = 1, [0xB1] = 1, [0xB2] = 1, [0xB3] = 1, [0xB4] = 1, [0xB5] = 1,
420
  [0xB6] = 1, [0xB7] = 1, [0xB8] = 1, [0xB9] = 1, [0xBA] = 1, [0xBB] = 1,
421
  [0xBC] = 1, [0xBD] = 1, [0xBE] = 1, [0xBF] = 1, [0xC0] = 1, [0xC1] = 1,
422
  [0xC2] = 1, [0xC3] = 1, [0xC4] = 1, [0xC5] = 1, [0xC6] = 1, [0xC7] = 1,
423
  [0xC8] = 1, [0xC9] = 1, [0xCA] = 1, [0xCB] = 1, [0xCC] = 1, [0xCD] = 1,
424
  [0xCE] = 1, [0xCF] = 1, [0xD0] = 1, [0xD1] = 1, [0xD2] = 1, [0xD3] = 1,
425
  [0xD4] = 1, [0xD5] = 1, [0xD6] = 1, [0xD7] = 1, [0xD8] = 1, [0xD9] = 1,
426
  [0xDA] = 1, [0xDB] = 1, [0xDC] = 1, [0xDD] = 1, [0xDE] = 1, [0xDF] = 1,
427
  [0xE0] = 1, [0xE1] = 1, [0xE2] = 1, [0xE3] = 1, [0xE4] = 1, [0xE5] = 1,
428
  [0xE6] = 1, [0xE7] = 1, [0xE8] = 1, [0xE9] = 1, [0xEA] = 1, [0xEB] = 1,
429
  [0xEC] = 1, [0xED] = 1, [0xEE] = 1, [0xEF] = 1, [0xF0] = 1, [0xF1] = 1,
430
  [0xF2] = 1, [0xF3] = 1, [0xF4] = 1, [0xF5] = 1, [0xF6] = 1, [0xF7] = 1,
431
  [0xF8] = 1, [0xF9] = 1, [0xFA] = 1, [0xFB] = 1, [0xFC] = 1, [0xFD] = 1,
432
  [0xFE] = 1, [0xFF] = 1,
433
};
434
435
10.8k
int nghttp2_check_header_value(const uint8_t *value, size_t len) {
436
10.8k
  const uint8_t *last;
437
132k
  for (last = value + len; value != last; ++value) {
438
122k
    if (!VALID_HD_VALUE_CHARS[*value]) {
439
338
      return 0;
440
338
    }
441
122k
  }
442
10.4k
  return 1;
443
10.8k
}
444
445
25.0k
int nghttp2_check_header_value_rfc9113(const uint8_t *value, size_t len) {
446
25.0k
  if (len == 0) {
447
13.2k
    return 1;
448
13.2k
  }
449
450
11.7k
  if (*value == ' ' || *value == '\t' || *(value + len - 1) == ' ' ||
451
11.0k
      *(value + len - 1) == '\t') {
452
969
    return 0;
453
969
  }
454
455
10.8k
  return nghttp2_check_header_value(value, len);
456
11.7k
}
457
458
static const uint8_t VALID_METHOD_CHARS[256] = {
459
  ['!'] = 1, ['#'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['*'] = 1,
460
  ['+'] = 1, ['-'] = 1, ['.'] = 1, ['0'] = 1, ['1'] = 1, ['2'] = 1,  ['3'] = 1,
461
  ['4'] = 1, ['5'] = 1, ['6'] = 1, ['7'] = 1, ['8'] = 1, ['9'] = 1,  ['A'] = 1,
462
  ['B'] = 1, ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1,  ['H'] = 1,
463
  ['I'] = 1, ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1,  ['O'] = 1,
464
  ['P'] = 1, ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1,  ['V'] = 1,
465
  ['W'] = 1, ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['^'] = 1, ['_'] = 1,  ['`'] = 1,
466
  ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1,  ['g'] = 1,
467
  ['h'] = 1, ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1,  ['n'] = 1,
468
  ['o'] = 1, ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1,  ['u'] = 1,
469
  ['v'] = 1, ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['|'] = 1,  ['~'] = 1,
470
};
471
472
3.36k
int nghttp2_check_method(const uint8_t *value, size_t len) {
473
3.36k
  const uint8_t *last;
474
3.36k
  if (len == 0) {
475
86
    return 0;
476
86
  }
477
16.9k
  for (last = value + len; value != last; ++value) {
478
13.7k
    if (!VALID_METHOD_CHARS[*value]) {
479
43
      return 0;
480
43
    }
481
13.7k
  }
482
3.23k
  return 1;
483
3.28k
}
484
485
static const uint8_t VALID_PATH_CHARS[256] = {
486
  ['!'] = 1,  ['"'] = 1,  ['#'] = 1,  ['$'] = 1,  ['%'] = 1,  ['&'] = 1,
487
  ['\''] = 1, ['('] = 1,  [')'] = 1,  ['*'] = 1,  ['+'] = 1,  [','] = 1,
488
  ['-'] = 1,  ['.'] = 1,  ['/'] = 1,  ['0'] = 1,  ['1'] = 1,  ['2'] = 1,
489
  ['3'] = 1,  ['4'] = 1,  ['5'] = 1,  ['6'] = 1,  ['7'] = 1,  ['8'] = 1,
490
  ['9'] = 1,  [':'] = 1,  [';'] = 1,  ['<'] = 1,  ['='] = 1,  ['>'] = 1,
491
  ['?'] = 1,  ['@'] = 1,  ['A'] = 1,  ['B'] = 1,  ['C'] = 1,  ['D'] = 1,
492
  ['E'] = 1,  ['F'] = 1,  ['G'] = 1,  ['H'] = 1,  ['I'] = 1,  ['J'] = 1,
493
  ['K'] = 1,  ['L'] = 1,  ['M'] = 1,  ['N'] = 1,  ['O'] = 1,  ['P'] = 1,
494
  ['Q'] = 1,  ['R'] = 1,  ['S'] = 1,  ['T'] = 1,  ['U'] = 1,  ['V'] = 1,
495
  ['W'] = 1,  ['X'] = 1,  ['Y'] = 1,  ['Z'] = 1,  ['['] = 1,  ['\\'] = 1,
496
  [']'] = 1,  ['^'] = 1,  ['_'] = 1,  ['`'] = 1,  ['a'] = 1,  ['b'] = 1,
497
  ['c'] = 1,  ['d'] = 1,  ['e'] = 1,  ['f'] = 1,  ['g'] = 1,  ['h'] = 1,
498
  ['i'] = 1,  ['j'] = 1,  ['k'] = 1,  ['l'] = 1,  ['m'] = 1,  ['n'] = 1,
499
  ['o'] = 1,  ['p'] = 1,  ['q'] = 1,  ['r'] = 1,  ['s'] = 1,  ['t'] = 1,
500
  ['u'] = 1,  ['v'] = 1,  ['w'] = 1,  ['x'] = 1,  ['y'] = 1,  ['z'] = 1,
501
  ['{'] = 1,  ['|'] = 1,  ['}'] = 1,  ['~'] = 1,  [0x80] = 1, [0x81] = 1,
502
  [0x82] = 1, [0x83] = 1, [0x84] = 1, [0x85] = 1, [0x86] = 1, [0x87] = 1,
503
  [0x88] = 1, [0x89] = 1, [0x8A] = 1, [0x8B] = 1, [0x8C] = 1, [0x8D] = 1,
504
  [0x8E] = 1, [0x8F] = 1, [0x90] = 1, [0x91] = 1, [0x92] = 1, [0x93] = 1,
505
  [0x94] = 1, [0x95] = 1, [0x96] = 1, [0x97] = 1, [0x98] = 1, [0x99] = 1,
506
  [0x9A] = 1, [0x9B] = 1, [0x9C] = 1, [0x9D] = 1, [0x9E] = 1, [0x9F] = 1,
507
  [0xA0] = 1, [0xA1] = 1, [0xA2] = 1, [0xA3] = 1, [0xA4] = 1, [0xA5] = 1,
508
  [0xA6] = 1, [0xA7] = 1, [0xA8] = 1, [0xA9] = 1, [0xAA] = 1, [0xAB] = 1,
509
  [0xAC] = 1, [0xAD] = 1, [0xAE] = 1, [0xAF] = 1, [0xB0] = 1, [0xB1] = 1,
510
  [0xB2] = 1, [0xB3] = 1, [0xB4] = 1, [0xB5] = 1, [0xB6] = 1, [0xB7] = 1,
511
  [0xB8] = 1, [0xB9] = 1, [0xBA] = 1, [0xBB] = 1, [0xBC] = 1, [0xBD] = 1,
512
  [0xBE] = 1, [0xBF] = 1, [0xC0] = 1, [0xC1] = 1, [0xC2] = 1, [0xC3] = 1,
513
  [0xC4] = 1, [0xC5] = 1, [0xC6] = 1, [0xC7] = 1, [0xC8] = 1, [0xC9] = 1,
514
  [0xCA] = 1, [0xCB] = 1, [0xCC] = 1, [0xCD] = 1, [0xCE] = 1, [0xCF] = 1,
515
  [0xD0] = 1, [0xD1] = 1, [0xD2] = 1, [0xD3] = 1, [0xD4] = 1, [0xD5] = 1,
516
  [0xD6] = 1, [0xD7] = 1, [0xD8] = 1, [0xD9] = 1, [0xDA] = 1, [0xDB] = 1,
517
  [0xDC] = 1, [0xDD] = 1, [0xDE] = 1, [0xDF] = 1, [0xE0] = 1, [0xE1] = 1,
518
  [0xE2] = 1, [0xE3] = 1, [0xE4] = 1, [0xE5] = 1, [0xE6] = 1, [0xE7] = 1,
519
  [0xE8] = 1, [0xE9] = 1, [0xEA] = 1, [0xEB] = 1, [0xEC] = 1, [0xED] = 1,
520
  [0xEE] = 1, [0xEF] = 1, [0xF0] = 1, [0xF1] = 1, [0xF2] = 1, [0xF3] = 1,
521
  [0xF4] = 1, [0xF5] = 1, [0xF6] = 1, [0xF7] = 1, [0xF8] = 1, [0xF9] = 1,
522
  [0xFA] = 1, [0xFB] = 1, [0xFC] = 1, [0xFD] = 1, [0xFE] = 1, [0xFF] = 1,
523
};
524
525
3.10k
int nghttp2_check_path(const uint8_t *value, size_t len) {
526
3.10k
  const uint8_t *last;
527
13.6k
  for (last = value + len; value != last; ++value) {
528
10.5k
    if (!VALID_PATH_CHARS[*value]) {
529
38
      return 0;
530
38
    }
531
10.5k
  }
532
3.07k
  return 1;
533
3.10k
}
534
535
static const uint8_t VALID_AUTHORITY_CHARS[256] = {
536
  ['!'] = 1, ['$'] = 1, ['%'] = 1, ['&'] = 1, ['\''] = 1, ['('] = 1, [')'] = 1,
537
  ['*'] = 1, ['+'] = 1, [','] = 1, ['-'] = 1, ['.'] = 1,  ['0'] = 1, ['1'] = 1,
538
  ['2'] = 1, ['3'] = 1, ['4'] = 1, ['5'] = 1, ['6'] = 1,  ['7'] = 1, ['8'] = 1,
539
  ['9'] = 1, [':'] = 1, [';'] = 1, ['='] = 1, ['@'] = 1,  ['A'] = 1, ['B'] = 1,
540
  ['C'] = 1, ['D'] = 1, ['E'] = 1, ['F'] = 1, ['G'] = 1,  ['H'] = 1, ['I'] = 1,
541
  ['J'] = 1, ['K'] = 1, ['L'] = 1, ['M'] = 1, ['N'] = 1,  ['O'] = 1, ['P'] = 1,
542
  ['Q'] = 1, ['R'] = 1, ['S'] = 1, ['T'] = 1, ['U'] = 1,  ['V'] = 1, ['W'] = 1,
543
  ['X'] = 1, ['Y'] = 1, ['Z'] = 1, ['['] = 1, [']'] = 1,  ['_'] = 1, ['a'] = 1,
544
  ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1,  ['g'] = 1, ['h'] = 1,
545
  ['i'] = 1, ['j'] = 1, ['k'] = 1, ['l'] = 1, ['m'] = 1,  ['n'] = 1, ['o'] = 1,
546
  ['p'] = 1, ['q'] = 1, ['r'] = 1, ['s'] = 1, ['t'] = 1,  ['u'] = 1, ['v'] = 1,
547
  ['w'] = 1, ['x'] = 1, ['y'] = 1, ['z'] = 1, ['~'] = 1,
548
};
549
550
0
int nghttp2_check_authority(const uint8_t *value, size_t len) {
551
0
  const uint8_t *last;
552
0
  for (last = value + len; value != last; ++value) {
553
0
    if (!VALID_AUTHORITY_CHARS[*value]) {
554
0
      return 0;
555
0
    }
556
0
  }
557
0
  return 1;
558
0
}
559
560
91.2k
uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len) {
561
91.2k
  if (len == 0) {
562
38.2k
    return dest;
563
38.2k
  }
564
565
52.9k
  memcpy(dest, src, len);
566
567
52.9k
  return dest + len;
568
91.2k
}
569
570
0
const char *nghttp2_http2_strerror(uint32_t error_code) {
571
0
  switch (error_code) {
572
0
  case NGHTTP2_NO_ERROR:
573
0
    return "NO_ERROR";
574
0
  case NGHTTP2_PROTOCOL_ERROR:
575
0
    return "PROTOCOL_ERROR";
576
0
  case NGHTTP2_INTERNAL_ERROR:
577
0
    return "INTERNAL_ERROR";
578
0
  case NGHTTP2_FLOW_CONTROL_ERROR:
579
0
    return "FLOW_CONTROL_ERROR";
580
0
  case NGHTTP2_SETTINGS_TIMEOUT:
581
0
    return "SETTINGS_TIMEOUT";
582
0
  case NGHTTP2_STREAM_CLOSED:
583
0
    return "STREAM_CLOSED";
584
0
  case NGHTTP2_FRAME_SIZE_ERROR:
585
0
    return "FRAME_SIZE_ERROR";
586
0
  case NGHTTP2_REFUSED_STREAM:
587
0
    return "REFUSED_STREAM";
588
0
  case NGHTTP2_CANCEL:
589
0
    return "CANCEL";
590
0
  case NGHTTP2_COMPRESSION_ERROR:
591
0
    return "COMPRESSION_ERROR";
592
0
  case NGHTTP2_CONNECT_ERROR:
593
0
    return "CONNECT_ERROR";
594
0
  case NGHTTP2_ENHANCE_YOUR_CALM:
595
0
    return "ENHANCE_YOUR_CALM";
596
0
  case NGHTTP2_INADEQUATE_SECURITY:
597
0
    return "INADEQUATE_SECURITY";
598
0
  case NGHTTP2_HTTP_1_1_REQUIRED:
599
0
    return "HTTP_1_1_REQUIRED";
600
0
  default:
601
0
    return "unknown";
602
0
  }
603
0
}