Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmnghttp2/lib/nghttp2_http.c
Line
Count
Source
1
/*
2
 * nghttp2 - HTTP/2 C Library
3
 *
4
 * Copyright (c) 2015 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_http.h"
26
27
#include <string.h>
28
#include <assert.h>
29
#include <stdio.h>
30
31
#include "nghttp2_hd.h"
32
#include "nghttp2_helper.h"
33
#include "nghttp2_extpri.h"
34
35
0
static uint8_t downcase(uint8_t c) {
36
0
  return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
37
0
}
38
39
0
static int memieq(const void *a, const void *b, size_t n) {
40
0
  size_t i;
41
0
  const uint8_t *aa = a, *bb = b;
42
43
0
  for (i = 0; i < n; ++i) {
44
0
    if (downcase(aa[i]) != downcase(bb[i])) {
45
0
      return 0;
46
0
    }
47
0
  }
48
0
  return 1;
49
0
}
50
51
0
#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
52
53
0
static int64_t parse_uint(const uint8_t *s, size_t len) {
54
0
  int64_t n = 0;
55
0
  size_t i;
56
0
  if (len == 0) {
57
0
    return -1;
58
0
  }
59
0
  for (i = 0; i < len; ++i) {
60
0
    if ('0' <= s[i] && s[i] <= '9') {
61
0
      if (n > INT64_MAX / 10) {
62
0
        return -1;
63
0
      }
64
0
      n *= 10;
65
0
      if (n > INT64_MAX - (s[i] - '0')) {
66
0
        return -1;
67
0
      }
68
0
      n += s[i] - '0';
69
0
      continue;
70
0
    }
71
0
    return -1;
72
0
  }
73
0
  return n;
74
0
}
75
76
static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
77
0
                               uint32_t flag) {
78
0
  if ((stream->http_flags & flag) || nv->value->len == 0) {
79
0
    return 0;
80
0
  }
81
0
  stream->http_flags = stream->http_flags | flag;
82
0
  return 1;
83
0
}
84
85
0
static int expect_response_body(nghttp2_stream *stream) {
86
0
  return (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_HEAD) == 0 &&
87
0
         stream->status_code / 100 != 1 && stream->status_code != 304 &&
88
0
         stream->status_code != 204;
89
0
}
90
91
/* For "http" or "https" URIs, OPTIONS request may have "*" in :path
92
   header field to represent system-wide OPTIONS request.  Otherwise,
93
   :path header field value must start with "/".  This function must
94
   be called after ":method" header field was received.  This function
95
   returns nonzero if path is valid.*/
96
0
static int check_path(nghttp2_stream *stream) {
97
0
  return (stream->http_flags & NGHTTP2_HTTP_FLAG_SCHEME_HTTP) == 0 ||
98
0
         ((stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_REGULAR) ||
99
0
          ((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_OPTIONS) &&
100
0
           (stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_ASTERISK)));
101
0
}
102
103
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
104
0
                                  int trailer, int connect_protocol) {
105
0
  nghttp2_extpri extpri;
106
107
0
  if (nv->name->base[0] == ':') {
108
0
    if (trailer ||
109
0
        (stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
110
0
      return NGHTTP2_ERR_HTTP_HEADER;
111
0
    }
112
0
  }
113
114
0
  switch (nv->token) {
115
0
  case NGHTTP2_TOKEN__AUTHORITY:
116
0
    if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) {
117
0
      return NGHTTP2_ERR_HTTP_HEADER;
118
0
    }
119
0
    break;
120
0
  case NGHTTP2_TOKEN__METHOD:
121
0
    if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) {
122
0
      return NGHTTP2_ERR_HTTP_HEADER;
123
0
    }
124
0
    switch (nv->value->len) {
125
0
    case 4:
126
0
      if (lstreq("HEAD", nv->value->base, nv->value->len)) {
127
0
        stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
128
0
      }
129
0
      break;
130
0
    case 7:
131
0
      switch (nv->value->base[6]) {
132
0
      case 'T':
133
0
        if (lstreq("CONNECT", nv->value->base, nv->value->len)) {
134
0
          if (stream->stream_id % 2 == 0) {
135
            /* we won't allow CONNECT for push */
136
0
            return NGHTTP2_ERR_HTTP_HEADER;
137
0
          }
138
0
          stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
139
0
        }
140
0
        break;
141
0
      case 'S':
142
0
        if (lstreq("OPTIONS", nv->value->base, nv->value->len)) {
143
0
          stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_OPTIONS;
144
0
        }
145
0
        break;
146
0
      }
147
0
      break;
148
0
    }
149
0
    break;
150
0
  case NGHTTP2_TOKEN__PATH:
151
0
    if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) {
152
0
      return NGHTTP2_ERR_HTTP_HEADER;
153
0
    }
154
0
    if (nv->value->base[0] == '/') {
155
0
      stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_REGULAR;
156
0
    } else if (nv->value->len == 1 && nv->value->base[0] == '*') {
157
0
      stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_ASTERISK;
158
0
    }
159
0
    break;
160
0
  case NGHTTP2_TOKEN__SCHEME:
161
0
    if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
162
0
      return NGHTTP2_ERR_HTTP_HEADER;
163
0
    }
164
0
    if ((nv->value->len == 4 && memieq("http", nv->value->base, 4)) ||
165
0
        (nv->value->len == 5 && memieq("https", nv->value->base, 5))) {
166
0
      stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP;
167
0
    }
168
0
    break;
169
0
  case NGHTTP2_TOKEN__PROTOCOL:
170
0
    if (!connect_protocol) {
171
0
      return NGHTTP2_ERR_HTTP_HEADER;
172
0
    }
173
174
0
    if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PROTOCOL)) {
175
0
      return NGHTTP2_ERR_HTTP_HEADER;
176
0
    }
177
0
    break;
178
0
  case NGHTTP2_TOKEN_HOST:
179
0
    if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) {
180
0
      return NGHTTP2_ERR_HTTP_HEADER;
181
0
    }
182
0
    break;
183
0
  case NGHTTP2_TOKEN_CONTENT_LENGTH: {
184
0
    if (stream->content_length != -1) {
185
0
      return NGHTTP2_ERR_HTTP_HEADER;
186
0
    }
187
0
    stream->content_length = parse_uint(nv->value->base, nv->value->len);
188
0
    if (stream->content_length == -1) {
189
0
      return NGHTTP2_ERR_HTTP_HEADER;
190
0
    }
191
0
    break;
192
0
  }
193
  /* disallowed header fields */
194
0
  case NGHTTP2_TOKEN_CONNECTION:
195
0
  case NGHTTP2_TOKEN_KEEP_ALIVE:
196
0
  case NGHTTP2_TOKEN_PROXY_CONNECTION:
197
0
  case NGHTTP2_TOKEN_TRANSFER_ENCODING:
198
0
  case NGHTTP2_TOKEN_UPGRADE:
199
0
    return NGHTTP2_ERR_HTTP_HEADER;
200
0
  case NGHTTP2_TOKEN_TE:
201
0
    if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
202
0
      return NGHTTP2_ERR_HTTP_HEADER;
203
0
    }
204
0
    break;
205
0
  case NGHTTP2_TOKEN_PRIORITY:
206
0
    if (!trailer &&
207
        /* Do not parse the header field in PUSH_PROMISE. */
208
0
        (stream->stream_id & 1) &&
209
0
        (stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
210
0
        !(stream->http_flags & NGHTTP2_HTTP_FLAG_BAD_PRIORITY)) {
211
0
      nghttp2_extpri_from_uint8(&extpri, stream->http_extpri);
212
0
      if (nghttp2_http_parse_priority(&extpri, nv->value->base,
213
0
                                      nv->value->len) == 0) {
214
0
        stream->http_extpri = nghttp2_extpri_to_uint8(&extpri);
215
0
        stream->http_flags |= NGHTTP2_HTTP_FLAG_PRIORITY;
216
0
      } else {
217
0
        stream->http_flags &= (uint32_t)~NGHTTP2_HTTP_FLAG_PRIORITY;
218
0
        stream->http_flags |= NGHTTP2_HTTP_FLAG_BAD_PRIORITY;
219
0
      }
220
0
    }
221
0
    break;
222
0
  default:
223
0
    if (nv->name->base[0] == ':') {
224
0
      return NGHTTP2_ERR_HTTP_HEADER;
225
0
    }
226
0
  }
227
228
0
  if (nv->name->base[0] != ':') {
229
0
    stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
230
0
  }
231
232
0
  return 0;
233
0
}
234
235
static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
236
0
                                   int trailer) {
237
0
  if (nv->name->base[0] == ':') {
238
0
    if (trailer ||
239
0
        (stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
240
0
      return NGHTTP2_ERR_HTTP_HEADER;
241
0
    }
242
0
  }
243
244
0
  switch (nv->token) {
245
0
  case NGHTTP2_TOKEN__STATUS: {
246
0
    if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) {
247
0
      return NGHTTP2_ERR_HTTP_HEADER;
248
0
    }
249
0
    if (nv->value->len != 3) {
250
0
      return NGHTTP2_ERR_HTTP_HEADER;
251
0
    }
252
0
    stream->status_code = (int16_t)parse_uint(nv->value->base, nv->value->len);
253
0
    if (stream->status_code == -1 || stream->status_code == 101) {
254
0
      return NGHTTP2_ERR_HTTP_HEADER;
255
0
    }
256
0
    break;
257
0
  }
258
0
  case NGHTTP2_TOKEN_CONTENT_LENGTH: {
259
0
    if (stream->status_code == 204) {
260
      /* content-length header field in 204 response is prohibited by
261
         RFC 7230.  But some widely used servers send content-length:
262
         0.  Until they get fixed, we ignore it. */
263
0
      if (stream->content_length != -1) {
264
        /* Found multiple content-length field */
265
0
        return NGHTTP2_ERR_HTTP_HEADER;
266
0
      }
267
0
      if (!lstrieq("0", nv->value->base, nv->value->len)) {
268
0
        return NGHTTP2_ERR_HTTP_HEADER;
269
0
      }
270
0
      stream->content_length = 0;
271
0
      return NGHTTP2_ERR_REMOVE_HTTP_HEADER;
272
0
    }
273
0
    if (stream->status_code / 100 == 1) {
274
0
      return NGHTTP2_ERR_HTTP_HEADER;
275
0
    }
276
    /* https://tools.ietf.org/html/rfc7230#section-3.3.3 */
277
0
    if (stream->status_code / 100 == 2 &&
278
0
        (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) {
279
0
      return NGHTTP2_ERR_REMOVE_HTTP_HEADER;
280
0
    }
281
0
    if (stream->content_length != -1) {
282
0
      return NGHTTP2_ERR_HTTP_HEADER;
283
0
    }
284
0
    stream->content_length = parse_uint(nv->value->base, nv->value->len);
285
0
    if (stream->content_length == -1) {
286
0
      return NGHTTP2_ERR_HTTP_HEADER;
287
0
    }
288
0
    break;
289
0
  }
290
  /* disallowed header fields */
291
0
  case NGHTTP2_TOKEN_CONNECTION:
292
0
  case NGHTTP2_TOKEN_KEEP_ALIVE:
293
0
  case NGHTTP2_TOKEN_PROXY_CONNECTION:
294
0
  case NGHTTP2_TOKEN_TRANSFER_ENCODING:
295
0
  case NGHTTP2_TOKEN_UPGRADE:
296
0
    return NGHTTP2_ERR_HTTP_HEADER;
297
0
  case NGHTTP2_TOKEN_TE:
298
0
    if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
299
0
      return NGHTTP2_ERR_HTTP_HEADER;
300
0
    }
301
0
    break;
302
0
  default:
303
0
    if (nv->name->base[0] == ':') {
304
0
      return NGHTTP2_ERR_HTTP_HEADER;
305
0
    }
306
0
  }
307
308
0
  if (nv->name->base[0] != ':') {
309
0
    stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
310
0
  }
311
312
0
  return 0;
313
0
}
314
315
0
static int check_scheme(const uint8_t *value, size_t len) {
316
0
  const uint8_t *last;
317
0
  if (len == 0) {
318
0
    return 0;
319
0
  }
320
321
0
  if (!(('A' <= *value && *value <= 'Z') || ('a' <= *value && *value <= 'z'))) {
322
0
    return 0;
323
0
  }
324
325
0
  last = value + len;
326
0
  ++value;
327
328
0
  for (; value != last; ++value) {
329
0
    if (!(('A' <= *value && *value <= 'Z') ||
330
0
          ('a' <= *value && *value <= 'z') ||
331
0
          ('0' <= *value && *value <= '9') || *value == '+' || *value == '-' ||
332
0
          *value == '.')) {
333
0
      return 0;
334
0
    }
335
0
  }
336
0
  return 1;
337
0
}
338
339
0
static int lws(const uint8_t *s, size_t n) {
340
0
  size_t i;
341
0
  for (i = 0; i < n; ++i) {
342
0
    if (s[i] != ' ' && s[i] != '\t') {
343
0
      return 0;
344
0
    }
345
0
  }
346
0
  return 1;
347
0
}
348
349
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
350
                           nghttp2_frame *frame, nghttp2_hd_nv *nv,
351
0
                           int trailer) {
352
0
  int rv;
353
354
  /* We are strict for pseudo header field.  One bad character should
355
     lead to fail.  OTOH, we should be a bit forgiving for regular
356
     headers, since existing public internet has so much illegal
357
     headers floating around and if we kill the stream because of
358
     this, we may disrupt many web sites and/or libraries.  So we
359
     become conservative here, and just ignore those illegal regular
360
     headers. */
361
0
  if (!nghttp2_check_header_name(nv->name->base, nv->name->len)) {
362
0
    size_t i;
363
0
    if (nv->name->len > 0 && nv->name->base[0] == ':') {
364
0
      return NGHTTP2_ERR_HTTP_HEADER;
365
0
    }
366
    /* header field name must be lower-cased without exception */
367
0
    for (i = 0; i < nv->name->len; ++i) {
368
0
      uint8_t c = nv->name->base[i];
369
0
      if ('A' <= c && c <= 'Z') {
370
0
        return NGHTTP2_ERR_HTTP_HEADER;
371
0
      }
372
0
    }
373
    /* When ignoring regular headers, we set this flag so that we
374
       still enforce header field ordering rule for pseudo header
375
       fields. */
376
0
    stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
377
0
    return NGHTTP2_ERR_IGN_HTTP_HEADER;
378
0
  }
379
380
0
  switch (nv->token) {
381
0
  case NGHTTP2_TOKEN__METHOD:
382
0
    rv = nghttp2_check_method(nv->value->base, nv->value->len);
383
0
    break;
384
0
  case NGHTTP2_TOKEN__PATH:
385
0
    rv = nghttp2_check_path(nv->value->base, nv->value->len);
386
0
    break;
387
0
  case NGHTTP2_TOKEN__AUTHORITY:
388
0
  case NGHTTP2_TOKEN_HOST:
389
0
    if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
390
0
      rv = nghttp2_check_authority(nv->value->base, nv->value->len);
391
0
    } else if (
392
0
        stream->flags &
393
0
        NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
394
0
      rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
395
0
    } else {
396
0
      rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
397
0
    }
398
0
    break;
399
0
  case NGHTTP2_TOKEN__SCHEME:
400
0
    rv = check_scheme(nv->value->base, nv->value->len);
401
0
    break;
402
0
  case NGHTTP2_TOKEN__PROTOCOL:
403
    /* Check the value consists of just white spaces, which was done
404
       in check_pseudo_header before
405
       nghttp2_check_header_value_rfc9113 has been introduced. */
406
0
    if ((stream->flags &
407
0
         NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) &&
408
0
        lws(nv->value->base, nv->value->len)) {
409
0
      rv = 0;
410
0
      break;
411
0
    }
412
    /* fall through */
413
0
  default:
414
0
    if (stream->flags &
415
0
        NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
416
0
      rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
417
0
    } else {
418
0
      rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
419
0
    }
420
0
  }
421
422
0
  if (rv == 0) {
423
0
    assert(nv->name->len > 0);
424
0
    if (nv->name->base[0] == ':') {
425
0
      return NGHTTP2_ERR_HTTP_HEADER;
426
0
    }
427
    /* When ignoring regular headers, we set this flag so that we
428
       still enforce header field ordering rule for pseudo header
429
       fields. */
430
0
    stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
431
0
    return NGHTTP2_ERR_IGN_HTTP_HEADER;
432
0
  }
433
434
0
  if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
435
0
    return http_request_on_header(stream, nv, trailer,
436
0
                                  session->server &&
437
0
                                      session->pending_enable_connect_protocol);
438
0
  }
439
440
0
  return http_response_on_header(stream, nv, trailer);
441
0
}
442
443
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
444
0
                                    nghttp2_frame *frame) {
445
0
  if (!(stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) &&
446
0
      (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) {
447
0
    if ((stream->http_flags &
448
0
         (NGHTTP2_HTTP_FLAG__SCHEME | NGHTTP2_HTTP_FLAG__PATH)) ||
449
0
        (stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0) {
450
0
      return -1;
451
0
    }
452
0
    stream->content_length = -1;
453
0
  } else {
454
0
    if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
455
0
            NGHTTP2_HTTP_FLAG_REQ_HEADERS ||
456
0
        (stream->http_flags &
457
0
         (NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
458
0
      return -1;
459
0
    }
460
0
    if ((stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) &&
461
0
        ((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) == 0 ||
462
0
         (stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0)) {
463
0
      return -1;
464
0
    }
465
0
    if (!check_path(stream)) {
466
0
      return -1;
467
0
    }
468
0
  }
469
470
0
  if (frame->hd.type == NGHTTP2_PUSH_PROMISE) {
471
    /* we are going to reuse data fields for upcoming response.  Clear
472
       them now, except for method flags. */
473
0
    stream->http_flags &= NGHTTP2_HTTP_FLAG_METH_ALL;
474
0
    stream->content_length = -1;
475
0
  }
476
477
0
  return 0;
478
0
}
479
480
0
int nghttp2_http_on_response_headers(nghttp2_stream *stream) {
481
0
  if ((stream->http_flags & NGHTTP2_HTTP_FLAG__STATUS) == 0) {
482
0
    return -1;
483
0
  }
484
485
0
  if (stream->status_code / 100 == 1) {
486
    /* non-final response */
487
0
    stream->http_flags = (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
488
0
                         NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
489
0
    stream->content_length = -1;
490
0
    stream->status_code = -1;
491
0
    return 0;
492
0
  }
493
494
0
  stream->http_flags =
495
0
      stream->http_flags & (uint32_t)~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
496
497
0
  if (!expect_response_body(stream)) {
498
0
    stream->content_length = 0;
499
0
  } else if (stream->http_flags & (NGHTTP2_HTTP_FLAG_METH_CONNECT |
500
0
                                   NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND)) {
501
0
    stream->content_length = -1;
502
0
  }
503
504
0
  return 0;
505
0
}
506
507
int nghttp2_http_on_trailer_headers(nghttp2_stream *stream,
508
0
                                    nghttp2_frame *frame) {
509
0
  (void)stream;
510
511
0
  if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
512
0
    return -1;
513
0
  }
514
515
0
  return 0;
516
0
}
517
518
0
int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream) {
519
0
  if (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) {
520
0
    return -1;
521
0
  }
522
523
0
  if (stream->content_length != -1 &&
524
0
      stream->content_length != stream->recv_content_length) {
525
0
    return -1;
526
0
  }
527
528
0
  return 0;
529
0
}
530
531
0
int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n) {
532
0
  stream->recv_content_length += (int64_t)n;
533
534
0
  if ((stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) ||
535
0
      (stream->content_length != -1 &&
536
0
       stream->recv_content_length > stream->content_length)) {
537
0
    return -1;
538
0
  }
539
540
0
  return 0;
541
0
}
542
543
void nghttp2_http_record_request_method(nghttp2_stream *stream,
544
0
                                        nghttp2_frame *frame) {
545
0
  const nghttp2_nv *nva;
546
0
  size_t nvlen;
547
0
  size_t i;
548
549
0
  switch (frame->hd.type) {
550
0
  case NGHTTP2_HEADERS:
551
0
    nva = frame->headers.nva;
552
0
    nvlen = frame->headers.nvlen;
553
0
    break;
554
0
  case NGHTTP2_PUSH_PROMISE:
555
0
    nva = frame->push_promise.nva;
556
0
    nvlen = frame->push_promise.nvlen;
557
0
    break;
558
0
  default:
559
0
    return;
560
0
  }
561
562
  /* TODO we should do this strictly. */
563
0
  for (i = 0; i < nvlen; ++i) {
564
0
    const nghttp2_nv *nv = &nva[i];
565
0
    if (!(nv->namelen == 7 && nv->name[6] == 'd' &&
566
0
          memcmp(":metho", nv->name, nv->namelen - 1) == 0)) {
567
0
      continue;
568
0
    }
569
0
    if (lstreq("CONNECT", nv->value, nv->valuelen)) {
570
0
      stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
571
0
      return;
572
0
    }
573
0
    if (lstreq("HEAD", nv->value, nv->valuelen)) {
574
0
      stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
575
0
      return;
576
0
    }
577
0
    return;
578
0
  }
579
0
}
580
581
/* Generated by genchartbl.py */
582
static const int SF_KEY_CHARS[] = {
583
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
584
    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
585
    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
586
    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
587
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
588
    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
589
    0 /* RS   */, 0 /* US   */, 0 /* SPC  */, 0 /* !    */, 0 /* "    */,
590
    0 /* #    */, 0 /* $    */, 0 /* %    */, 0 /* &    */, 0 /* '    */,
591
    0 /* (    */, 0 /* )    */, 1 /* *    */, 0 /* +    */, 0 /* ,    */,
592
    1 /* -    */, 1 /* .    */, 0 /* /    */, 1 /* 0    */, 1 /* 1    */,
593
    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
594
    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 0 /* :    */, 0 /* ;    */,
595
    0 /* <    */, 0 /* =    */, 0 /* >    */, 0 /* ?    */, 0 /* @    */,
596
    0 /* A    */, 0 /* B    */, 0 /* C    */, 0 /* D    */, 0 /* E    */,
597
    0 /* F    */, 0 /* G    */, 0 /* H    */, 0 /* I    */, 0 /* J    */,
598
    0 /* K    */, 0 /* L    */, 0 /* M    */, 0 /* N    */, 0 /* O    */,
599
    0 /* P    */, 0 /* Q    */, 0 /* R    */, 0 /* S    */, 0 /* T    */,
600
    0 /* U    */, 0 /* V    */, 0 /* W    */, 0 /* X    */, 0 /* Y    */,
601
    0 /* Z    */, 0 /* [    */, 0 /* \    */, 0 /* ]    */, 0 /* ^    */,
602
    1 /* _    */, 0 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
603
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
604
    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
605
    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
606
    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
607
    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */, 0 /* |    */,
608
    0 /* }    */, 0 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
609
    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
610
    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
611
    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
612
    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
613
    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
614
    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
615
    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
616
    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
617
    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
618
    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
619
    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
620
    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
621
    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
622
    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
623
    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
624
    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
625
    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
626
    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
627
    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
628
    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
629
    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
630
    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
631
    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
632
    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
633
    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
634
    0 /* 0xff */,
635
};
636
637
0
static ssize_t sf_parse_key(const uint8_t *begin, const uint8_t *end) {
638
0
  const uint8_t *p = begin;
639
640
0
  if ((*p < 'a' || 'z' < *p) && *p != '*') {
641
0
    return -1;
642
0
  }
643
644
0
  for (; p != end && SF_KEY_CHARS[*p]; ++p)
645
0
    ;
646
647
0
  return p - begin;
648
0
}
649
650
static ssize_t sf_parse_integer_or_decimal(nghttp2_sf_value *dest,
651
                                           const uint8_t *begin,
652
0
                                           const uint8_t *end) {
653
0
  const uint8_t *p = begin;
654
0
  int sign = 1;
655
0
  int64_t value = 0;
656
0
  int type = NGHTTP2_SF_VALUE_TYPE_INTEGER;
657
0
  size_t len = 0;
658
0
  size_t fpos = 0;
659
0
  size_t i;
660
661
0
  if (*p == '-') {
662
0
    if (++p == end) {
663
0
      return -1;
664
0
    }
665
666
0
    sign = -1;
667
0
  }
668
669
0
  if (*p < '0' || '9' < *p) {
670
0
    return -1;
671
0
  }
672
673
0
  for (; p != end; ++p) {
674
0
    switch (*p) {
675
0
    case '0':
676
0
    case '1':
677
0
    case '2':
678
0
    case '3':
679
0
    case '4':
680
0
    case '5':
681
0
    case '6':
682
0
    case '7':
683
0
    case '8':
684
0
    case '9':
685
0
      value *= 10;
686
0
      value += *p - '0';
687
688
0
      if (++len > 15) {
689
0
        return -1;
690
0
      }
691
692
0
      break;
693
0
    case '.':
694
0
      if (type != NGHTTP2_SF_VALUE_TYPE_INTEGER) {
695
0
        goto fin;
696
0
      }
697
698
0
      if (len > 12) {
699
0
        return -1;
700
0
      }
701
0
      fpos = len;
702
0
      type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
703
704
0
      break;
705
0
    default:
706
0
      goto fin;
707
0
    };
708
0
  }
709
710
0
fin:
711
0
  switch (type) {
712
0
  case NGHTTP2_SF_VALUE_TYPE_INTEGER:
713
0
    if (dest) {
714
0
      dest->type = (uint8_t)type;
715
0
      dest->i = value * sign;
716
0
    }
717
718
0
    return p - begin;
719
0
  case NGHTTP2_SF_VALUE_TYPE_DECIMAL:
720
0
    if (fpos == len || len - fpos > 3) {
721
0
      return -1;
722
0
    }
723
724
0
    if (dest) {
725
0
      dest->type = (uint8_t)type;
726
0
      dest->d = (double)value;
727
0
      for (i = len - fpos; i > 0; --i) {
728
0
        dest->d /= (double)10;
729
0
      }
730
0
      dest->d *= sign;
731
0
    }
732
733
0
    return p - begin;
734
0
  default:
735
0
    assert(0);
736
0
    abort();
737
0
  }
738
0
}
739
740
/* Generated by genchartbl.py */
741
static const int SF_DQUOTE_CHARS[] = {
742
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
743
    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
744
    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
745
    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
746
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
747
    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
748
    0 /* RS   */, 0 /* US   */, 1 /* SPC  */, 1 /* !    */, 0 /* "    */,
749
    1 /* #    */, 1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
750
    1 /* (    */, 1 /* )    */, 1 /* *    */, 1 /* +    */, 1 /* ,    */,
751
    1 /* -    */, 1 /* .    */, 1 /* /    */, 1 /* 0    */, 1 /* 1    */,
752
    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
753
    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 1 /* :    */, 1 /* ;    */,
754
    1 /* <    */, 1 /* =    */, 1 /* >    */, 1 /* ?    */, 1 /* @    */,
755
    1 /* A    */, 1 /* B    */, 1 /* C    */, 1 /* D    */, 1 /* E    */,
756
    1 /* F    */, 1 /* G    */, 1 /* H    */, 1 /* I    */, 1 /* J    */,
757
    1 /* K    */, 1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
758
    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */, 1 /* T    */,
759
    1 /* U    */, 1 /* V    */, 1 /* W    */, 1 /* X    */, 1 /* Y    */,
760
    1 /* Z    */, 1 /* [    */, 0 /* \    */, 1 /* ]    */, 1 /* ^    */,
761
    1 /* _    */, 1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
762
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
763
    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
764
    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
765
    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
766
    1 /* x    */, 1 /* y    */, 1 /* z    */, 1 /* {    */, 1 /* |    */,
767
    1 /* }    */, 1 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
768
    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
769
    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
770
    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
771
    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
772
    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
773
    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
774
    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
775
    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
776
    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
777
    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
778
    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
779
    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
780
    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
781
    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
782
    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
783
    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
784
    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
785
    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
786
    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
787
    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
788
    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
789
    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
790
    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
791
    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
792
    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
793
    0 /* 0xff */,
794
};
795
796
static ssize_t sf_parse_string(nghttp2_sf_value *dest, const uint8_t *begin,
797
0
                               const uint8_t *end) {
798
0
  const uint8_t *p = begin;
799
800
0
  if (*p++ != '"') {
801
0
    return -1;
802
0
  }
803
804
0
  for (; p != end; ++p) {
805
0
    switch (*p) {
806
0
    case '\\':
807
0
      if (++p == end) {
808
0
        return -1;
809
0
      }
810
811
0
      switch (*p) {
812
0
      case '"':
813
0
      case '\\':
814
0
        break;
815
0
      default:
816
0
        return -1;
817
0
      }
818
819
0
      break;
820
0
    case '"':
821
0
      if (dest) {
822
0
        dest->type = NGHTTP2_SF_VALUE_TYPE_STRING;
823
0
        dest->s.base = begin + 1;
824
0
        dest->s.len = (size_t)(p - dest->s.base);
825
0
      }
826
827
0
      ++p;
828
829
0
      return p - begin;
830
0
    default:
831
0
      if (!SF_DQUOTE_CHARS[*p]) {
832
0
        return -1;
833
0
      }
834
0
    }
835
0
  }
836
837
0
  return -1;
838
0
}
839
840
/* Generated by genchartbl.py */
841
static const int SF_TOKEN_CHARS[] = {
842
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
843
    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
844
    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
845
    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
846
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
847
    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
848
    0 /* RS   */, 0 /* US   */, 0 /* SPC  */, 1 /* !    */, 0 /* "    */,
849
    1 /* #    */, 1 /* $    */, 1 /* %    */, 1 /* &    */, 1 /* '    */,
850
    0 /* (    */, 0 /* )    */, 1 /* *    */, 1 /* +    */, 0 /* ,    */,
851
    1 /* -    */, 1 /* .    */, 1 /* /    */, 1 /* 0    */, 1 /* 1    */,
852
    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
853
    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 1 /* :    */, 0 /* ;    */,
854
    0 /* <    */, 0 /* =    */, 0 /* >    */, 0 /* ?    */, 0 /* @    */,
855
    1 /* A    */, 1 /* B    */, 1 /* C    */, 1 /* D    */, 1 /* E    */,
856
    1 /* F    */, 1 /* G    */, 1 /* H    */, 1 /* I    */, 1 /* J    */,
857
    1 /* K    */, 1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
858
    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */, 1 /* T    */,
859
    1 /* U    */, 1 /* V    */, 1 /* W    */, 1 /* X    */, 1 /* Y    */,
860
    1 /* Z    */, 0 /* [    */, 0 /* \    */, 0 /* ]    */, 1 /* ^    */,
861
    1 /* _    */, 1 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
862
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
863
    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
864
    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
865
    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
866
    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */, 1 /* |    */,
867
    0 /* }    */, 1 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
868
    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
869
    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
870
    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
871
    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
872
    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
873
    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
874
    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
875
    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
876
    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
877
    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
878
    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
879
    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
880
    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
881
    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
882
    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
883
    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
884
    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
885
    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
886
    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
887
    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
888
    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
889
    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
890
    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
891
    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
892
    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
893
    0 /* 0xff */,
894
};
895
896
static ssize_t sf_parse_token(nghttp2_sf_value *dest, const uint8_t *begin,
897
0
                              const uint8_t *end) {
898
0
  const uint8_t *p = begin;
899
900
0
  if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') {
901
0
    return -1;
902
0
  }
903
904
0
  for (; p != end && SF_TOKEN_CHARS[*p]; ++p)
905
0
    ;
906
907
0
  if (dest) {
908
0
    dest->type = NGHTTP2_SF_VALUE_TYPE_TOKEN;
909
0
    dest->s.base = begin;
910
0
    dest->s.len = (size_t)(p - begin);
911
0
  }
912
913
0
  return p - begin;
914
0
}
915
916
/* Generated by genchartbl.py */
917
static const int SF_BYTESEQ_CHARS[] = {
918
    0 /* NUL  */, 0 /* SOH  */, 0 /* STX  */, 0 /* ETX  */, 0 /* EOT  */,
919
    0 /* ENQ  */, 0 /* ACK  */, 0 /* BEL  */, 0 /* BS   */, 0 /* HT   */,
920
    0 /* LF   */, 0 /* VT   */, 0 /* FF   */, 0 /* CR   */, 0 /* SO   */,
921
    0 /* SI   */, 0 /* DLE  */, 0 /* DC1  */, 0 /* DC2  */, 0 /* DC3  */,
922
    0 /* DC4  */, 0 /* NAK  */, 0 /* SYN  */, 0 /* ETB  */, 0 /* CAN  */,
923
    0 /* EM   */, 0 /* SUB  */, 0 /* ESC  */, 0 /* FS   */, 0 /* GS   */,
924
    0 /* RS   */, 0 /* US   */, 0 /* SPC  */, 0 /* !    */, 0 /* "    */,
925
    0 /* #    */, 0 /* $    */, 0 /* %    */, 0 /* &    */, 0 /* '    */,
926
    0 /* (    */, 0 /* )    */, 0 /* *    */, 1 /* +    */, 0 /* ,    */,
927
    0 /* -    */, 0 /* .    */, 1 /* /    */, 1 /* 0    */, 1 /* 1    */,
928
    1 /* 2    */, 1 /* 3    */, 1 /* 4    */, 1 /* 5    */, 1 /* 6    */,
929
    1 /* 7    */, 1 /* 8    */, 1 /* 9    */, 0 /* :    */, 0 /* ;    */,
930
    0 /* <    */, 1 /* =    */, 0 /* >    */, 0 /* ?    */, 0 /* @    */,
931
    1 /* A    */, 1 /* B    */, 1 /* C    */, 1 /* D    */, 1 /* E    */,
932
    1 /* F    */, 1 /* G    */, 1 /* H    */, 1 /* I    */, 1 /* J    */,
933
    1 /* K    */, 1 /* L    */, 1 /* M    */, 1 /* N    */, 1 /* O    */,
934
    1 /* P    */, 1 /* Q    */, 1 /* R    */, 1 /* S    */, 1 /* T    */,
935
    1 /* U    */, 1 /* V    */, 1 /* W    */, 1 /* X    */, 1 /* Y    */,
936
    1 /* Z    */, 0 /* [    */, 0 /* \    */, 0 /* ]    */, 0 /* ^    */,
937
    0 /* _    */, 0 /* `    */, 1 /* a    */, 1 /* b    */, 1 /* c    */,
938
    1 /* d    */, 1 /* e    */, 1 /* f    */, 1 /* g    */, 1 /* h    */,
939
    1 /* i    */, 1 /* j    */, 1 /* k    */, 1 /* l    */, 1 /* m    */,
940
    1 /* n    */, 1 /* o    */, 1 /* p    */, 1 /* q    */, 1 /* r    */,
941
    1 /* s    */, 1 /* t    */, 1 /* u    */, 1 /* v    */, 1 /* w    */,
942
    1 /* x    */, 1 /* y    */, 1 /* z    */, 0 /* {    */, 0 /* |    */,
943
    0 /* }    */, 0 /* ~    */, 0 /* DEL  */, 0 /* 0x80 */, 0 /* 0x81 */,
944
    0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
945
    0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
946
    0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
947
    0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
948
    0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
949
    0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
950
    0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
951
    0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
952
    0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
953
    0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
954
    0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
955
    0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
956
    0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
957
    0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
958
    0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
959
    0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
960
    0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
961
    0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
962
    0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
963
    0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
964
    0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
965
    0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
966
    0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
967
    0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
968
    0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
969
    0 /* 0xff */,
970
};
971
972
static ssize_t sf_parse_byteseq(nghttp2_sf_value *dest, const uint8_t *begin,
973
0
                                const uint8_t *end) {
974
0
  const uint8_t *p = begin;
975
976
0
  if (*p++ != ':') {
977
0
    return -1;
978
0
  }
979
980
0
  for (; p != end; ++p) {
981
0
    switch (*p) {
982
0
    case ':':
983
0
      if (dest) {
984
0
        dest->type = NGHTTP2_SF_VALUE_TYPE_BYTESEQ;
985
0
        dest->s.base = begin + 1;
986
0
        dest->s.len = (size_t)(p - dest->s.base);
987
0
      }
988
989
0
      ++p;
990
991
0
      return p - begin;
992
0
    default:
993
0
      if (!SF_BYTESEQ_CHARS[*p]) {
994
0
        return -1;
995
0
      }
996
0
    }
997
0
  }
998
999
0
  return -1;
1000
0
}
1001
1002
static ssize_t sf_parse_boolean(nghttp2_sf_value *dest, const uint8_t *begin,
1003
0
                                const uint8_t *end) {
1004
0
  const uint8_t *p = begin;
1005
0
  int b;
1006
1007
0
  if (*p++ != '?') {
1008
0
    return -1;
1009
0
  }
1010
1011
0
  if (p == end) {
1012
0
    return -1;
1013
0
  }
1014
1015
0
  switch (*p++) {
1016
0
  case '0':
1017
0
    b = 0;
1018
0
    break;
1019
0
  case '1':
1020
0
    b = 1;
1021
0
    break;
1022
0
  default:
1023
0
    return -1;
1024
0
  }
1025
1026
0
  if (dest) {
1027
0
    dest->type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
1028
0
    dest->b = b;
1029
0
  }
1030
1031
0
  return p - begin;
1032
0
}
1033
1034
static ssize_t sf_parse_bare_item(nghttp2_sf_value *dest, const uint8_t *begin,
1035
0
                                  const uint8_t *end) {
1036
0
  switch (*begin) {
1037
0
  case '-':
1038
0
  case '0':
1039
0
  case '1':
1040
0
  case '2':
1041
0
  case '3':
1042
0
  case '4':
1043
0
  case '5':
1044
0
  case '6':
1045
0
  case '7':
1046
0
  case '8':
1047
0
  case '9':
1048
0
    return sf_parse_integer_or_decimal(dest, begin, end);
1049
0
  case '"':
1050
0
    return sf_parse_string(dest, begin, end);
1051
0
  case '*':
1052
0
    return sf_parse_token(dest, begin, end);
1053
0
  case ':':
1054
0
    return sf_parse_byteseq(dest, begin, end);
1055
0
  case '?':
1056
0
    return sf_parse_boolean(dest, begin, end);
1057
0
  default:
1058
0
    if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) {
1059
0
      return sf_parse_token(dest, begin, end);
1060
0
    }
1061
0
    return -1;
1062
0
  }
1063
0
}
1064
1065
#define sf_discard_sp_end_err(BEGIN, END, ERR)                                 \
1066
0
  for (;; ++(BEGIN)) {                                                         \
1067
0
    if ((BEGIN) == (END)) {                                                    \
1068
0
      return (ERR);                                                            \
1069
0
    }                                                                          \
1070
0
    if (*(BEGIN) != ' ') {                                                     \
1071
0
      break;                                                                   \
1072
0
    }                                                                          \
1073
0
  }
1074
1075
0
static ssize_t sf_parse_params(const uint8_t *begin, const uint8_t *end) {
1076
0
  const uint8_t *p = begin;
1077
0
  ssize_t slen;
1078
1079
0
  for (; p != end && *p == ';';) {
1080
0
    ++p;
1081
1082
0
    sf_discard_sp_end_err(p, end, -1);
1083
1084
0
    slen = sf_parse_key(p, end);
1085
0
    if (slen < 0) {
1086
0
      return -1;
1087
0
    }
1088
1089
0
    p += slen;
1090
1091
0
    if (p == end || *p != '=') {
1092
      /* Boolean true */
1093
0
    } else if (++p == end) {
1094
0
      return -1;
1095
0
    } else {
1096
0
      slen = sf_parse_bare_item(NULL, p, end);
1097
0
      if (slen < 0) {
1098
0
        return -1;
1099
0
      }
1100
1101
0
      p += slen;
1102
0
    }
1103
0
  }
1104
1105
0
  return p - begin;
1106
0
}
1107
1108
static ssize_t sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
1109
0
                             const uint8_t *end) {
1110
0
  const uint8_t *p = begin;
1111
0
  ssize_t slen;
1112
1113
0
  slen = sf_parse_bare_item(dest, p, end);
1114
0
  if (slen < 0) {
1115
0
    return -1;
1116
0
  }
1117
1118
0
  p += slen;
1119
1120
0
  slen = sf_parse_params(p, end);
1121
0
  if (slen < 0) {
1122
0
    return -1;
1123
0
  }
1124
1125
0
  p += slen;
1126
1127
0
  return p - begin;
1128
0
}
1129
1130
ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
1131
0
                              const uint8_t *end) {
1132
0
  return sf_parse_item(dest, begin, end);
1133
0
}
1134
1135
static ssize_t sf_parse_inner_list(nghttp2_sf_value *dest, const uint8_t *begin,
1136
0
                                   const uint8_t *end) {
1137
0
  const uint8_t *p = begin;
1138
0
  ssize_t slen;
1139
1140
0
  if (*p++ != '(') {
1141
0
    return -1;
1142
0
  }
1143
1144
0
  for (;;) {
1145
0
    sf_discard_sp_end_err(p, end, -1);
1146
1147
0
    if (*p == ')') {
1148
0
      ++p;
1149
1150
0
      slen = sf_parse_params(p, end);
1151
0
      if (slen < 0) {
1152
0
        return -1;
1153
0
      }
1154
1155
0
      p += slen;
1156
1157
0
      if (dest) {
1158
0
        dest->type = NGHTTP2_SF_VALUE_TYPE_INNER_LIST;
1159
0
      }
1160
1161
0
      return p - begin;
1162
0
    }
1163
1164
0
    slen = sf_parse_item(NULL, p, end);
1165
0
    if (slen < 0) {
1166
0
      return -1;
1167
0
    }
1168
1169
0
    p += slen;
1170
1171
0
    if (p == end || (*p != ' ' && *p != ')')) {
1172
0
      return -1;
1173
0
    }
1174
0
  }
1175
0
}
1176
1177
ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
1178
0
                                    const uint8_t *begin, const uint8_t *end) {
1179
0
  return sf_parse_inner_list(dest, begin, end);
1180
0
}
1181
1182
static ssize_t sf_parse_item_or_inner_list(nghttp2_sf_value *dest,
1183
                                           const uint8_t *begin,
1184
0
                                           const uint8_t *end) {
1185
0
  if (*begin == '(') {
1186
0
    return sf_parse_inner_list(dest, begin, end);
1187
0
  }
1188
1189
0
  return sf_parse_item(dest, begin, end);
1190
0
}
1191
1192
#define sf_discard_ows(BEGIN, END)                                             \
1193
0
  for (;; ++(BEGIN)) {                                                         \
1194
0
    if ((BEGIN) == (END)) {                                                    \
1195
0
      goto fin;                                                                \
1196
0
    }                                                                          \
1197
0
    if (*(BEGIN) != ' ' && *(BEGIN) != '\t') {                                 \
1198
0
      break;                                                                   \
1199
0
    }                                                                          \
1200
0
  }
1201
1202
#define sf_discard_ows_end_err(BEGIN, END, ERR)                                \
1203
0
  for (;; ++(BEGIN)) {                                                         \
1204
0
    if ((BEGIN) == (END)) {                                                    \
1205
0
      return (ERR);                                                            \
1206
0
    }                                                                          \
1207
0
    if (*(BEGIN) != ' ' && *(BEGIN) != '\t') {                                 \
1208
0
      break;                                                                   \
1209
0
    }                                                                          \
1210
0
  }
1211
1212
int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
1213
0
                                size_t valuelen) {
1214
0
  const uint8_t *p = value, *end = value + valuelen;
1215
0
  ssize_t slen;
1216
0
  nghttp2_sf_value val;
1217
0
  nghttp2_extpri pri = *dest;
1218
0
  const uint8_t *key;
1219
0
  size_t keylen;
1220
1221
0
  for (; p != end && *p == ' '; ++p)
1222
0
    ;
1223
1224
0
  for (; p != end;) {
1225
0
    slen = sf_parse_key(p, end);
1226
0
    if (slen < 0) {
1227
0
      return NGHTTP2_ERR_INVALID_ARGUMENT;
1228
0
    }
1229
1230
0
    key = p;
1231
0
    keylen = (size_t)slen;
1232
1233
0
    p += slen;
1234
1235
0
    if (p == end || *p != '=') {
1236
      /* Boolean true */
1237
0
      val.type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
1238
0
      val.b = 1;
1239
1240
0
      slen = sf_parse_params(p, end);
1241
0
      if (slen < 0) {
1242
0
        return NGHTTP2_ERR_INVALID_ARGUMENT;
1243
0
      }
1244
0
    } else if (++p == end) {
1245
0
      return NGHTTP2_ERR_INVALID_ARGUMENT;
1246
0
    } else {
1247
0
      slen = sf_parse_item_or_inner_list(&val, p, end);
1248
0
      if (slen < 0) {
1249
0
        return NGHTTP2_ERR_INVALID_ARGUMENT;
1250
0
      }
1251
0
    }
1252
1253
0
    p += slen;
1254
1255
0
    if (keylen == 1) {
1256
0
      switch (key[0]) {
1257
0
      case 'i':
1258
0
        if (val.type != NGHTTP2_SF_VALUE_TYPE_BOOLEAN) {
1259
0
          return NGHTTP2_ERR_INVALID_ARGUMENT;
1260
0
        }
1261
1262
0
        pri.inc = val.b;
1263
1264
0
        break;
1265
0
      case 'u':
1266
0
        if (val.type != NGHTTP2_SF_VALUE_TYPE_INTEGER ||
1267
0
            val.i < NGHTTP2_EXTPRI_URGENCY_HIGH ||
1268
0
            NGHTTP2_EXTPRI_URGENCY_LOW < val.i) {
1269
0
          return NGHTTP2_ERR_INVALID_ARGUMENT;
1270
0
        }
1271
1272
0
        pri.urgency = (uint32_t)val.i;
1273
1274
0
        break;
1275
0
      }
1276
0
    }
1277
1278
0
    sf_discard_ows(p, end);
1279
1280
0
    if (*p++ != ',') {
1281
0
      return NGHTTP2_ERR_INVALID_ARGUMENT;
1282
0
    }
1283
1284
0
    sf_discard_ows_end_err(p, end, NGHTTP2_ERR_INVALID_ARGUMENT);
1285
0
  }
1286
1287
0
fin:
1288
0
  *dest = pri;
1289
1290
0
  return 0;
1291
0
}