Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmnghttp2/lib/nghttp2_http.c
3153 views
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
static uint8_t downcase(uint8_t c) {
36
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
37
}
38
39
static int memieq(const void *a, const void *b, size_t n) {
40
size_t i;
41
const uint8_t *aa = a, *bb = b;
42
43
for (i = 0; i < n; ++i) {
44
if (downcase(aa[i]) != downcase(bb[i])) {
45
return 0;
46
}
47
}
48
return 1;
49
}
50
51
#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
52
53
static int64_t parse_uint(const uint8_t *s, size_t len) {
54
int64_t n = 0;
55
size_t i;
56
if (len == 0) {
57
return -1;
58
}
59
for (i = 0; i < len; ++i) {
60
if ('0' <= s[i] && s[i] <= '9') {
61
if (n > INT64_MAX / 10) {
62
return -1;
63
}
64
n *= 10;
65
if (n > INT64_MAX - (s[i] - '0')) {
66
return -1;
67
}
68
n += s[i] - '0';
69
continue;
70
}
71
return -1;
72
}
73
return n;
74
}
75
76
static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
77
uint32_t flag) {
78
if ((stream->http_flags & flag) || nv->value->len == 0) {
79
return 0;
80
}
81
stream->http_flags = stream->http_flags | flag;
82
return 1;
83
}
84
85
static int expect_response_body(nghttp2_stream *stream) {
86
return (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_HEAD) == 0 &&
87
stream->status_code / 100 != 1 && stream->status_code != 304 &&
88
stream->status_code != 204;
89
}
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
static int check_path(nghttp2_stream *stream) {
97
return (stream->http_flags & NGHTTP2_HTTP_FLAG_SCHEME_HTTP) == 0 ||
98
((stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_REGULAR) ||
99
((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_OPTIONS) &&
100
(stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_ASTERISK)));
101
}
102
103
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
104
int trailer, int connect_protocol) {
105
nghttp2_extpri extpri;
106
107
if (nv->name->base[0] == ':') {
108
if (trailer ||
109
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
110
return NGHTTP2_ERR_HTTP_HEADER;
111
}
112
}
113
114
switch (nv->token) {
115
case NGHTTP2_TOKEN__AUTHORITY:
116
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) {
117
return NGHTTP2_ERR_HTTP_HEADER;
118
}
119
break;
120
case NGHTTP2_TOKEN__METHOD:
121
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) {
122
return NGHTTP2_ERR_HTTP_HEADER;
123
}
124
switch (nv->value->len) {
125
case 4:
126
if (lstreq("HEAD", nv->value->base, nv->value->len)) {
127
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
128
}
129
break;
130
case 7:
131
switch (nv->value->base[6]) {
132
case 'T':
133
if (lstreq("CONNECT", nv->value->base, nv->value->len)) {
134
if (stream->stream_id % 2 == 0) {
135
/* we won't allow CONNECT for push */
136
return NGHTTP2_ERR_HTTP_HEADER;
137
}
138
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
139
}
140
break;
141
case 'S':
142
if (lstreq("OPTIONS", nv->value->base, nv->value->len)) {
143
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_OPTIONS;
144
}
145
break;
146
}
147
break;
148
}
149
break;
150
case NGHTTP2_TOKEN__PATH:
151
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) {
152
return NGHTTP2_ERR_HTTP_HEADER;
153
}
154
if (nv->value->base[0] == '/') {
155
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_REGULAR;
156
} else if (nv->value->len == 1 && nv->value->base[0] == '*') {
157
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_ASTERISK;
158
}
159
break;
160
case NGHTTP2_TOKEN__SCHEME:
161
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
162
return NGHTTP2_ERR_HTTP_HEADER;
163
}
164
if ((nv->value->len == 4 && memieq("http", nv->value->base, 4)) ||
165
(nv->value->len == 5 && memieq("https", nv->value->base, 5))) {
166
stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP;
167
}
168
break;
169
case NGHTTP2_TOKEN__PROTOCOL:
170
if (!connect_protocol) {
171
return NGHTTP2_ERR_HTTP_HEADER;
172
}
173
174
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PROTOCOL)) {
175
return NGHTTP2_ERR_HTTP_HEADER;
176
}
177
break;
178
case NGHTTP2_TOKEN_HOST:
179
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) {
180
return NGHTTP2_ERR_HTTP_HEADER;
181
}
182
break;
183
case NGHTTP2_TOKEN_CONTENT_LENGTH: {
184
if (stream->content_length != -1) {
185
return NGHTTP2_ERR_HTTP_HEADER;
186
}
187
stream->content_length = parse_uint(nv->value->base, nv->value->len);
188
if (stream->content_length == -1) {
189
return NGHTTP2_ERR_HTTP_HEADER;
190
}
191
break;
192
}
193
/* disallowed header fields */
194
case NGHTTP2_TOKEN_CONNECTION:
195
case NGHTTP2_TOKEN_KEEP_ALIVE:
196
case NGHTTP2_TOKEN_PROXY_CONNECTION:
197
case NGHTTP2_TOKEN_TRANSFER_ENCODING:
198
case NGHTTP2_TOKEN_UPGRADE:
199
return NGHTTP2_ERR_HTTP_HEADER;
200
case NGHTTP2_TOKEN_TE:
201
if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
202
return NGHTTP2_ERR_HTTP_HEADER;
203
}
204
break;
205
case NGHTTP2_TOKEN_PRIORITY:
206
if (!trailer &&
207
/* Do not parse the header field in PUSH_PROMISE. */
208
(stream->stream_id & 1) &&
209
(stream->flags & NGHTTP2_STREAM_FLAG_NO_RFC7540_PRIORITIES) &&
210
!(stream->http_flags & NGHTTP2_HTTP_FLAG_BAD_PRIORITY)) {
211
nghttp2_extpri_from_uint8(&extpri, stream->http_extpri);
212
if (nghttp2_http_parse_priority(&extpri, nv->value->base,
213
nv->value->len) == 0) {
214
stream->http_extpri = nghttp2_extpri_to_uint8(&extpri);
215
stream->http_flags |= NGHTTP2_HTTP_FLAG_PRIORITY;
216
} else {
217
stream->http_flags &= (uint32_t)~NGHTTP2_HTTP_FLAG_PRIORITY;
218
stream->http_flags |= NGHTTP2_HTTP_FLAG_BAD_PRIORITY;
219
}
220
}
221
break;
222
default:
223
if (nv->name->base[0] == ':') {
224
return NGHTTP2_ERR_HTTP_HEADER;
225
}
226
}
227
228
if (nv->name->base[0] != ':') {
229
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
230
}
231
232
return 0;
233
}
234
235
static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
236
int trailer) {
237
if (nv->name->base[0] == ':') {
238
if (trailer ||
239
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
240
return NGHTTP2_ERR_HTTP_HEADER;
241
}
242
}
243
244
switch (nv->token) {
245
case NGHTTP2_TOKEN__STATUS: {
246
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) {
247
return NGHTTP2_ERR_HTTP_HEADER;
248
}
249
if (nv->value->len != 3) {
250
return NGHTTP2_ERR_HTTP_HEADER;
251
}
252
stream->status_code = (int16_t)parse_uint(nv->value->base, nv->value->len);
253
if (stream->status_code == -1 || stream->status_code == 101) {
254
return NGHTTP2_ERR_HTTP_HEADER;
255
}
256
break;
257
}
258
case NGHTTP2_TOKEN_CONTENT_LENGTH: {
259
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
if (stream->content_length != -1) {
264
/* Found multiple content-length field */
265
return NGHTTP2_ERR_HTTP_HEADER;
266
}
267
if (!lstrieq("0", nv->value->base, nv->value->len)) {
268
return NGHTTP2_ERR_HTTP_HEADER;
269
}
270
stream->content_length = 0;
271
return NGHTTP2_ERR_REMOVE_HTTP_HEADER;
272
}
273
if (stream->status_code / 100 == 1) {
274
return NGHTTP2_ERR_HTTP_HEADER;
275
}
276
/* https://tools.ietf.org/html/rfc7230#section-3.3.3 */
277
if (stream->status_code / 100 == 2 &&
278
(stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) {
279
return NGHTTP2_ERR_REMOVE_HTTP_HEADER;
280
}
281
if (stream->content_length != -1) {
282
return NGHTTP2_ERR_HTTP_HEADER;
283
}
284
stream->content_length = parse_uint(nv->value->base, nv->value->len);
285
if (stream->content_length == -1) {
286
return NGHTTP2_ERR_HTTP_HEADER;
287
}
288
break;
289
}
290
/* disallowed header fields */
291
case NGHTTP2_TOKEN_CONNECTION:
292
case NGHTTP2_TOKEN_KEEP_ALIVE:
293
case NGHTTP2_TOKEN_PROXY_CONNECTION:
294
case NGHTTP2_TOKEN_TRANSFER_ENCODING:
295
case NGHTTP2_TOKEN_UPGRADE:
296
return NGHTTP2_ERR_HTTP_HEADER;
297
case NGHTTP2_TOKEN_TE:
298
if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
299
return NGHTTP2_ERR_HTTP_HEADER;
300
}
301
break;
302
default:
303
if (nv->name->base[0] == ':') {
304
return NGHTTP2_ERR_HTTP_HEADER;
305
}
306
}
307
308
if (nv->name->base[0] != ':') {
309
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
310
}
311
312
return 0;
313
}
314
315
static int check_scheme(const uint8_t *value, size_t len) {
316
const uint8_t *last;
317
if (len == 0) {
318
return 0;
319
}
320
321
if (!(('A' <= *value && *value <= 'Z') || ('a' <= *value && *value <= 'z'))) {
322
return 0;
323
}
324
325
last = value + len;
326
++value;
327
328
for (; value != last; ++value) {
329
if (!(('A' <= *value && *value <= 'Z') ||
330
('a' <= *value && *value <= 'z') ||
331
('0' <= *value && *value <= '9') || *value == '+' || *value == '-' ||
332
*value == '.')) {
333
return 0;
334
}
335
}
336
return 1;
337
}
338
339
static int lws(const uint8_t *s, size_t n) {
340
size_t i;
341
for (i = 0; i < n; ++i) {
342
if (s[i] != ' ' && s[i] != '\t') {
343
return 0;
344
}
345
}
346
return 1;
347
}
348
349
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
350
nghttp2_frame *frame, nghttp2_hd_nv *nv,
351
int trailer) {
352
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
if (!nghttp2_check_header_name(nv->name->base, nv->name->len)) {
362
size_t i;
363
if (nv->name->len > 0 && nv->name->base[0] == ':') {
364
return NGHTTP2_ERR_HTTP_HEADER;
365
}
366
/* header field name must be lower-cased without exception */
367
for (i = 0; i < nv->name->len; ++i) {
368
uint8_t c = nv->name->base[i];
369
if ('A' <= c && c <= 'Z') {
370
return NGHTTP2_ERR_HTTP_HEADER;
371
}
372
}
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
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
377
return NGHTTP2_ERR_IGN_HTTP_HEADER;
378
}
379
380
switch (nv->token) {
381
case NGHTTP2_TOKEN__METHOD:
382
rv = nghttp2_check_method(nv->value->base, nv->value->len);
383
break;
384
case NGHTTP2_TOKEN__PATH:
385
rv = nghttp2_check_path(nv->value->base, nv->value->len);
386
break;
387
case NGHTTP2_TOKEN__AUTHORITY:
388
case NGHTTP2_TOKEN_HOST:
389
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
390
rv = nghttp2_check_authority(nv->value->base, nv->value->len);
391
} else if (
392
stream->flags &
393
NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
394
rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
395
} else {
396
rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
397
}
398
break;
399
case NGHTTP2_TOKEN__SCHEME:
400
rv = check_scheme(nv->value->base, nv->value->len);
401
break;
402
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
if ((stream->flags &
407
NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) &&
408
lws(nv->value->base, nv->value->len)) {
409
rv = 0;
410
break;
411
}
412
/* fall through */
413
default:
414
if (stream->flags &
415
NGHTTP2_STREAM_FLAG_NO_RFC9113_LEADING_AND_TRAILING_WS_VALIDATION) {
416
rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
417
} else {
418
rv = nghttp2_check_header_value_rfc9113(nv->value->base, nv->value->len);
419
}
420
}
421
422
if (rv == 0) {
423
assert(nv->name->len > 0);
424
if (nv->name->base[0] == ':') {
425
return NGHTTP2_ERR_HTTP_HEADER;
426
}
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
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
431
return NGHTTP2_ERR_IGN_HTTP_HEADER;
432
}
433
434
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
435
return http_request_on_header(stream, nv, trailer,
436
session->server &&
437
session->pending_enable_connect_protocol);
438
}
439
440
return http_response_on_header(stream, nv, trailer);
441
}
442
443
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
444
nghttp2_frame *frame) {
445
if (!(stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) &&
446
(stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) {
447
if ((stream->http_flags &
448
(NGHTTP2_HTTP_FLAG__SCHEME | NGHTTP2_HTTP_FLAG__PATH)) ||
449
(stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0) {
450
return -1;
451
}
452
stream->content_length = -1;
453
} else {
454
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
455
NGHTTP2_HTTP_FLAG_REQ_HEADERS ||
456
(stream->http_flags &
457
(NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
458
return -1;
459
}
460
if ((stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) &&
461
((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) == 0 ||
462
(stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0)) {
463
return -1;
464
}
465
if (!check_path(stream)) {
466
return -1;
467
}
468
}
469
470
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
stream->http_flags &= NGHTTP2_HTTP_FLAG_METH_ALL;
474
stream->content_length = -1;
475
}
476
477
return 0;
478
}
479
480
int nghttp2_http_on_response_headers(nghttp2_stream *stream) {
481
if ((stream->http_flags & NGHTTP2_HTTP_FLAG__STATUS) == 0) {
482
return -1;
483
}
484
485
if (stream->status_code / 100 == 1) {
486
/* non-final response */
487
stream->http_flags = (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
488
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
489
stream->content_length = -1;
490
stream->status_code = -1;
491
return 0;
492
}
493
494
stream->http_flags =
495
stream->http_flags & (uint32_t)~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE;
496
497
if (!expect_response_body(stream)) {
498
stream->content_length = 0;
499
} else if (stream->http_flags & (NGHTTP2_HTTP_FLAG_METH_CONNECT |
500
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND)) {
501
stream->content_length = -1;
502
}
503
504
return 0;
505
}
506
507
int nghttp2_http_on_trailer_headers(nghttp2_stream *stream,
508
nghttp2_frame *frame) {
509
(void)stream;
510
511
if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
512
return -1;
513
}
514
515
return 0;
516
}
517
518
int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream) {
519
if (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) {
520
return -1;
521
}
522
523
if (stream->content_length != -1 &&
524
stream->content_length != stream->recv_content_length) {
525
return -1;
526
}
527
528
return 0;
529
}
530
531
int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n) {
532
stream->recv_content_length += (int64_t)n;
533
534
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) ||
535
(stream->content_length != -1 &&
536
stream->recv_content_length > stream->content_length)) {
537
return -1;
538
}
539
540
return 0;
541
}
542
543
void nghttp2_http_record_request_method(nghttp2_stream *stream,
544
nghttp2_frame *frame) {
545
const nghttp2_nv *nva;
546
size_t nvlen;
547
size_t i;
548
549
switch (frame->hd.type) {
550
case NGHTTP2_HEADERS:
551
nva = frame->headers.nva;
552
nvlen = frame->headers.nvlen;
553
break;
554
case NGHTTP2_PUSH_PROMISE:
555
nva = frame->push_promise.nva;
556
nvlen = frame->push_promise.nvlen;
557
break;
558
default:
559
return;
560
}
561
562
/* TODO we should do this strictly. */
563
for (i = 0; i < nvlen; ++i) {
564
const nghttp2_nv *nv = &nva[i];
565
if (!(nv->namelen == 7 && nv->name[6] == 'd' &&
566
memcmp(":metho", nv->name, nv->namelen - 1) == 0)) {
567
continue;
568
}
569
if (lstreq("CONNECT", nv->value, nv->valuelen)) {
570
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
571
return;
572
}
573
if (lstreq("HEAD", nv->value, nv->valuelen)) {
574
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
575
return;
576
}
577
return;
578
}
579
}
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
static ssize_t sf_parse_key(const uint8_t *begin, const uint8_t *end) {
638
const uint8_t *p = begin;
639
640
if ((*p < 'a' || 'z' < *p) && *p != '*') {
641
return -1;
642
}
643
644
for (; p != end && SF_KEY_CHARS[*p]; ++p)
645
;
646
647
return p - begin;
648
}
649
650
static ssize_t sf_parse_integer_or_decimal(nghttp2_sf_value *dest,
651
const uint8_t *begin,
652
const uint8_t *end) {
653
const uint8_t *p = begin;
654
int sign = 1;
655
int64_t value = 0;
656
int type = NGHTTP2_SF_VALUE_TYPE_INTEGER;
657
size_t len = 0;
658
size_t fpos = 0;
659
size_t i;
660
661
if (*p == '-') {
662
if (++p == end) {
663
return -1;
664
}
665
666
sign = -1;
667
}
668
669
if (*p < '0' || '9' < *p) {
670
return -1;
671
}
672
673
for (; p != end; ++p) {
674
switch (*p) {
675
case '0':
676
case '1':
677
case '2':
678
case '3':
679
case '4':
680
case '5':
681
case '6':
682
case '7':
683
case '8':
684
case '9':
685
value *= 10;
686
value += *p - '0';
687
688
if (++len > 15) {
689
return -1;
690
}
691
692
break;
693
case '.':
694
if (type != NGHTTP2_SF_VALUE_TYPE_INTEGER) {
695
goto fin;
696
}
697
698
if (len > 12) {
699
return -1;
700
}
701
fpos = len;
702
type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
703
704
break;
705
default:
706
goto fin;
707
};
708
}
709
710
fin:
711
switch (type) {
712
case NGHTTP2_SF_VALUE_TYPE_INTEGER:
713
if (dest) {
714
dest->type = (uint8_t)type;
715
dest->i = value * sign;
716
}
717
718
return p - begin;
719
case NGHTTP2_SF_VALUE_TYPE_DECIMAL:
720
if (fpos == len || len - fpos > 3) {
721
return -1;
722
}
723
724
if (dest) {
725
dest->type = (uint8_t)type;
726
dest->d = (double)value;
727
for (i = len - fpos; i > 0; --i) {
728
dest->d /= (double)10;
729
}
730
dest->d *= sign;
731
}
732
733
return p - begin;
734
default:
735
assert(0);
736
abort();
737
}
738
}
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
const uint8_t *end) {
798
const uint8_t *p = begin;
799
800
if (*p++ != '"') {
801
return -1;
802
}
803
804
for (; p != end; ++p) {
805
switch (*p) {
806
case '\\':
807
if (++p == end) {
808
return -1;
809
}
810
811
switch (*p) {
812
case '"':
813
case '\\':
814
break;
815
default:
816
return -1;
817
}
818
819
break;
820
case '"':
821
if (dest) {
822
dest->type = NGHTTP2_SF_VALUE_TYPE_STRING;
823
dest->s.base = begin + 1;
824
dest->s.len = (size_t)(p - dest->s.base);
825
}
826
827
++p;
828
829
return p - begin;
830
default:
831
if (!SF_DQUOTE_CHARS[*p]) {
832
return -1;
833
}
834
}
835
}
836
837
return -1;
838
}
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
const uint8_t *end) {
898
const uint8_t *p = begin;
899
900
if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') {
901
return -1;
902
}
903
904
for (; p != end && SF_TOKEN_CHARS[*p]; ++p)
905
;
906
907
if (dest) {
908
dest->type = NGHTTP2_SF_VALUE_TYPE_TOKEN;
909
dest->s.base = begin;
910
dest->s.len = (size_t)(p - begin);
911
}
912
913
return p - begin;
914
}
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
const uint8_t *end) {
974
const uint8_t *p = begin;
975
976
if (*p++ != ':') {
977
return -1;
978
}
979
980
for (; p != end; ++p) {
981
switch (*p) {
982
case ':':
983
if (dest) {
984
dest->type = NGHTTP2_SF_VALUE_TYPE_BYTESEQ;
985
dest->s.base = begin + 1;
986
dest->s.len = (size_t)(p - dest->s.base);
987
}
988
989
++p;
990
991
return p - begin;
992
default:
993
if (!SF_BYTESEQ_CHARS[*p]) {
994
return -1;
995
}
996
}
997
}
998
999
return -1;
1000
}
1001
1002
static ssize_t sf_parse_boolean(nghttp2_sf_value *dest, const uint8_t *begin,
1003
const uint8_t *end) {
1004
const uint8_t *p = begin;
1005
int b;
1006
1007
if (*p++ != '?') {
1008
return -1;
1009
}
1010
1011
if (p == end) {
1012
return -1;
1013
}
1014
1015
switch (*p++) {
1016
case '0':
1017
b = 0;
1018
break;
1019
case '1':
1020
b = 1;
1021
break;
1022
default:
1023
return -1;
1024
}
1025
1026
if (dest) {
1027
dest->type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
1028
dest->b = b;
1029
}
1030
1031
return p - begin;
1032
}
1033
1034
static ssize_t sf_parse_bare_item(nghttp2_sf_value *dest, const uint8_t *begin,
1035
const uint8_t *end) {
1036
switch (*begin) {
1037
case '-':
1038
case '0':
1039
case '1':
1040
case '2':
1041
case '3':
1042
case '4':
1043
case '5':
1044
case '6':
1045
case '7':
1046
case '8':
1047
case '9':
1048
return sf_parse_integer_or_decimal(dest, begin, end);
1049
case '"':
1050
return sf_parse_string(dest, begin, end);
1051
case '*':
1052
return sf_parse_token(dest, begin, end);
1053
case ':':
1054
return sf_parse_byteseq(dest, begin, end);
1055
case '?':
1056
return sf_parse_boolean(dest, begin, end);
1057
default:
1058
if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) {
1059
return sf_parse_token(dest, begin, end);
1060
}
1061
return -1;
1062
}
1063
}
1064
1065
#define sf_discard_sp_end_err(BEGIN, END, ERR) \
1066
for (;; ++(BEGIN)) { \
1067
if ((BEGIN) == (END)) { \
1068
return (ERR); \
1069
} \
1070
if (*(BEGIN) != ' ') { \
1071
break; \
1072
} \
1073
}
1074
1075
static ssize_t sf_parse_params(const uint8_t *begin, const uint8_t *end) {
1076
const uint8_t *p = begin;
1077
ssize_t slen;
1078
1079
for (; p != end && *p == ';';) {
1080
++p;
1081
1082
sf_discard_sp_end_err(p, end, -1);
1083
1084
slen = sf_parse_key(p, end);
1085
if (slen < 0) {
1086
return -1;
1087
}
1088
1089
p += slen;
1090
1091
if (p == end || *p != '=') {
1092
/* Boolean true */
1093
} else if (++p == end) {
1094
return -1;
1095
} else {
1096
slen = sf_parse_bare_item(NULL, p, end);
1097
if (slen < 0) {
1098
return -1;
1099
}
1100
1101
p += slen;
1102
}
1103
}
1104
1105
return p - begin;
1106
}
1107
1108
static ssize_t sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
1109
const uint8_t *end) {
1110
const uint8_t *p = begin;
1111
ssize_t slen;
1112
1113
slen = sf_parse_bare_item(dest, p, end);
1114
if (slen < 0) {
1115
return -1;
1116
}
1117
1118
p += slen;
1119
1120
slen = sf_parse_params(p, end);
1121
if (slen < 0) {
1122
return -1;
1123
}
1124
1125
p += slen;
1126
1127
return p - begin;
1128
}
1129
1130
ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
1131
const uint8_t *end) {
1132
return sf_parse_item(dest, begin, end);
1133
}
1134
1135
static ssize_t sf_parse_inner_list(nghttp2_sf_value *dest, const uint8_t *begin,
1136
const uint8_t *end) {
1137
const uint8_t *p = begin;
1138
ssize_t slen;
1139
1140
if (*p++ != '(') {
1141
return -1;
1142
}
1143
1144
for (;;) {
1145
sf_discard_sp_end_err(p, end, -1);
1146
1147
if (*p == ')') {
1148
++p;
1149
1150
slen = sf_parse_params(p, end);
1151
if (slen < 0) {
1152
return -1;
1153
}
1154
1155
p += slen;
1156
1157
if (dest) {
1158
dest->type = NGHTTP2_SF_VALUE_TYPE_INNER_LIST;
1159
}
1160
1161
return p - begin;
1162
}
1163
1164
slen = sf_parse_item(NULL, p, end);
1165
if (slen < 0) {
1166
return -1;
1167
}
1168
1169
p += slen;
1170
1171
if (p == end || (*p != ' ' && *p != ')')) {
1172
return -1;
1173
}
1174
}
1175
}
1176
1177
ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
1178
const uint8_t *begin, const uint8_t *end) {
1179
return sf_parse_inner_list(dest, begin, end);
1180
}
1181
1182
static ssize_t sf_parse_item_or_inner_list(nghttp2_sf_value *dest,
1183
const uint8_t *begin,
1184
const uint8_t *end) {
1185
if (*begin == '(') {
1186
return sf_parse_inner_list(dest, begin, end);
1187
}
1188
1189
return sf_parse_item(dest, begin, end);
1190
}
1191
1192
#define sf_discard_ows(BEGIN, END) \
1193
for (;; ++(BEGIN)) { \
1194
if ((BEGIN) == (END)) { \
1195
goto fin; \
1196
} \
1197
if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
1198
break; \
1199
} \
1200
}
1201
1202
#define sf_discard_ows_end_err(BEGIN, END, ERR) \
1203
for (;; ++(BEGIN)) { \
1204
if ((BEGIN) == (END)) { \
1205
return (ERR); \
1206
} \
1207
if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
1208
break; \
1209
} \
1210
}
1211
1212
int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
1213
size_t valuelen) {
1214
const uint8_t *p = value, *end = value + valuelen;
1215
ssize_t slen;
1216
nghttp2_sf_value val;
1217
nghttp2_extpri pri = *dest;
1218
const uint8_t *key;
1219
size_t keylen;
1220
1221
for (; p != end && *p == ' '; ++p)
1222
;
1223
1224
for (; p != end;) {
1225
slen = sf_parse_key(p, end);
1226
if (slen < 0) {
1227
return NGHTTP2_ERR_INVALID_ARGUMENT;
1228
}
1229
1230
key = p;
1231
keylen = (size_t)slen;
1232
1233
p += slen;
1234
1235
if (p == end || *p != '=') {
1236
/* Boolean true */
1237
val.type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
1238
val.b = 1;
1239
1240
slen = sf_parse_params(p, end);
1241
if (slen < 0) {
1242
return NGHTTP2_ERR_INVALID_ARGUMENT;
1243
}
1244
} else if (++p == end) {
1245
return NGHTTP2_ERR_INVALID_ARGUMENT;
1246
} else {
1247
slen = sf_parse_item_or_inner_list(&val, p, end);
1248
if (slen < 0) {
1249
return NGHTTP2_ERR_INVALID_ARGUMENT;
1250
}
1251
}
1252
1253
p += slen;
1254
1255
if (keylen == 1) {
1256
switch (key[0]) {
1257
case 'i':
1258
if (val.type != NGHTTP2_SF_VALUE_TYPE_BOOLEAN) {
1259
return NGHTTP2_ERR_INVALID_ARGUMENT;
1260
}
1261
1262
pri.inc = val.b;
1263
1264
break;
1265
case 'u':
1266
if (val.type != NGHTTP2_SF_VALUE_TYPE_INTEGER ||
1267
val.i < NGHTTP2_EXTPRI_URGENCY_HIGH ||
1268
NGHTTP2_EXTPRI_URGENCY_LOW < val.i) {
1269
return NGHTTP2_ERR_INVALID_ARGUMENT;
1270
}
1271
1272
pri.urgency = (uint32_t)val.i;
1273
1274
break;
1275
}
1276
}
1277
1278
sf_discard_ows(p, end);
1279
1280
if (*p++ != ',') {
1281
return NGHTTP2_ERR_INVALID_ARGUMENT;
1282
}
1283
1284
sf_discard_ows_end_err(p, end, NGHTTP2_ERR_INVALID_ARGUMENT);
1285
}
1286
1287
fin:
1288
*dest = pri;
1289
1290
return 0;
1291
}
1292
1293