Import ngtcp2/sfparse, Structured Field Values parser

This commit is contained in:
Tatsuhiro Tsujikawa 2023-04-22 17:41:07 +09:00
parent cc1402bf44
commit 2ee33fe8cd
9 changed files with 1594 additions and 1199 deletions

View File

@ -25,6 +25,7 @@ set(NGHTTP2_SOURCES
nghttp2_rcbuf.c
nghttp2_extpri.c
nghttp2_debug.c
sfparse.c
)
set(NGHTTP2_RES "")

View File

@ -51,7 +51,8 @@ OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
nghttp2_http.c \
nghttp2_rcbuf.c \
nghttp2_extpri.c \
nghttp2_debug.c
nghttp2_debug.c \
sfparse.c
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_frame.h \
@ -68,7 +69,8 @@ HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
nghttp2_http.h \
nghttp2_rcbuf.h \
nghttp2_extpri.h \
nghttp2_debug.h
nghttp2_debug.h \
sfparse.h
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
libnghttp2_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined \

View File

@ -31,6 +31,7 @@
#include "nghttp2_hd.h"
#include "nghttp2_helper.h"
#include "nghttp2_extpri.h"
#include "sfparse.h"
static uint8_t downcase(uint8_t c) {
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
@ -578,713 +579,52 @@ void nghttp2_http_record_request_method(nghttp2_stream *stream,
}
}
/* Generated by genchartbl.py */
static const int SF_KEY_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */,
0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */,
0 /* ( */, 0 /* ) */, 1 /* * */, 0 /* + */, 0 /* , */,
1 /* - */, 1 /* . */, 0 /* / */, 1 /* 0 */, 1 /* 1 */,
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
0 /* A */, 0 /* B */, 0 /* C */, 0 /* D */, 0 /* E */,
0 /* F */, 0 /* G */, 0 /* H */, 0 /* I */, 0 /* J */,
0 /* K */, 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, 0 /* T */,
0 /* U */, 0 /* V */, 0 /* W */, 0 /* X */, 0 /* Y */,
0 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */,
1 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */,
0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
0 /* 0xff */,
};
static ssize_t sf_parse_key(const uint8_t *begin, const uint8_t *end) {
const uint8_t *p = begin;
if ((*p < 'a' || 'z' < *p) && *p != '*') {
return -1;
}
for (; p != end && SF_KEY_CHARS[*p]; ++p)
;
return (ssize_t)(p - begin);
}
static ssize_t sf_parse_integer_or_decimal(nghttp2_sf_value *dest,
const uint8_t *begin,
const uint8_t *end) {
const uint8_t *p = begin;
int sign = 1;
int64_t value = 0;
int type = NGHTTP2_SF_VALUE_TYPE_INTEGER;
size_t len = 0;
size_t fpos = 0;
size_t i;
if (*p == '-') {
if (++p == end) {
return -1;
}
sign = -1;
}
if (*p < '0' || '9' < *p) {
return -1;
}
for (; p != end; ++p) {
switch (*p) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
value *= 10;
value += *p - '0';
if (++len > 15) {
return -1;
}
break;
case '.':
if (type != NGHTTP2_SF_VALUE_TYPE_INTEGER) {
goto fin;
}
if (len > 12) {
return -1;
}
fpos = len;
type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
break;
default:
goto fin;
};
}
fin:
switch (type) {
case NGHTTP2_SF_VALUE_TYPE_INTEGER:
if (dest) {
dest->type = (uint8_t)type;
dest->i = value * sign;
}
return (ssize_t)(p - begin);
case NGHTTP2_SF_VALUE_TYPE_DECIMAL:
if (fpos == len || len - fpos > 3) {
return -1;
}
if (dest) {
dest->type = (uint8_t)type;
dest->d = (double)value;
for (i = len - fpos; i > 0; --i) {
dest->d /= (double)10;
}
dest->d *= sign;
}
return (ssize_t)(p - begin);
default:
assert(0);
abort();
}
}
/* Generated by genchartbl.py */
static const int SF_DQUOTE_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
0 /* RS */, 0 /* US */, 1 /* SPC */, 1 /* ! */, 0 /* " */,
1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* , */,
1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, 1 /* @ */,
1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
1 /* Z */, 1 /* [ */, 0 /* \ */, 1 /* ] */, 1 /* ^ */,
1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, 1 /* | */,
1 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
0 /* 0xff */,
};
static ssize_t sf_parse_string(nghttp2_sf_value *dest, const uint8_t *begin,
const uint8_t *end) {
const uint8_t *p = begin;
if (*p++ != '"') {
return -1;
}
for (; p != end; ++p) {
switch (*p) {
case '\\':
if (++p == end) {
return -1;
}
switch (*p) {
case '"':
case '\\':
break;
default:
return -1;
}
break;
case '"':
if (dest) {
dest->type = NGHTTP2_SF_VALUE_TYPE_STRING;
dest->s.base = begin + 1;
dest->s.len = (size_t)(p - dest->s.base);
}
++p;
return (ssize_t)(p - begin);
default:
if (!SF_DQUOTE_CHARS[*p]) {
return -1;
}
}
}
return -1;
}
/* Generated by genchartbl.py */
static const int SF_TOKEN_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
0 /* RS */, 0 /* US */, 0 /* SPC */, 1 /* ! */, 0 /* " */,
1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, 0 /* , */,
1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 0 /* ; */,
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 1 /* ^ */,
1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* | */,
0 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
0 /* 0xff */,
};
static ssize_t sf_parse_token(nghttp2_sf_value *dest, const uint8_t *begin,
const uint8_t *end) {
const uint8_t *p = begin;
if ((*p < 'A' || 'Z' < *p) && (*p < 'a' || 'z' < *p) && *p != '*') {
return -1;
}
for (; p != end && SF_TOKEN_CHARS[*p]; ++p)
;
if (dest) {
dest->type = NGHTTP2_SF_VALUE_TYPE_TOKEN;
dest->s.base = begin;
dest->s.len = (size_t)(p - begin);
}
return (ssize_t)(p - begin);
}
/* Generated by genchartbl.py */
static const int SF_BYTESEQ_CHARS[] = {
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
0 /* RS */, 0 /* US */, 0 /* SPC */, 0 /* ! */, 0 /* " */,
0 /* # */, 0 /* $ */, 0 /* % */, 0 /* & */, 0 /* ' */,
0 /* ( */, 0 /* ) */, 0 /* * */, 1 /* + */, 0 /* , */,
0 /* - */, 0 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
1 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 0 /* ^ */,
0 /* _ */, 0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 0 /* | */,
0 /* } */, 0 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
0 /* 0xff */,
};
static ssize_t sf_parse_byteseq(nghttp2_sf_value *dest, const uint8_t *begin,
const uint8_t *end) {
const uint8_t *p = begin;
if (*p++ != ':') {
return -1;
}
for (; p != end; ++p) {
switch (*p) {
case ':':
if (dest) {
dest->type = NGHTTP2_SF_VALUE_TYPE_BYTESEQ;
dest->s.base = begin + 1;
dest->s.len = (size_t)(p - dest->s.base);
}
++p;
return (ssize_t)(p - begin);
default:
if (!SF_BYTESEQ_CHARS[*p]) {
return -1;
}
}
}
return -1;
}
static ssize_t sf_parse_boolean(nghttp2_sf_value *dest, const uint8_t *begin,
const uint8_t *end) {
const uint8_t *p = begin;
int b;
if (*p++ != '?') {
return -1;
}
if (p == end) {
return -1;
}
switch (*p++) {
case '0':
b = 0;
break;
case '1':
b = 1;
break;
default:
return -1;
}
if (dest) {
dest->type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
dest->b = b;
}
return (ssize_t)(p - begin);
}
static ssize_t sf_parse_bare_item(nghttp2_sf_value *dest, const uint8_t *begin,
const uint8_t *end) {
switch (*begin) {
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return sf_parse_integer_or_decimal(dest, begin, end);
case '"':
return sf_parse_string(dest, begin, end);
case '*':
return sf_parse_token(dest, begin, end);
case ':':
return sf_parse_byteseq(dest, begin, end);
case '?':
return sf_parse_boolean(dest, begin, end);
default:
if (('A' <= *begin && *begin <= 'Z') || ('a' <= *begin && *begin <= 'z')) {
return sf_parse_token(dest, begin, end);
}
return -1;
}
}
#define sf_discard_sp_end_err(BEGIN, END, ERR) \
for (;; ++(BEGIN)) { \
if ((BEGIN) == (END)) { \
return (ERR); \
} \
if (*(BEGIN) != ' ') { \
break; \
} \
}
static ssize_t sf_parse_params(const uint8_t *begin, const uint8_t *end) {
const uint8_t *p = begin;
ssize_t slen;
for (; p != end && *p == ';';) {
++p;
sf_discard_sp_end_err(p, end, -1);
slen = sf_parse_key(p, end);
if (slen < 0) {
return -1;
}
p += slen;
if (p == end || *p != '=') {
/* Boolean true */
} else if (++p == end) {
return -1;
} else {
slen = sf_parse_bare_item(NULL, p, end);
if (slen < 0) {
return -1;
}
p += slen;
}
}
return (ssize_t)(p - begin);
}
static ssize_t sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
const uint8_t *end) {
const uint8_t *p = begin;
ssize_t slen;
slen = sf_parse_bare_item(dest, p, end);
if (slen < 0) {
return -1;
}
p += slen;
slen = sf_parse_params(p, end);
if (slen < 0) {
return -1;
}
p += slen;
return (ssize_t)(p - begin);
}
ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
const uint8_t *end) {
return sf_parse_item(dest, begin, end);
}
static ssize_t sf_parse_inner_list(nghttp2_sf_value *dest, const uint8_t *begin,
const uint8_t *end) {
const uint8_t *p = begin;
ssize_t slen;
if (*p++ != '(') {
return -1;
}
for (;;) {
sf_discard_sp_end_err(p, end, -1);
if (*p == ')') {
++p;
slen = sf_parse_params(p, end);
if (slen < 0) {
return -1;
}
p += slen;
if (dest) {
dest->type = NGHTTP2_SF_VALUE_TYPE_INNER_LIST;
}
return (ssize_t)(p - begin);
}
slen = sf_parse_item(NULL, p, end);
if (slen < 0) {
return -1;
}
p += slen;
if (p == end || (*p != ' ' && *p != ')')) {
return -1;
}
}
}
ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
const uint8_t *begin, const uint8_t *end) {
return sf_parse_inner_list(dest, begin, end);
}
static ssize_t sf_parse_item_or_inner_list(nghttp2_sf_value *dest,
const uint8_t *begin,
const uint8_t *end) {
if (*begin == '(') {
return sf_parse_inner_list(dest, begin, end);
}
return sf_parse_item(dest, begin, end);
}
#define sf_discard_ows(BEGIN, END) \
for (;; ++(BEGIN)) { \
if ((BEGIN) == (END)) { \
goto fin; \
} \
if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
break; \
} \
}
#define sf_discard_ows_end_err(BEGIN, END, ERR) \
for (;; ++(BEGIN)) { \
if ((BEGIN) == (END)) { \
return (ERR); \
} \
if (*(BEGIN) != ' ' && *(BEGIN) != '\t') { \
break; \
} \
}
int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
size_t valuelen) {
const uint8_t *p = value, *end = value + valuelen;
ssize_t slen;
nghttp2_sf_value val;
nghttp2_extpri pri = *dest;
const uint8_t *key;
size_t keylen;
sf_parser sfp;
sf_vec key;
sf_value val;
int rv;
for (; p != end && *p == ' '; ++p)
;
for (; p != end;) {
slen = sf_parse_key(p, end);
if (slen < 0) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
key = p;
keylen = (size_t)slen;
p += slen;
if (p == end || *p != '=') {
/* Boolean true */
val.type = NGHTTP2_SF_VALUE_TYPE_BOOLEAN;
val.b = 1;
slen = sf_parse_params(p, end);
if (slen < 0) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
} else if (++p == end) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
} else {
slen = sf_parse_item_or_inner_list(&val, p, end);
if (slen < 0) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
}
p += slen;
if (keylen == 1) {
switch (key[0]) {
case 'i':
if (val.type != NGHTTP2_SF_VALUE_TYPE_BOOLEAN) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
pri.inc = val.b;
break;
case 'u':
if (val.type != NGHTTP2_SF_VALUE_TYPE_INTEGER ||
val.i < NGHTTP2_EXTPRI_URGENCY_HIGH ||
NGHTTP2_EXTPRI_URGENCY_LOW < val.i) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
pri.urgency = (uint32_t)val.i;
sf_parser_init(&sfp, value, valuelen);
for (;;) {
rv = sf_parser_dict(&sfp, &key, &val);
if (rv != 0) {
if (rv == SF_ERR_EOF) {
break;
}
}
sf_discard_ows(p, end);
if (*p++ != ',') {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
sf_discard_ows_end_err(p, end, NGHTTP2_ERR_INVALID_ARGUMENT);
if (key.len != 1) {
continue;
}
switch (key.base[0]) {
case 'i':
if (val.type != SF_TYPE_BOOLEAN) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
pri.inc = val.boolean;
break;
case 'u':
if (val.type != SF_TYPE_INTEGER ||
val.integer < NGHTTP2_EXTPRI_URGENCY_HIGH ||
NGHTTP2_EXTPRI_URGENCY_LOW < val.integer) {
return NGHTTP2_ERR_INVALID_ARGUMENT;
}
pri.urgency = (uint32_t)val.integer;
break;
}
}
fin:
*dest = pri;
return 0;

View File

@ -94,54 +94,6 @@ int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n);
void nghttp2_http_record_request_method(nghttp2_stream *stream,
nghttp2_frame *frame);
/*
* RFC 8941 Structured Field Values.
*/
typedef enum nghttp2_sf_value_type {
NGHTTP2_SF_VALUE_TYPE_BOOLEAN,
NGHTTP2_SF_VALUE_TYPE_INTEGER,
NGHTTP2_SF_VALUE_TYPE_DECIMAL,
NGHTTP2_SF_VALUE_TYPE_STRING,
NGHTTP2_SF_VALUE_TYPE_TOKEN,
NGHTTP2_SF_VALUE_TYPE_BYTESEQ,
NGHTTP2_SF_VALUE_TYPE_INNER_LIST,
} nghttp2_sf_value_type;
/*
* nghttp2_sf_value stores Structured Field Values item. For Inner
* List, only type is set to NGHTTP2_SF_VALUE_TYPE_INNER_LIST.
*/
typedef struct nghttp2_sf_value {
uint8_t type;
union {
int b;
int64_t i;
double d;
struct {
const uint8_t *base;
size_t len;
} s;
};
} nghttp2_sf_value;
/*
* nghttp2_sf_parse_item parses the input sequence [|begin|, |end|)
* and stores the parsed an Item in |dest|. It returns the number of
* bytes consumed if it succeeds, or -1. This function is declared
* here for unit tests.
*/
ssize_t nghttp2_sf_parse_item(nghttp2_sf_value *dest, const uint8_t *begin,
const uint8_t *end);
/*
* nghttp2_sf_parse_inner_list parses the input sequence [|begin|, |end|)
* and stores the parsed an Inner List in |dest|. It returns the number of
* bytes consumed if it succeeds, or -1. This function is declared
* here for unit tests.
*/
ssize_t nghttp2_sf_parse_inner_list(nghttp2_sf_value *dest,
const uint8_t *begin, const uint8_t *end);
int nghttp2_http_parse_priority(nghttp2_extpri *dest, const uint8_t *value,
size_t valuelen);

1146
lib/sfparse.c Normal file

File diff suppressed because it is too large Load Diff

409
lib/sfparse.h Normal file
View File

@ -0,0 +1,409 @@
/*
* sfparse
*
* Copyright (c) 2023 sfparse contributors
* Copyright (c) 2019 nghttp3 contributors
* Copyright (c) 2015 nghttp2 contributors
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SFPARSE_H
#define SFPARSE_H
/* Define WIN32 when build target is Win32 API (borrowed from
libcurl) */
#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
# define WIN32
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_MSC_VER) && (_MSC_VER < 1800)
/* MSVC < 2013 does not have inttypes.h because it is not C99
compliant. See compiler macros and version number in
https://sourceforge.net/p/predef/wiki/Compilers/ */
# include <stdint.h>
#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
# include <inttypes.h>
#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
#include <sys/types.h>
#include <stddef.h>
/**
* @enum
*
* :type:`sf_type` defines value type.
*/
typedef enum sf_type {
/**
* :enum:`SF_TYPE_BOOLEAN` indicates boolean type.
*/
SF_TYPE_BOOLEAN,
/**
* :enum:`SF_TYPE_INTEGER` indicates integer type.
*/
SF_TYPE_INTEGER,
/**
* :enum:`SF_TYPE_DECIMAL` indicates decimal type.
*/
SF_TYPE_DECIMAL,
/**
* :enum:`SF_TYPE_STRING` indicates string type.
*/
SF_TYPE_STRING,
/**
* :enum:`SF_TYPE_TOKEN` indicates token type.
*/
SF_TYPE_TOKEN,
/**
* :enum:`SF_TYPE_BYTESEQ` indicates byte sequence type.
*/
SF_TYPE_BYTESEQ,
/**
* :enum:`SF_TYPE_INNER_LIST` indicates inner list type.
*/
SF_TYPE_INNER_LIST,
/**
* :enum:`SF_TYPE_DATE` indicates date type.
*/
SF_TYPE_DATE
} sf_type;
/**
* @macro
*
* :macro:`SF_ERR_PARSE_ERROR` indicates fatal parse error has
* occurred, and it is not possible to continue the processing.
*/
#define SF_ERR_PARSE_ERROR -1
/**
* @macro
*
* :macro:`SF_ERR_EOF` indicates that there is nothing left to read.
* The context of this error varies depending on the function that
* returns this error code.
*/
#define SF_ERR_EOF -2
/**
* @struct
*
* :type:`sf_vec` stores sequence of bytes.
*/
typedef struct sf_vec {
/**
* :member:`base` points to the beginning of the sequence of bytes.
*/
uint8_t *base;
/**
* :member:`len` is the number of bytes contained in this sequence.
*/
size_t len;
} sf_vec;
/**
* @macro
*
* :macro:`SF_VALUE_FLAG_NONE` indicates no flag set.
*/
#define SF_VALUE_FLAG_NONE 0x0u
/**
* @macro
*
* :macro:`SF_VALUE_FLAG_ESCAPED_STRING` indicates that a string
* contains escaped character(s).
*/
#define SF_VALUE_FLAG_ESCAPED_STRING 0x1u
/**
* @struct
*
* :type:`sf_decimal` contains decimal value.
*/
typedef struct sf_decimal {
/**
* :member:`numer` contains numerator of the decimal value.
*/
int64_t numer;
/**
* :member:`denom` contains denominator of the decimal value.
*/
int64_t denom;
} sf_decimal;
/**
* @struct
*
* :type:`sf_value` stores a Structured Field item. For Inner List,
* only type is set to :enum:`sf_type.SF_TYPE_INNER_LIST`. In order
* to read the items contained in an inner list, call
* `sf_parser_inner_list`.
*/
typedef struct sf_value {
/**
* :member:`type` is the type of the value contained in this
* particular object.
*/
sf_type type;
/**
* :member:`flags` is bitwise OR of one or more of
* :macro:`SF_VALUE_FLAG_* <SF_VALUE_FLAG_NONE>`.
*/
uint32_t flags;
/**
* @anonunion_start
*
* @sf_value_value
*/
union {
/**
* :member:`boolean` contains boolean value if :member:`type` ==
* :enum:`sf_type.SF_TYPE_BOOLEAN`. 1 indicates true, and 0
* indicates false.
*/
int boolean;
/**
* :member:`integer` contains integer value if :member:`type` is
* either :enum:`sf_type.SF_TYPE_INTEGER` or
* :enum:`sf_type.SF_TYPE_DATE`.
*/
int64_t integer;
/**
* :member:`decimal` contains decimal value if :member:`type` ==
* :enum:`sf_type.SF_TYPE_DECIMAL`.
*/
sf_decimal decimal;
/**
* :member:`vec` contains sequence of bytes if :member:`type` is
* either :enum:`sf_type.SF_TYPE_STRING`,
* :enum:`sf_type.SF_TYPE_TOKEN`, or
* :enum:`sf_type.SF_TYPE_BYTESEQ`.
*
* For :enum:`sf_type.SF_TYPE_STRING`, this field contains one or
* more escaped characters if :member:`flags` has
* :macro:`SF_VALUE_FLAG_ESCAPED_STRING` set. To unescape the
* string, use `sf_unescape`.
*
* For :enum:`sf_type.SF_TYPE_BYTESEQ`, this field contains base64
* encoded string. To decode this byte string, use
* `sf_base64decode`.
*
* If :member:`vec.len <sf_vec.len>` == 0, :member:`vec.base
* <sf_vec.base>` is guaranteed to be NULL.
*/
sf_vec vec;
/**
* @anonunion_end
*/
};
} sf_value;
/**
* @struct
*
* :type:`sf_parser` is the Structured Field Values parser. Use
* `sf_parser_init` to initialize it.
*/
typedef struct sf_parser {
/* all fields are private */
const uint8_t *pos;
const uint8_t *end;
uint32_t state;
} sf_parser;
/**
* @function
*
* `sf_parser_init` initializes |sfp| with the given buffer pointed by
* |data| of length |datalen|.
*/
void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen);
/**
* @function
*
* `sf_parser_param` reads a parameter. If this function returns 0,
* it stores parameter key and value in |dest_key| and |dest_value|
* respectively, if they are not NULL.
*
* This function does no effort to find duplicated keys. Same key may
* be reported more than once.
*
* Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SF_ERR_EOF`, all parameters have
* read, and caller can continue to read rest of the values. If it
* returns :macro:`SF_ERR_PARSE_ERROR`, it encountered fatal error
* while parsing field value.
*/
int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value);
/**
* @function
*
* `sf_parser_dict` reads the next dictionary key and value pair. If
* this function returns 0, it stores the key and value in |dest_key|
* and |dest_value| respectively, if they are not NULL.
*
* Caller can optionally read parameters attached to the pair by
* calling `sf_parser_param`.
*
* This function does no effort to find duplicated keys. Same key may
* be reported more than once.
*
* Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SF_ERR_EOF`, all key and value
* pairs have been read, and there is nothing left to read.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :macro:`SF_ERR_EOF`
* All values in the dictionary have read.
* :macro:`SF_ERR_PARSE_ERROR`
* It encountered fatal error while parsing field value.
*/
int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value);
/**
* @function
*
* `sf_parser_list` reads the next list item. If this function
* returns 0, it stores the item in |dest| if it is not NULL.
*
* Caller can optionally read parameters attached to the item by
* calling `sf_parser_param`.
*
* Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SF_ERR_EOF`, all values in the
* list have been read, and there is nothing left to read.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :macro:`SF_ERR_EOF`
* All values in the list have read.
* :macro:`SF_ERR_PARSE_ERROR`
* It encountered fatal error while parsing field value.
*/
int sf_parser_list(sf_parser *sfp, sf_value *dest);
/**
* @function
*
* `sf_parser_item` reads a single item. If this function returns 0,
* it stores the item in |dest| if it is not NULL.
*
* This function is only used for the field value that consists of a
* single item.
*
* Caller can optionally read parameters attached to the item by
* calling `sf_parser_param`.
*
* Caller should call this function again to make sure that there is
* nothing left to read. If this 2nd function call returns
* :macro:`SF_ERR_EOF`, all data have been processed successfully.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :macro:`SF_ERR_EOF`
* There is nothing left to read.
* :macro:`SF_ERR_PARSE_ERROR`
* It encountered fatal error while parsing field value.
*/
int sf_parser_item(sf_parser *sfp, sf_value *dest);
/**
* @function
*
* `sf_parser_inner_list` reads the next inner list item. If this
* function returns 0, it stores the item in |dest| if it is not NULL.
*
* Caller can optionally read parameters attached to the item by
* calling `sf_parser_param`.
*
* Caller should keep calling this function until it returns negative
* error code. If it returns :macro:`SF_ERR_EOF`, all values in this
* inner list have been read, and caller can optionally read
* parameters attached to this inner list by calling
* `sf_parser_param`. Then caller can continue to read rest of the
* values.
*
* This function returns 0 if it succeeds, or one of the following
* negative error codes:
*
* :macro:`SF_ERR_EOF`
* All values in the inner list have read.
* :macro:`SF_ERR_PARSE_ERROR`
* It encountered fatal error while parsing field value.
*/
int sf_parser_inner_list(sf_parser *sfp, sf_value *dest);
/**
* @function
*
* `sf_unescape` copies |src| to |dest| by removing escapes (``\``).
* |src| should be the pointer to :member:`sf_value.vec` of type
* :enum:`sf_type.SF_TYPE_STRING` produced by either `sf_parser_dict`,
* `sf_parser_list`, `sf_parser_inner_list`, `sf_parser_item`, or
* `sf_parser_param`, otherwise the behavior is undefined.
*
* :member:`dest->base <sf_vec.base>` must point to the buffer that
* has sufficient space to store the unescaped string.
*
* If there is no escape character in |src|, |*src| is assigned to
* |*dest|. This includes the case that :member:`src->len
* <sf_vec.len>` == 0.
*
* This function sets the length of unescaped string to
* :member:`dest->len <sf_vec.len>`.
*/
void sf_unescape(sf_vec *dest, const sf_vec *src);
/**
* @function
*
* `sf_base64decode` decodes Base64 encoded string |src| and writes
* the result into |dest|. |src| should be the pointer to
* :member:`sf_value.vec` of type :enum:`sf_type.SF_TYPE_BYTESEQ`
* produced by either `sf_parser_dict`, `sf_parser_list`,
* `sf_parser_inner_list`, `sf_parser_item`, or `sf_parser_param`,
* otherwise the behavior is undefined.
*
* :member:`dest->base <sf_vec.base>` must point to the buffer that
* has sufficient space to store the decoded byte string.
*
* If :member:`src->len <sf_vec.len>` == 0, |*src| is assigned to
* |*dest|.
*
* This function sets the length of decoded byte string to
* :member:`dest->len <sf_vec.len>`.
*/
void sf_base64decode(sf_vec *dest, const sf_vec *src);
#ifdef __cplusplus
}
#endif
#endif /* SFPARSE_H */

View File

@ -449,9 +449,6 @@ int main(void) {
!CU_add_test(pSuite, "bufs_realloc", test_nghttp2_bufs_realloc) ||
!CU_add_test(pSuite, "http_parse_priority",
test_nghttp2_http_parse_priority) ||
!CU_add_test(pSuite, "sf_parse_item", test_nghttp2_sf_parse_item) ||
!CU_add_test(pSuite, "sf_parse_inner_list",
test_nghttp2_sf_parse_inner_list) ||
!CU_add_test(pSuite, "extpri_to_uint8", test_nghttp2_extpri_to_uint8)) {
CU_cleanup_registry();
return (int)CU_get_error();

View File

@ -204,453 +204,3 @@ void test_nghttp2_http_parse_priority(void) {
CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT == rv);
}
}
void test_nghttp2_sf_parse_item(void) {
{
nghttp2_sf_value val;
const uint8_t s[] = "?1";
val.type = 0xff;
CU_ASSERT(2 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BOOLEAN == val.type);
CU_ASSERT(1 == val.b);
}
{
nghttp2_sf_value val;
const uint8_t s[] = "?1 ";
val.type = 0xff;
CU_ASSERT(2 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BOOLEAN == val.type);
CU_ASSERT(1 == val.b);
}
{
nghttp2_sf_value val;
const uint8_t s[] = "?1;foo=bar";
val.type = 0xff;
CU_ASSERT(10 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BOOLEAN == val.type);
CU_ASSERT(1 == val.b);
}
{
const uint8_t s[] = {'?', '1', ';', 'f', 'o', 'o', '='};
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s)));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "?0";
val.type = 0xff;
CU_ASSERT(2 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BOOLEAN == val.type);
CU_ASSERT(0 == val.b);
}
{
nghttp2_sf_value val;
const uint8_t s[] = "?0 ";
val.type = 0xff;
CU_ASSERT(2 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BOOLEAN == val.type);
CU_ASSERT(0 == val.b);
}
{
const uint8_t s[] = "?2";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "?";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "?1";
CU_ASSERT(2 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
nghttp2_sf_value val;
const uint8_t s[] = ":cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==:";
val.type = 0xff;
CU_ASSERT(46 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BYTESEQ == val.type);
CU_ASSERT(44 == val.s.len);
CU_ASSERT(0 == memcmp("cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==",
val.s.base, val.s.len));
}
{
nghttp2_sf_value val;
const uint8_t s[] = ":cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==: ";
val.type = 0xff;
CU_ASSERT(46 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BYTESEQ == val.type);
CU_ASSERT(44 == val.s.len);
CU_ASSERT(0 == memcmp("cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==",
val.s.base, val.s.len));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "::";
val.type = 0xff;
CU_ASSERT(2 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BYTESEQ == val.type);
CU_ASSERT(0 == val.s.len);
}
{
const uint8_t s[] = ":cHJldGVuZCB0aGlzIGlzIGJpbmFyeSBjb250ZW50Lg==";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = ":";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = ":@:";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = ":foo:";
CU_ASSERT(5 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
nghttp2_sf_value val;
const uint8_t s[] =
":abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=:";
val.type = 0xff;
CU_ASSERT(67 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_BYTESEQ == val.type);
CU_ASSERT(65 == val.s.len);
CU_ASSERT(
0 ==
memcmp(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=",
val.s.base, val.s.len));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "foo123/456";
val.type = 0xff;
CU_ASSERT(10 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_TOKEN == val.type);
CU_ASSERT(10 == val.s.len);
CU_ASSERT(0 == memcmp(s, val.s.base, val.s.len));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "foo123/456 ";
val.type = 0xff;
CU_ASSERT(10 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_TOKEN == val.type);
CU_ASSERT(10 == val.s.len);
CU_ASSERT(0 == memcmp(s, val.s.base, val.s.len));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "*";
val.type = 0xff;
CU_ASSERT(1 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_TOKEN == val.type);
CU_ASSERT(1 == val.s.len);
CU_ASSERT(0 == memcmp(s, val.s.base, val.s.len));
}
{
const uint8_t s[] = "*";
CU_ASSERT(1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "\"hello world\"";
val.type = 0xff;
CU_ASSERT(13 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_STRING == val.type);
CU_ASSERT(11 == val.s.len);
CU_ASSERT(0 == memcmp("hello world", val.s.base, val.s.len));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "\"hello world\" ";
val.type = 0xff;
CU_ASSERT(13 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_STRING == val.type);
CU_ASSERT(11 == val.s.len);
CU_ASSERT(0 == memcmp("hello world", val.s.base, val.s.len));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "\"foo\\\"\\\\\"";
val.type = 0xff;
CU_ASSERT(9 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_STRING == val.type);
CU_ASSERT(7 == val.s.len);
CU_ASSERT(0 == memcmp("foo\\\"\\\\", val.s.base, val.s.len));
}
{
const uint8_t s[] = "\"foo\\x\"";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "\"foo";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "\"\x7f\"";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "\"\x1f\"";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "\"foo\"";
CU_ASSERT(5 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "4.5";
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
CU_ASSERT(3 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_DECIMAL == val.type);
CU_ASSERT(fabs(4.5 - val.d) < 1e-9);
}
{
nghttp2_sf_value val;
const uint8_t s[] = "4.5 ";
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
CU_ASSERT(3 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_DECIMAL == val.type);
CU_ASSERT(fabs(4.5 - val.d) < 1e-9);
}
{
nghttp2_sf_value val;
const uint8_t s[] = "-4.5";
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
CU_ASSERT(4 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_DECIMAL == val.type);
CU_ASSERT(fabs(-4.5 - val.d) < 1e-9);
}
{
const uint8_t s[] = "4.5";
CU_ASSERT(3 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "123456789012.123";
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
CU_ASSERT(16 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_DECIMAL == val.type);
CU_ASSERT(fabs(123456789012.123 - val.d) < 1e-9);
}
{
const uint8_t s[] = "1123456789012.123";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "123456789012.1234";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "1.";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "123456789012345";
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
CU_ASSERT(15 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INTEGER == val.type);
CU_ASSERT(123456789012345 == val.i);
}
{
nghttp2_sf_value val;
const uint8_t s[] = "1 ";
val.type = NGHTTP2_SF_VALUE_TYPE_DECIMAL;
CU_ASSERT(1 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INTEGER == val.type);
CU_ASSERT(1 == val.i);
}
{
const uint8_t s[] = "1";
CU_ASSERT(1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "1234567890123456";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
nghttp2_sf_value val;
const uint8_t s[] = "\"foo\";a; b=\"bar\";c=1.3;d=9;e=baz;f=:aaa:";
val.type = 0xff;
CU_ASSERT(41 == nghttp2_sf_parse_item(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_STRING == val.type);
CU_ASSERT(0 == memcmp("foo", val.s.base, val.s.len));
}
{
const uint8_t s[] = "\"foo\";a; b=\"bar";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "foo;";
CU_ASSERT(-1 == nghttp2_sf_parse_item(NULL, s, s + sizeof(s) - 1));
}
}
void test_nghttp2_sf_parse_inner_list(void) {
{
nghttp2_sf_value val;
const uint8_t s[] = "()";
val.type = 0xff;
CU_ASSERT(2 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
}
{
nghttp2_sf_value val;
const uint8_t s[] = "( )";
val.type = 0xff;
CU_ASSERT(7 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
}
{
nghttp2_sf_value val;
const uint8_t s[] = "(a)";
val.type = 0xff;
CU_ASSERT(3 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
}
{
nghttp2_sf_value val;
const uint8_t s[] = "(a b)";
val.type = 0xff;
CU_ASSERT(5 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
}
{
nghttp2_sf_value val;
const uint8_t s[] = "( a b )";
val.type = 0xff;
CU_ASSERT(10 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
}
{
nghttp2_sf_value val;
const uint8_t s[] = "( a;foo=bar)";
val.type = 0xff;
CU_ASSERT(12 == nghttp2_sf_parse_inner_list(&val, s, s + sizeof(s) - 1));
CU_ASSERT(NGHTTP2_SF_VALUE_TYPE_INNER_LIST == val.type);
}
{
const uint8_t s[] = "(";
CU_ASSERT(-1 == nghttp2_sf_parse_inner_list(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "(a";
CU_ASSERT(-1 == nghttp2_sf_parse_inner_list(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "(a ";
CU_ASSERT(-1 == nghttp2_sf_parse_inner_list(NULL, s, s + sizeof(s) - 1));
}
{
const uint8_t s[] = "(a;b";
CU_ASSERT(-1 == nghttp2_sf_parse_inner_list(NULL, s, s + sizeof(s) - 1));
}
}

View File

@ -31,7 +31,5 @@
#endif /* HAVE_CONFIG_H */
void test_nghttp2_http_parse_priority(void);
void test_nghttp2_sf_parse_item(void);
void test_nghttp2_sf_parse_inner_list(void);
#endif /* NGHTTP2_HTTP_TEST_H */