aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-contrib <robot-contrib@yandex-team.com>2023-05-25 20:22:07 +0300
committerrobot-contrib <robot-contrib@yandex-team.com>2023-05-25 20:22:07 +0300
commit31a1d179be9f1c6f46182d1b77b7899a78bf64c5 (patch)
treef81af49e1b4f69d9cfa076643de9e98965741f67
parente601d6faae19d0f1f281bcb5179f5157af9d177c (diff)
downloadydb-31a1d179be9f1c6f46182d1b77b7899a78bf64c5.tar.gz
Update contrib/libs/nghttp2 to 1.53.0
-rw-r--r--contrib/libs/nghttp2/CMakeLists.darwin-x86_64.txt1
-rw-r--r--contrib/libs/nghttp2/CMakeLists.linux-aarch64.txt1
-rw-r--r--contrib/libs/nghttp2/CMakeLists.linux-x86_64.txt1
-rw-r--r--contrib/libs/nghttp2/README.rst10
-rw-r--r--contrib/libs/nghttp2/config.h6
-rw-r--r--contrib/libs/nghttp2/lib/includes/nghttp2/nghttp2ver.h4
-rw-r--r--contrib/libs/nghttp2/lib/nghttp2_http.c716
-rw-r--r--contrib/libs/nghttp2/lib/nghttp2_http.h48
-rw-r--r--contrib/libs/nghttp2/lib/nghttp2_map.c61
-rw-r--r--contrib/libs/nghttp2/lib/nghttp2_map.h8
-rw-r--r--contrib/libs/nghttp2/lib/nghttp2_session.c24
-rw-r--r--contrib/libs/nghttp2/lib/sfparse.c1146
-rw-r--r--contrib/libs/nghttp2/lib/sfparse.h409
13 files changed, 1649 insertions, 786 deletions
diff --git a/contrib/libs/nghttp2/CMakeLists.darwin-x86_64.txt b/contrib/libs/nghttp2/CMakeLists.darwin-x86_64.txt
index e6d5bc3ea1..90e3c9ccba 100644
--- a/contrib/libs/nghttp2/CMakeLists.darwin-x86_64.txt
+++ b/contrib/libs/nghttp2/CMakeLists.darwin-x86_64.txt
@@ -44,4 +44,5 @@ target_sources(contrib-libs-nghttp2 PRIVATE
${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/nghttp2_stream.c
${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/nghttp2_submit.c
${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/nghttp2_version.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/sfparse.c
)
diff --git a/contrib/libs/nghttp2/CMakeLists.linux-aarch64.txt b/contrib/libs/nghttp2/CMakeLists.linux-aarch64.txt
index 3224ad6131..b62f0bb925 100644
--- a/contrib/libs/nghttp2/CMakeLists.linux-aarch64.txt
+++ b/contrib/libs/nghttp2/CMakeLists.linux-aarch64.txt
@@ -47,4 +47,5 @@ target_sources(contrib-libs-nghttp2 PRIVATE
${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/nghttp2_stream.c
${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/nghttp2_submit.c
${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/nghttp2_version.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/sfparse.c
)
diff --git a/contrib/libs/nghttp2/CMakeLists.linux-x86_64.txt b/contrib/libs/nghttp2/CMakeLists.linux-x86_64.txt
index 3224ad6131..b62f0bb925 100644
--- a/contrib/libs/nghttp2/CMakeLists.linux-x86_64.txt
+++ b/contrib/libs/nghttp2/CMakeLists.linux-x86_64.txt
@@ -47,4 +47,5 @@ target_sources(contrib-libs-nghttp2 PRIVATE
${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/nghttp2_stream.c
${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/nghttp2_submit.c
${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/nghttp2_version.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/nghttp2/lib/sfparse.c
)
diff --git a/contrib/libs/nghttp2/README.rst b/contrib/libs/nghttp2/README.rst
index 6871a60570..76291f0b12 100644
--- a/contrib/libs/nghttp2/README.rst
+++ b/contrib/libs/nghttp2/README.rst
@@ -129,9 +129,9 @@ following libraries are required:
* `OpenSSL with QUIC support
<https://github.com/quictls/openssl/tree/OpenSSL_1_1_1t+quic>`_; or
`BoringSSL <https://boringssl.googlesource.com/boringssl/>`_ (commit
- 80a243e07ef77156af66efa7d22ac35aba44c1b3)
-* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ >= 0.13.0
-* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ >= 0.7.0
+ b0b1f9dfc583c96d5f91b7f8cdb7efabcf22793b)
+* `ngtcp2 <https://github.com/ngtcp2/ngtcp2>`_ >= 0.15.0
+* `nghttp3 <https://github.com/ngtcp2/nghttp3>`_ >= 0.9.0
Use ``--enable-http3`` configure option to enable HTTP/3 feature for
h2load and nghttpx.
@@ -354,7 +354,7 @@ Build nghttp3:
.. code-block:: text
- $ git clone --depth 1 -b v0.8.0 https://github.com/ngtcp2/nghttp3
+ $ git clone --depth 1 -b v0.11.0 https://github.com/ngtcp2/nghttp3
$ cd nghttp3
$ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only
@@ -366,7 +366,7 @@ Build ngtcp2:
.. code-block:: text
- $ git clone --depth 1 -b v0.13.1 https://github.com/ngtcp2/ngtcp2
+ $ git clone --depth 1 -b v0.15.0 https://github.com/ngtcp2/ngtcp2
$ cd ngtcp2
$ autoreconf -i
$ ./configure --prefix=$PWD/build --enable-lib-only \
diff --git a/contrib/libs/nghttp2/config.h b/contrib/libs/nghttp2/config.h
index f5553463dc..62d1211177 100644
--- a/contrib/libs/nghttp2/config.h
+++ b/contrib/libs/nghttp2/config.h
@@ -244,7 +244,7 @@
#define PACKAGE_NAME "nghttp2"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "nghttp2 1.52.0"
+#define PACKAGE_STRING "nghttp2 1.53.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "nghttp2"
@@ -253,7 +253,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.52.0"
+#define PACKAGE_VERSION "1.53.0"
/* The size of `int *', as computed by sizeof. */
#define SIZEOF_INT_P 8
@@ -358,7 +358,7 @@
/* Version number of package */
-#define VERSION "1.52.0"
+#define VERSION "1.53.0"
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
diff --git a/contrib/libs/nghttp2/lib/includes/nghttp2/nghttp2ver.h b/contrib/libs/nghttp2/lib/includes/nghttp2/nghttp2ver.h
index 6ed0ac4a9b..46e7004be2 100644
--- a/contrib/libs/nghttp2/lib/includes/nghttp2/nghttp2ver.h
+++ b/contrib/libs/nghttp2/lib/includes/nghttp2/nghttp2ver.h
@@ -29,7 +29,7 @@
* @macro
* Version number of the nghttp2 library release
*/
-#define NGHTTP2_VERSION "1.52.0"
+#define NGHTTP2_VERSION "1.53.0"
/**
* @macro
@@ -37,6 +37,6 @@
* release. This is a 24 bit number with 8 bits for major number, 8 bits
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
*/
-#define NGHTTP2_VERSION_NUM 0x013400
+#define NGHTTP2_VERSION_NUM 0x013500
#endif /* NGHTTP2VER_H */
diff --git a/contrib/libs/nghttp2/lib/nghttp2_http.c b/contrib/libs/nghttp2/lib/nghttp2_http.c
index 83e5e6685f..ecdeb21ddb 100644
--- a/contrib/libs/nghttp2/lib/nghttp2_http.c
+++ b/contrib/libs/nghttp2/lib/nghttp2_http.c
@@ -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 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 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 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 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 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 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 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 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 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 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;
+
+ sf_parser_init(&sfp, value, valuelen);
- for (; p != end && *p == ' '; ++p)
- ;
+ for (;;) {
+ rv = sf_parser_dict(&sfp, &key, &val);
+ if (rv != 0) {
+ if (rv == SF_ERR_EOF) {
+ break;
+ }
- 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;
+ if (key.len != 1) {
+ continue;
+ }
- slen = sf_parse_params(p, end);
- if (slen < 0) {
+ switch (key.base[0]) {
+ case 'i':
+ if (val.type != SF_TYPE_BOOLEAN) {
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;
+ pri.inc = val.boolean;
- 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;
-
- break;
+ 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;
}
- }
- sf_discard_ows(p, end);
+ pri.urgency = (uint32_t)val.integer;
- if (*p++ != ',') {
- return NGHTTP2_ERR_INVALID_ARGUMENT;
+ break;
}
-
- sf_discard_ows_end_err(p, end, NGHTTP2_ERR_INVALID_ARGUMENT);
}
-fin:
*dest = pri;
return 0;
diff --git a/contrib/libs/nghttp2/lib/nghttp2_http.h b/contrib/libs/nghttp2/lib/nghttp2_http.h
index 0c3a78eeef..d9992fe690 100644
--- a/contrib/libs/nghttp2/lib/nghttp2_http.h
+++ b/contrib/libs/nghttp2/lib/nghttp2_http.h
@@ -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);
diff --git a/contrib/libs/nghttp2/lib/nghttp2_map.c b/contrib/libs/nghttp2/lib/nghttp2_map.c
index e5db168ca2..5f63fc2bb8 100644
--- a/contrib/libs/nghttp2/lib/nghttp2_map.c
+++ b/contrib/libs/nghttp2/lib/nghttp2_map.c
@@ -31,21 +31,14 @@
#include "nghttp2_helper.h"
-#define NGHTTP2_INITIAL_TABLE_LENBITS 8
+#define NGHTTP2_INITIAL_TABLE_LENBITS 4
-int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
+void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
map->mem = mem;
- map->tablelen = 1 << NGHTTP2_INITIAL_TABLE_LENBITS;
- map->tablelenbits = NGHTTP2_INITIAL_TABLE_LENBITS;
- map->table =
- nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_bucket));
- if (map->table == NULL) {
- return NGHTTP2_ERR_NOMEM;
- }
-
+ map->tablelen = 0;
+ map->tablelenbits = 0;
+ map->table = NULL;
map->size = 0;
-
- return 0;
}
void nghttp2_map_free(nghttp2_map *map) {
@@ -78,6 +71,10 @@ int nghttp2_map_each(nghttp2_map *map, int (*func)(void *data, void *ptr),
uint32_t i;
nghttp2_map_bucket *bkt;
+ if (map->size == 0) {
+ return 0;
+ }
+
for (i = 0; i < map->tablelen; ++i) {
bkt = &map->table[i];
@@ -223,9 +220,17 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
/* Load factor is 0.75 */
if ((map->size + 1) * 4 > map->tablelen * 3) {
- rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1);
- if (rv != 0) {
- return rv;
+ if (map->tablelen) {
+ rv = map_resize(map, map->tablelen * 2, map->tablelenbits + 1);
+ if (rv != 0) {
+ return rv;
+ }
+ } else {
+ rv = map_resize(map, 1 << NGHTTP2_INITIAL_TABLE_LENBITS,
+ NGHTTP2_INITIAL_TABLE_LENBITS);
+ if (rv != 0) {
+ return rv;
+ }
}
}
@@ -239,11 +244,18 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_key_type key, void *data) {
}
void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) {
- uint32_t h = hash(key);
- size_t idx = h2idx(h, map->tablelenbits);
+ uint32_t h;
+ size_t idx;
nghttp2_map_bucket *bkt;
size_t d = 0;
+ if (map->size == 0) {
+ return NULL;
+ }
+
+ h = hash(key);
+ idx = h2idx(h, map->tablelenbits);
+
for (;;) {
bkt = &map->table[idx];
@@ -262,11 +274,18 @@ void *nghttp2_map_find(nghttp2_map *map, nghttp2_map_key_type key) {
}
int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
- uint32_t h = hash(key);
- size_t idx = h2idx(h, map->tablelenbits), didx;
+ uint32_t h;
+ size_t idx, didx;
nghttp2_map_bucket *bkt;
size_t d = 0;
+ if (map->size == 0) {
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+ }
+
+ h = hash(key);
+ idx = h2idx(h, map->tablelenbits);
+
for (;;) {
bkt = &map->table[idx];
@@ -306,6 +325,10 @@ int nghttp2_map_remove(nghttp2_map *map, nghttp2_map_key_type key) {
}
void nghttp2_map_clear(nghttp2_map *map) {
+ if (map->tablelen == 0) {
+ return;
+ }
+
memset(map->table, 0, sizeof(*map->table) * map->tablelen);
map->size = 0;
}
diff --git a/contrib/libs/nghttp2/lib/nghttp2_map.h b/contrib/libs/nghttp2/lib/nghttp2_map.h
index 1419a09a35..d90245aab7 100644
--- a/contrib/libs/nghttp2/lib/nghttp2_map.h
+++ b/contrib/libs/nghttp2/lib/nghttp2_map.h
@@ -54,14 +54,8 @@ typedef struct nghttp2_map {
/*
* Initializes the map |map|.
- *
- * This function returns 0 if it succeeds, or one of the following
- * negative error codes:
- *
- * NGHTTP2_ERR_NOMEM
- * Out of memory
*/
-int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem);
+void nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem);
/*
* Deallocates any resources allocated for |map|. The stored entries
diff --git a/contrib/libs/nghttp2/lib/nghttp2_session.c b/contrib/libs/nghttp2/lib/nghttp2_session.c
index 93f3f07cf7..7509ceb5c6 100644
--- a/contrib/libs/nghttp2/lib/nghttp2_session.c
+++ b/contrib/libs/nghttp2/lib/nghttp2_session.c
@@ -584,10 +584,6 @@ static int session_new(nghttp2_session **session_ptr,
if (rv != 0) {
goto fail_hd_inflater;
}
- rv = nghttp2_map_init(&(*session_ptr)->streams, mem);
- if (rv != 0) {
- goto fail_map;
- }
nbuffer = ((*session_ptr)->max_send_header_block_length +
NGHTTP2_FRAMEBUF_CHUNKLEN - 1) /
@@ -605,6 +601,8 @@ static int session_new(nghttp2_session **session_ptr,
goto fail_aob_framebuf;
}
+ nghttp2_map_init(&(*session_ptr)->streams, mem);
+
active_outbound_item_reset(&(*session_ptr)->aob, mem);
(*session_ptr)->callbacks = *callbacks;
@@ -637,8 +635,6 @@ static int session_new(nghttp2_session **session_ptr,
return 0;
fail_aob_framebuf:
- nghttp2_map_free(&(*session_ptr)->streams);
-fail_map:
nghttp2_hd_inflate_free(&(*session_ptr)->hd_inflater);
fail_hd_inflater:
nghttp2_hd_deflate_free(&(*session_ptr)->hd_deflater);
@@ -5931,7 +5927,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += readlen;
if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
- return in - first;
+ return (ssize_t)(in - first);
}
if (iframe->sbuf.pos[3] != NGHTTP2_SETTINGS ||
@@ -5968,7 +5964,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += readlen;
if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
- return in - first;
+ return (ssize_t)(in - first);
}
nghttp2_frame_unpack_frame_hd(&iframe->frame.hd, iframe->sbuf.pos);
@@ -6468,7 +6464,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf));
if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
- return in - first;
+ return (ssize_t)(in - first);
}
switch (iframe->frame.hd.type) {
@@ -6772,7 +6768,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += hd_proclen;
iframe->payloadleft -= hd_proclen;
- return in - first;
+ return (ssize_t)(in - first);
}
if (rv == NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE) {
@@ -6963,7 +6959,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
in += readlen;
if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
- return in - first;
+ return (ssize_t)(in - first);
}
nghttp2_frame_unpack_frame_hd(&cont_hd, iframe->sbuf.pos);
@@ -7021,7 +7017,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
iframe->payloadleft, nghttp2_buf_mark_avail(&iframe->sbuf));
if (nghttp2_buf_mark_avail(&iframe->sbuf)) {
- return in - first;
+ return (ssize_t)(in - first);
}
/* Pad Length field is subject to flow control */
@@ -7171,7 +7167,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
session, iframe->frame.hd.flags, iframe->frame.hd.stream_id,
in - readlen, (size_t)data_readlen, session->user_data);
if (rv == NGHTTP2_ERR_PAUSE) {
- return in - first;
+ return (ssize_t)(in - first);
}
if (nghttp2_is_fatal(rv)) {
@@ -7351,7 +7347,7 @@ ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
assert(in == last);
- return in - first;
+ return (ssize_t)(in - first);
}
int nghttp2_session_recv(nghttp2_session *session) {
diff --git a/contrib/libs/nghttp2/lib/sfparse.c b/contrib/libs/nghttp2/lib/sfparse.c
new file mode 100644
index 0000000000..efa2850c9d
--- /dev/null
+++ b/contrib/libs/nghttp2/lib/sfparse.c
@@ -0,0 +1,1146 @@
+/*
+ * 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.
+ */
+#include "sfparse.h"
+
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#define SF_STATE_DICT 0x08u
+#define SF_STATE_LIST 0x10u
+#define SF_STATE_ITEM 0x18u
+
+#define SF_STATE_INNER_LIST 0x04u
+
+#define SF_STATE_BEFORE 0x00u
+#define SF_STATE_BEFORE_PARAMS 0x01u
+#define SF_STATE_PARAMS 0x02u
+#define SF_STATE_AFTER 0x03u
+
+#define SF_STATE_OP_MASK 0x03u
+
+#define SF_SET_STATE_AFTER(NAME) (SF_STATE_##NAME | SF_STATE_AFTER)
+#define SF_SET_STATE_BEFORE_PARAMS(NAME) \
+ (SF_STATE_##NAME | SF_STATE_BEFORE_PARAMS)
+#define SF_SET_STATE_INNER_LIST_BEFORE(NAME) \
+ (SF_STATE_##NAME | SF_STATE_INNER_LIST | SF_STATE_BEFORE)
+
+#define SF_STATE_DICT_AFTER SF_SET_STATE_AFTER(DICT)
+#define SF_STATE_DICT_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(DICT)
+#define SF_STATE_DICT_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(DICT)
+
+#define SF_STATE_LIST_AFTER SF_SET_STATE_AFTER(LIST)
+#define SF_STATE_LIST_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(LIST)
+#define SF_STATE_LIST_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(LIST)
+
+#define SF_STATE_ITEM_AFTER SF_SET_STATE_AFTER(ITEM)
+#define SF_STATE_ITEM_BEFORE_PARAMS SF_SET_STATE_BEFORE_PARAMS(ITEM)
+#define SF_STATE_ITEM_INNER_LIST_BEFORE SF_SET_STATE_INNER_LIST_BEFORE(ITEM)
+
+#define SF_STATE_INITIAL 0x00u
+
+#define DIGIT_CASES \
+ case '0': \
+ case '1': \
+ case '2': \
+ case '3': \
+ case '4': \
+ case '5': \
+ case '6': \
+ case '7': \
+ case '8': \
+ case '9'
+
+#define LCALPHA_CASES \
+ case 'a': \
+ case 'b': \
+ case 'c': \
+ case 'd': \
+ case 'e': \
+ case 'f': \
+ case 'g': \
+ case 'h': \
+ case 'i': \
+ case 'j': \
+ case 'k': \
+ case 'l': \
+ case 'm': \
+ case 'n': \
+ case 'o': \
+ case 'p': \
+ case 'q': \
+ case 'r': \
+ case 's': \
+ case 't': \
+ case 'u': \
+ case 'v': \
+ case 'w': \
+ case 'x': \
+ case 'y': \
+ case 'z'
+
+#define UCALPHA_CASES \
+ case 'A': \
+ case 'B': \
+ case 'C': \
+ case 'D': \
+ case 'E': \
+ case 'F': \
+ case 'G': \
+ case 'H': \
+ case 'I': \
+ case 'J': \
+ case 'K': \
+ case 'L': \
+ case 'M': \
+ case 'N': \
+ case 'O': \
+ case 'P': \
+ case 'Q': \
+ case 'R': \
+ case 'S': \
+ case 'T': \
+ case 'U': \
+ case 'V': \
+ case 'W': \
+ case 'X': \
+ case 'Y': \
+ case 'Z'
+
+#define ALPHA_CASES \
+ UCALPHA_CASES: \
+ LCALPHA_CASES
+
+#define X20_21_CASES \
+ case ' ': \
+ case '!'
+
+#define X23_5B_CASES \
+ case '#': \
+ case '$': \
+ case '%': \
+ case '&': \
+ case '\'': \
+ case '(': \
+ case ')': \
+ case '*': \
+ case '+': \
+ case ',': \
+ case '-': \
+ case '.': \
+ case '/': \
+ DIGIT_CASES: \
+ case ':': \
+ case ';': \
+ case '<': \
+ case '=': \
+ case '>': \
+ case '?': \
+ case '@': \
+ UCALPHA_CASES: \
+ case '['
+
+#define X5D_7E_CASES \
+ case ']': \
+ case '^': \
+ case '_': \
+ case '`': \
+ LCALPHA_CASES: \
+ case '{': \
+ case '|': \
+ case '}': \
+ case '~'
+
+static int is_ws(uint8_t c) {
+ switch (c) {
+ case ' ':
+ case '\t':
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int parser_eof(sf_parser *sfp) { return sfp->pos == sfp->end; }
+
+static void parser_discard_ows(sf_parser *sfp) {
+ for (; !parser_eof(sfp) && is_ws(*sfp->pos); ++sfp->pos)
+ ;
+}
+
+static void parser_discard_sp(sf_parser *sfp) {
+ for (; !parser_eof(sfp) && *sfp->pos == ' '; ++sfp->pos)
+ ;
+}
+
+static void parser_set_op_state(sf_parser *sfp, uint32_t op) {
+ sfp->state &= ~SF_STATE_OP_MASK;
+ sfp->state |= op;
+}
+
+static void parser_unset_inner_list_state(sf_parser *sfp) {
+ sfp->state &= ~SF_STATE_INNER_LIST;
+}
+
+static int parser_key(sf_parser *sfp, sf_vec *dest) {
+ const uint8_t *base;
+
+ switch (*sfp->pos) {
+ case '*':
+ LCALPHA_CASES:
+ break;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ base = sfp->pos++;
+
+ for (; !parser_eof(sfp); ++sfp->pos) {
+ switch (*sfp->pos) {
+ case '_':
+ case '-':
+ case '.':
+ case '*':
+ DIGIT_CASES:
+ LCALPHA_CASES:
+ continue;
+ }
+
+ break;
+ }
+
+ if (dest) {
+ dest->base = (uint8_t *)base;
+ dest->len = (size_t)(sfp->pos - dest->base);
+ }
+
+ return 0;
+}
+
+static int parser_number(sf_parser *sfp, sf_value *dest) {
+ int sign = 1;
+ int64_t value = 0;
+ size_t len = 0;
+ size_t fpos = 0;
+
+ if (*sfp->pos == '-') {
+ ++sfp->pos;
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ sign = -1;
+ }
+
+ assert(!parser_eof(sfp));
+
+ for (; !parser_eof(sfp); ++sfp->pos) {
+ switch (*sfp->pos) {
+ DIGIT_CASES:
+ if (++len > 15) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ value *= 10;
+ value += *sfp->pos - '0';
+
+ continue;
+ }
+
+ break;
+ }
+
+ if (len == 0) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ if (parser_eof(sfp) || *sfp->pos != '.') {
+ if (dest) {
+ dest->type = SF_TYPE_INTEGER;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ dest->integer = value * sign;
+ }
+
+ return 0;
+ }
+
+ /* decimal */
+
+ if (len > 12) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ fpos = len;
+
+ ++sfp->pos;
+
+ for (; !parser_eof(sfp); ++sfp->pos) {
+ switch (*sfp->pos) {
+ DIGIT_CASES:
+ if (++len > 15) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ value *= 10;
+ value += *sfp->pos - '0';
+
+ continue;
+ }
+
+ break;
+ }
+
+ if (fpos == len || len - fpos > 3) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ if (dest) {
+ dest->type = SF_TYPE_DECIMAL;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ dest->decimal.numer = value * sign;
+
+ switch (len - fpos) {
+ case 1:
+ dest->decimal.denom = 10;
+
+ break;
+ case 2:
+ dest->decimal.denom = 100;
+
+ break;
+ case 3:
+ dest->decimal.denom = 1000;
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int parser_date(sf_parser *sfp, sf_value *dest) {
+ int rv;
+ sf_value val;
+
+ /* The first byte has already been validated by the caller. */
+ assert('@' == *sfp->pos);
+
+ ++sfp->pos;
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ rv = parser_number(sfp, &val);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (val.type != SF_TYPE_INTEGER) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ if (dest) {
+ *dest = val;
+ dest->type = SF_TYPE_DATE;
+ }
+
+ return 0;
+}
+
+static int parser_string(sf_parser *sfp, sf_value *dest) {
+ const uint8_t *base;
+ uint32_t flags = SF_VALUE_FLAG_NONE;
+
+ /* The first byte has already been validated by the caller. */
+ assert('"' == *sfp->pos);
+
+ base = ++sfp->pos;
+
+ for (; !parser_eof(sfp); ++sfp->pos) {
+ switch (*sfp->pos) {
+ X20_21_CASES:
+ X23_5B_CASES:
+ X5D_7E_CASES:
+ break;
+ case '\\':
+ ++sfp->pos;
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ switch (*sfp->pos) {
+ case '"':
+ case '\\':
+ flags = SF_VALUE_FLAG_ESCAPED_STRING;
+
+ break;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ break;
+ case '"':
+ if (dest) {
+ dest->type = SF_TYPE_STRING;
+ dest->flags = flags;
+ dest->vec.len = (size_t)(sfp->pos - base);
+ dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base;
+ }
+
+ ++sfp->pos;
+
+ return 0;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+ }
+
+ return SF_ERR_PARSE_ERROR;
+}
+
+static int parser_token(sf_parser *sfp, sf_value *dest) {
+ const uint8_t *base;
+
+ /* The first byte has already been validated by the caller. */
+ base = sfp->pos++;
+
+ for (; !parser_eof(sfp); ++sfp->pos) {
+ switch (*sfp->pos) {
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '.':
+ case '^':
+ case '_':
+ case '`':
+ case '|':
+ case '~':
+ case ':':
+ case '/':
+ DIGIT_CASES:
+ ALPHA_CASES:
+ continue;
+ }
+
+ break;
+ }
+
+ if (dest) {
+ dest->type = SF_TYPE_TOKEN;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ dest->vec.base = (uint8_t *)base;
+ dest->vec.len = (size_t)(sfp->pos - base);
+ }
+
+ return 0;
+}
+
+static int parser_byteseq(sf_parser *sfp, sf_value *dest) {
+ const uint8_t *base;
+
+ /* The first byte has already been validated by the caller. */
+ assert(':' == *sfp->pos);
+
+ base = ++sfp->pos;
+
+ for (; !parser_eof(sfp); ++sfp->pos) {
+ switch (*sfp->pos) {
+ case '+':
+ case '/':
+ DIGIT_CASES:
+ ALPHA_CASES:
+ continue;
+ case '=':
+ switch ((sfp->pos - base) & 0x3) {
+ case 0:
+ case 1:
+ return SF_ERR_PARSE_ERROR;
+ case 2:
+ switch (*(sfp->pos - 1)) {
+ case 'A':
+ case 'Q':
+ case 'g':
+ case 'w':
+ break;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ ++sfp->pos;
+
+ if (parser_eof(sfp) || *sfp->pos != '=') {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ break;
+ case 3:
+ switch (*(sfp->pos - 1)) {
+ case 'A':
+ case 'E':
+ case 'I':
+ case 'M':
+ case 'Q':
+ case 'U':
+ case 'Y':
+ case 'c':
+ case 'g':
+ case 'k':
+ case 'o':
+ case 's':
+ case 'w':
+ case '0':
+ case '4':
+ case '8':
+ break;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ break;
+ }
+
+ ++sfp->pos;
+
+ if (parser_eof(sfp) || *sfp->pos != ':') {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ goto fin;
+ case ':':
+ if ((sfp->pos - base) & 0x3) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ goto fin;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+ }
+
+ return SF_ERR_PARSE_ERROR;
+
+fin:
+ if (dest) {
+ dest->type = SF_TYPE_BYTESEQ;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ dest->vec.len = (size_t)(sfp->pos - base);
+ dest->vec.base = dest->vec.len == 0 ? NULL : (uint8_t *)base;
+ }
+
+ ++sfp->pos;
+
+ return 0;
+}
+
+static int parser_boolean(sf_parser *sfp, sf_value *dest) {
+ int b;
+
+ /* The first byte has already been validated by the caller. */
+ assert('?' == *sfp->pos);
+
+ ++sfp->pos;
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ switch (*sfp->pos) {
+ case '0':
+ b = 0;
+
+ break;
+ case '1':
+ b = 1;
+
+ break;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ ++sfp->pos;
+
+ if (dest) {
+ dest->type = SF_TYPE_BOOLEAN;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ dest->boolean = b;
+ }
+
+ return 0;
+}
+
+static int parser_bare_item(sf_parser *sfp, sf_value *dest) {
+ switch (*sfp->pos) {
+ case '"':
+ return parser_string(sfp, dest);
+ case '-':
+ DIGIT_CASES:
+ return parser_number(sfp, dest);
+ case '@':
+ return parser_date(sfp, dest);
+ case ':':
+ return parser_byteseq(sfp, dest);
+ case '?':
+ return parser_boolean(sfp, dest);
+ case '*':
+ ALPHA_CASES:
+ return parser_token(sfp, dest);
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+}
+
+static int parser_skip_inner_list(sf_parser *sfp);
+
+int sf_parser_param(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) {
+ int rv;
+
+ switch (sfp->state & SF_STATE_OP_MASK) {
+ case SF_STATE_BEFORE:
+ rv = parser_skip_inner_list(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_BEFORE_PARAMS:
+ parser_set_op_state(sfp, SF_STATE_PARAMS);
+
+ break;
+ case SF_STATE_PARAMS:
+ break;
+ default:
+ assert(0);
+ abort();
+ }
+
+ if (parser_eof(sfp) || *sfp->pos != ';') {
+ parser_set_op_state(sfp, SF_STATE_AFTER);
+
+ return SF_ERR_EOF;
+ }
+
+ ++sfp->pos;
+
+ parser_discard_sp(sfp);
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ rv = parser_key(sfp, dest_key);
+ if (rv != 0) {
+ return rv;
+ }
+
+ if (parser_eof(sfp) || *sfp->pos != '=') {
+ if (dest_value) {
+ dest_value->type = SF_TYPE_BOOLEAN;
+ dest_value->flags = SF_VALUE_FLAG_NONE;
+ dest_value->boolean = 1;
+ }
+
+ return 0;
+ }
+
+ ++sfp->pos;
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ return parser_bare_item(sfp, dest_value);
+}
+
+static int parser_skip_params(sf_parser *sfp) {
+ int rv;
+
+ for (;;) {
+ rv = sf_parser_param(sfp, NULL, NULL);
+ switch (rv) {
+ case 0:
+ break;
+ case SF_ERR_EOF:
+ return 0;
+ case SF_ERR_PARSE_ERROR:
+ return rv;
+ default:
+ assert(0);
+ abort();
+ }
+ }
+}
+
+int sf_parser_inner_list(sf_parser *sfp, sf_value *dest) {
+ int rv;
+
+ switch (sfp->state & SF_STATE_OP_MASK) {
+ case SF_STATE_BEFORE:
+ parser_discard_sp(sfp);
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ break;
+ case SF_STATE_BEFORE_PARAMS:
+ rv = parser_skip_params(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* Technically, we are entering SF_STATE_AFTER, but we will set
+ another state without reading the state. */
+ /* parser_set_op_state(sfp, SF_STATE_AFTER); */
+
+ /* fall through */
+ case SF_STATE_AFTER:
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ switch (*sfp->pos) {
+ case ' ':
+ parser_discard_sp(sfp);
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ break;
+ case ')':
+ break;
+ default:
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ break;
+ default:
+ assert(0);
+ abort();
+ }
+
+ if (*sfp->pos == ')') {
+ ++sfp->pos;
+
+ parser_unset_inner_list_state(sfp);
+ parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS);
+
+ return SF_ERR_EOF;
+ }
+
+ rv = parser_bare_item(sfp, dest);
+ if (rv != 0) {
+ return rv;
+ }
+
+ parser_set_op_state(sfp, SF_STATE_BEFORE_PARAMS);
+
+ return 0;
+}
+
+static int parser_skip_inner_list(sf_parser *sfp) {
+ int rv;
+
+ for (;;) {
+ rv = sf_parser_inner_list(sfp, NULL);
+ switch (rv) {
+ case 0:
+ break;
+ case SF_ERR_EOF:
+ return 0;
+ case SF_ERR_PARSE_ERROR:
+ return rv;
+ default:
+ assert(0);
+ abort();
+ }
+ }
+}
+
+static int parser_next_key_or_item(sf_parser *sfp) {
+ parser_discard_ows(sfp);
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_EOF;
+ }
+
+ if (*sfp->pos != ',') {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ ++sfp->pos;
+
+ parser_discard_ows(sfp);
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ return 0;
+}
+
+static int parser_dict_value(sf_parser *sfp, sf_value *dest) {
+ int rv;
+
+ if (parser_eof(sfp) || *(sfp->pos) != '=') {
+ /* Boolean true */
+ if (dest) {
+ dest->type = SF_TYPE_BOOLEAN;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ dest->boolean = 1;
+ }
+
+ sfp->state = SF_STATE_DICT_BEFORE_PARAMS;
+
+ return 0;
+ }
+
+ ++sfp->pos;
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ if (*sfp->pos == '(') {
+ if (dest) {
+ dest->type = SF_TYPE_INNER_LIST;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ }
+
+ ++sfp->pos;
+
+ sfp->state = SF_STATE_DICT_INNER_LIST_BEFORE;
+
+ return 0;
+ }
+
+ rv = parser_bare_item(sfp, dest);
+ if (rv != 0) {
+ return rv;
+ }
+
+ sfp->state = SF_STATE_DICT_BEFORE_PARAMS;
+
+ return 0;
+}
+
+int sf_parser_dict(sf_parser *sfp, sf_vec *dest_key, sf_value *dest_value) {
+ int rv;
+
+ switch (sfp->state) {
+ case SF_STATE_DICT_INNER_LIST_BEFORE:
+ rv = parser_skip_inner_list(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_DICT_BEFORE_PARAMS:
+ rv = parser_skip_params(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_DICT_AFTER:
+ rv = parser_next_key_or_item(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ break;
+ case SF_STATE_INITIAL:
+ parser_discard_sp(sfp);
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_EOF;
+ }
+
+ break;
+ default:
+ assert(0);
+ abort();
+ }
+
+ rv = parser_key(sfp, dest_key);
+ if (rv != 0) {
+ return rv;
+ }
+
+ return parser_dict_value(sfp, dest_value);
+}
+
+int sf_parser_list(sf_parser *sfp, sf_value *dest) {
+ int rv;
+
+ switch (sfp->state) {
+ case SF_STATE_LIST_INNER_LIST_BEFORE:
+ rv = parser_skip_inner_list(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_LIST_BEFORE_PARAMS:
+ rv = parser_skip_params(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_LIST_AFTER:
+ rv = parser_next_key_or_item(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ break;
+ case SF_STATE_INITIAL:
+ parser_discard_sp(sfp);
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_EOF;
+ }
+
+ break;
+ default:
+ assert(0);
+ abort();
+ }
+
+ if (*sfp->pos == '(') {
+ if (dest) {
+ dest->type = SF_TYPE_INNER_LIST;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ }
+
+ ++sfp->pos;
+
+ sfp->state = SF_STATE_LIST_INNER_LIST_BEFORE;
+
+ return 0;
+ }
+
+ rv = parser_bare_item(sfp, dest);
+ if (rv != 0) {
+ return rv;
+ }
+
+ sfp->state = SF_STATE_LIST_BEFORE_PARAMS;
+
+ return 0;
+}
+
+int sf_parser_item(sf_parser *sfp, sf_value *dest) {
+ int rv;
+
+ switch (sfp->state) {
+ case SF_STATE_INITIAL:
+ parser_discard_sp(sfp);
+
+ if (parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ break;
+ case SF_STATE_ITEM_INNER_LIST_BEFORE:
+ rv = parser_skip_inner_list(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_ITEM_BEFORE_PARAMS:
+ rv = parser_skip_params(sfp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ /* fall through */
+ case SF_STATE_ITEM_AFTER:
+ parser_discard_sp(sfp);
+
+ if (!parser_eof(sfp)) {
+ return SF_ERR_PARSE_ERROR;
+ }
+
+ return SF_ERR_EOF;
+ default:
+ assert(0);
+ abort();
+ }
+
+ if (*sfp->pos == '(') {
+ if (dest) {
+ dest->type = SF_TYPE_INNER_LIST;
+ dest->flags = SF_VALUE_FLAG_NONE;
+ }
+
+ ++sfp->pos;
+
+ sfp->state = SF_STATE_ITEM_INNER_LIST_BEFORE;
+
+ return 0;
+ }
+
+ rv = parser_bare_item(sfp, dest);
+ if (rv != 0) {
+ return rv;
+ }
+
+ sfp->state = SF_STATE_ITEM_BEFORE_PARAMS;
+
+ return 0;
+}
+
+void sf_parser_init(sf_parser *sfp, const uint8_t *data, size_t datalen) {
+ if (datalen == 0) {
+ sfp->pos = sfp->end = NULL;
+ } else {
+ sfp->pos = data;
+ sfp->end = data + datalen;
+ }
+
+ sfp->state = SF_STATE_INITIAL;
+}
+
+void sf_unescape(sf_vec *dest, const sf_vec *src) {
+ const uint8_t *p, *q;
+ uint8_t *o;
+ size_t len, slen;
+
+ if (src->len == 0) {
+ *dest = *src;
+
+ return;
+ }
+
+ o = dest->base;
+ p = src->base;
+ len = src->len;
+
+ for (;;) {
+ q = memchr(p, '\\', len);
+ if (q == NULL) {
+ if (len == src->len) {
+ *dest = *src;
+
+ return;
+ }
+
+ memcpy(o, p, len);
+ o += len;
+
+ break;
+ }
+
+ slen = (size_t)(q - p);
+ memcpy(o, p, slen);
+ o += slen;
+
+ p = q + 1;
+ *o++ = *p++;
+ len -= slen + 2;
+ }
+
+ dest->len = (size_t)(o - dest->base);
+}
+
+void sf_base64decode(sf_vec *dest, const sf_vec *src) {
+ static const int index_tbl[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1};
+ uint8_t *o;
+ const uint8_t *p, *end;
+ uint32_t n;
+ size_t i;
+ int idx;
+
+ assert((src->len & 0x3) == 0);
+
+ if (src->len == 0) {
+ *dest = *src;
+
+ return;
+ }
+
+ o = dest->base;
+ p = src->base;
+ end = src->base + src->len;
+
+ for (; p != end;) {
+ n = 0;
+
+ for (i = 1; i <= 4; ++i, ++p) {
+ idx = index_tbl[*p];
+
+ if (idx == -1) {
+ assert(i > 2);
+
+ if (i == 3) {
+ assert(*p == '=' && *(p + 1) == '=' && p + 2 == end);
+
+ *o++ = (uint8_t)(n >> 16);
+
+ goto fin;
+ }
+
+ assert(*p == '=' && p + 1 == end);
+
+ *o++ = (uint8_t)(n >> 16);
+ *o++ = (n >> 8) & 0xffu;
+
+ goto fin;
+ }
+
+ n += (uint32_t)(idx << (24 - i * 6));
+ }
+
+ *o++ = (uint8_t)(n >> 16);
+ *o++ = (n >> 8) & 0xffu;
+ *o++ = n & 0xffu;
+ }
+
+fin:
+ dest->len = (size_t)(o - dest->base);
+}
diff --git a/contrib/libs/nghttp2/lib/sfparse.h b/contrib/libs/nghttp2/lib/sfparse.h
new file mode 100644
index 0000000000..1474db1429
--- /dev/null
+++ b/contrib/libs/nghttp2/lib/sfparse.h
@@ -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 */