mirror of
https://github.com/nodejs/node.git
synced 2025-08-15 13:48:44 +02:00

Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/59249 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
442 lines
14 KiB
C
442 lines
14 KiB
C
/*
|
|
* 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 /* (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) */
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif /* defined(__cplusplus) */
|
|
|
|
#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:`sfparse_type` defines value type.
|
|
*/
|
|
typedef enum sfparse_type {
|
|
/**
|
|
* :enum:`SFPARSE_TYPE_BOOLEAN` indicates boolean type.
|
|
*/
|
|
SFPARSE_TYPE_BOOLEAN,
|
|
/**
|
|
* :enum:`SFPARSE_TYPE_INTEGER` indicates integer type.
|
|
*/
|
|
SFPARSE_TYPE_INTEGER,
|
|
/**
|
|
* :enum:`SFPARSE_TYPE_DECIMAL` indicates decimal type.
|
|
*/
|
|
SFPARSE_TYPE_DECIMAL,
|
|
/**
|
|
* :enum:`SFPARSE_TYPE_STRING` indicates string type.
|
|
*/
|
|
SFPARSE_TYPE_STRING,
|
|
/**
|
|
* :enum:`SFPARSE_TYPE_TOKEN` indicates token type.
|
|
*/
|
|
SFPARSE_TYPE_TOKEN,
|
|
/**
|
|
* :enum:`SFPARSE_TYPE_BYTESEQ` indicates byte sequence type.
|
|
*/
|
|
SFPARSE_TYPE_BYTESEQ,
|
|
/**
|
|
* :enum:`SFPARSE_TYPE_INNER_LIST` indicates inner list type.
|
|
*/
|
|
SFPARSE_TYPE_INNER_LIST,
|
|
/**
|
|
* :enum:`SFPARSE_TYPE_DATE` indicates date type.
|
|
*/
|
|
SFPARSE_TYPE_DATE,
|
|
/**
|
|
* :enum:`SFPARSE_TYPE_DISPSTRING` indicates display string type.
|
|
*/
|
|
SFPARSE_TYPE_DISPSTRING
|
|
} sfparse_type;
|
|
|
|
/**
|
|
* @macro
|
|
*
|
|
* :macro:`SFPARSE_ERR_PARSE` indicates fatal parse error has
|
|
* occurred, and it is not possible to continue the processing.
|
|
*/
|
|
#define SFPARSE_ERR_PARSE -1
|
|
|
|
/**
|
|
* @macro
|
|
*
|
|
* :macro:`SFPARSE_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 SFPARSE_ERR_EOF -2
|
|
|
|
/**
|
|
* @struct
|
|
*
|
|
* :type:`sfparse_vec` stores sequence of bytes.
|
|
*/
|
|
typedef struct sfparse_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;
|
|
} sfparse_vec;
|
|
|
|
/**
|
|
* @macro
|
|
*
|
|
* :macro:`SFPARSE_VALUE_FLAG_NONE` indicates no flag set.
|
|
*/
|
|
#define SFPARSE_VALUE_FLAG_NONE 0x0u
|
|
|
|
/**
|
|
* @macro
|
|
*
|
|
* :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` indicates that a string
|
|
* contains escaped character(s).
|
|
*/
|
|
#define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1u
|
|
|
|
/**
|
|
* @struct
|
|
*
|
|
* :type:`sfparse_decimal` contains decimal value.
|
|
*/
|
|
typedef struct sfparse_decimal {
|
|
/**
|
|
* :member:`numer` contains numerator of the decimal value.
|
|
*/
|
|
int64_t numer;
|
|
/**
|
|
* :member:`denom` contains denominator of the decimal value.
|
|
*/
|
|
int64_t denom;
|
|
} sfparse_decimal;
|
|
|
|
/**
|
|
* @struct
|
|
*
|
|
* :type:`sfparse_value` stores a Structured Field item. For Inner
|
|
* List, only type is set to
|
|
* :enum:`sfparse_type.SFPARSE_TYPE_INNER_LIST`. In order to read the
|
|
* items contained in an inner list, call `sfparse_parser_inner_list`.
|
|
*/
|
|
typedef struct sfparse_value {
|
|
/**
|
|
* :member:`type` is the type of the value contained in this
|
|
* particular object.
|
|
*/
|
|
sfparse_type type;
|
|
/**
|
|
* :member:`flags` is bitwise OR of one or more of
|
|
* :macro:`SFPARSE_VALUE_FLAG_* <SFPARSE_VALUE_FLAG_NONE>`.
|
|
*/
|
|
uint32_t flags;
|
|
/**
|
|
* @anonunion_start
|
|
*
|
|
* @sfparse_value_value
|
|
*/
|
|
union {
|
|
/**
|
|
* :member:`boolean` contains boolean value if :member:`type` ==
|
|
* :enum:`sfparse_type.SFPARSE_TYPE_BOOLEAN`. 1 indicates true,
|
|
* and 0 indicates false.
|
|
*/
|
|
int boolean;
|
|
/**
|
|
* :member:`integer` contains integer value if :member:`type` is
|
|
* either :enum:`sfparse_type.SFPARSE_TYPE_INTEGER` or
|
|
* :enum:`sfparse_type.SFPARSE_TYPE_DATE`.
|
|
*/
|
|
int64_t integer;
|
|
/**
|
|
* :member:`decimal` contains decimal value if :member:`type` ==
|
|
* :enum:`sfparse_type.SFPARSE_TYPE_DECIMAL`.
|
|
*/
|
|
sfparse_decimal decimal;
|
|
/**
|
|
* :member:`vec` contains sequence of bytes if :member:`type` is
|
|
* either :enum:`sfparse_type.SFPARSE_TYPE_STRING`,
|
|
* :enum:`sfparse_type.SFPARSE_TYPE_TOKEN`,
|
|
* :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, or
|
|
* :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`.
|
|
*
|
|
* For :enum:`sfparse_type.SFPARSE_TYPE_STRING`, this field
|
|
* contains one or more escaped characters if :member:`flags` has
|
|
* :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` set. To unescape
|
|
* the string, use `sfparse_unescape`.
|
|
*
|
|
* For :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ`, this field
|
|
* contains base64 encoded string. To decode this byte string,
|
|
* use `sfparse_base64decode`.
|
|
*
|
|
* For :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING`, this field
|
|
* may contain percent-encoded UTF-8 byte sequences. To decode
|
|
* it, use `sfparse_pctdecode`.
|
|
*
|
|
* If :member:`vec.len <sfparse_vec.len>` == 0, :member:`vec.base
|
|
* <sfparse_vec.base>` is guaranteed to be NULL.
|
|
*/
|
|
sfparse_vec vec;
|
|
/**
|
|
* @anonunion_end
|
|
*/
|
|
};
|
|
} sfparse_value;
|
|
|
|
/**
|
|
* @struct
|
|
*
|
|
* :type:`sfparse_parser` is the Structured Field Values parser. Use
|
|
* `sfparse_parser_init` to initialize it.
|
|
*/
|
|
typedef struct sfparse_parser {
|
|
/* all fields are private */
|
|
const uint8_t *pos;
|
|
const uint8_t *end;
|
|
uint32_t state;
|
|
} sfparse_parser;
|
|
|
|
/**
|
|
* @function
|
|
*
|
|
* `sfparse_parser_init` initializes |sfp| with the given data encoded
|
|
* in Structured Field Values pointed by |data| of length |datalen|.
|
|
*/
|
|
void sfparse_parser_init(sfparse_parser *sfp, const uint8_t *data,
|
|
size_t datalen);
|
|
|
|
/**
|
|
* @function
|
|
*
|
|
* `sfparse_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:`SFPARSE_ERR_EOF`, all parameters
|
|
* have read, and caller can continue to read rest of the values. If
|
|
* it returns :macro:`SFPARSE_ERR_PARSE`, it encountered fatal error
|
|
* while parsing field value.
|
|
*/
|
|
int sfparse_parser_param(sfparse_parser *sfp, sfparse_vec *dest_key,
|
|
sfparse_value *dest_value);
|
|
|
|
/**
|
|
* @function
|
|
*
|
|
* `sfparse_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 `sfparse_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:`SFPARSE_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:`SFPARSE_ERR_EOF`
|
|
* All values in the dictionary have read.
|
|
* :macro:`SFPARSE_ERR_PARSE`
|
|
* It encountered fatal error while parsing field value.
|
|
*/
|
|
int sfparse_parser_dict(sfparse_parser *sfp, sfparse_vec *dest_key,
|
|
sfparse_value *dest_value);
|
|
|
|
/**
|
|
* @function
|
|
*
|
|
* `sfparse_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 `sfparse_parser_param`.
|
|
*
|
|
* Caller should keep calling this function until it returns negative
|
|
* error code. If it returns :macro:`SFPARSE_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:`SFPARSE_ERR_EOF`
|
|
* All values in the list have read.
|
|
* :macro:`SFPARSE_ERR_PARSE`
|
|
* It encountered fatal error while parsing field value.
|
|
*/
|
|
int sfparse_parser_list(sfparse_parser *sfp, sfparse_value *dest);
|
|
|
|
/**
|
|
* @function
|
|
*
|
|
* `sfparse_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 `sfparse_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:`SFPARSE_ERR_EOF`, all data have been processed
|
|
* successfully.
|
|
*
|
|
* This function returns 0 if it succeeds, or one of the following
|
|
* negative error codes:
|
|
*
|
|
* :macro:`SFPARSE_ERR_EOF`
|
|
* There is nothing left to read.
|
|
* :macro:`SFPARSE_ERR_PARSE`
|
|
* It encountered fatal error while parsing field value.
|
|
*/
|
|
int sfparse_parser_item(sfparse_parser *sfp, sfparse_value *dest);
|
|
|
|
/**
|
|
* @function
|
|
*
|
|
* `sfparse_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 `sfparse_parser_param`.
|
|
*
|
|
* Caller should keep calling this function until it returns negative
|
|
* error code. If it returns :macro:`SFPARSE_ERR_EOF`, all values in
|
|
* this inner list have been read, and caller can optionally read
|
|
* parameters attached to this inner list by calling
|
|
* `sfparse_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:`SFPARSE_ERR_EOF`
|
|
* All values in the inner list have read.
|
|
* :macro:`SFPARSE_ERR_PARSE`
|
|
* It encountered fatal error while parsing field value.
|
|
*/
|
|
int sfparse_parser_inner_list(sfparse_parser *sfp, sfparse_value *dest);
|
|
|
|
/**
|
|
* @function
|
|
*
|
|
* `sfparse_unescape` copies |src| to |dest| by removing escapes
|
|
* (``\``). |src| should be the pointer to
|
|
* :member:`sfparse_value.vec` of type
|
|
* :enum:`sfparse_type.SFPARSE_TYPE_STRING` produced by either
|
|
* `sfparse_parser_dict`, `sfparse_parser_list`,
|
|
* `sfparse_parser_inner_list`, `sfparse_parser_item`, or
|
|
* `sfparse_parser_param`, otherwise the behavior is undefined.
|
|
*
|
|
* :member:`dest->base <sfparse_vec.base>` must point to the buffer
|
|
* that has sufficient space to store the unescaped string. The
|
|
* memory areas pointed by :member:`dest->base <sfparse_vec.base>` and
|
|
* :member:`src->base <sfparse_vec.base>` must not overlap.
|
|
*
|
|
* This function sets the length of unescaped string to
|
|
* :member:`dest->len <sfparse_vec.len>`.
|
|
*/
|
|
void sfparse_unescape(sfparse_vec *dest, const sfparse_vec *src);
|
|
|
|
/**
|
|
* @function
|
|
*
|
|
* `sfparse_base64decode` decodes Base64 encoded string |src| and
|
|
* writes the result into |dest|. |src| should be the pointer to
|
|
* :member:`sfparse_value.vec` of type
|
|
* :enum:`sfparse_type.SFPARSE_TYPE_BYTESEQ` produced by either
|
|
* `sfparse_parser_dict`, `sfparse_parser_list`,
|
|
* `sfparse_parser_inner_list`, `sfparse_parser_item`, or
|
|
* `sfparse_parser_param`, otherwise the behavior is undefined.
|
|
*
|
|
* :member:`dest->base <sfparse_vec.base>` must point to the buffer
|
|
* that has sufficient space to store the decoded byte string.
|
|
*
|
|
* This function sets the length of decoded byte string to
|
|
* :member:`dest->len <sfparse_vec.len>`.
|
|
*/
|
|
void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src);
|
|
|
|
/**
|
|
* @function
|
|
*
|
|
* `sfparse_pctdecode` decodes percent-encoded string |src| and writes
|
|
* the result into |dest|. |src| should be the pointer to
|
|
* :member:`sfparse_value.vec` of type
|
|
* :enum:`sfparse_type.SFPARSE_TYPE_DISPSTRING` produced by either
|
|
* `sfparse_parser_dict`, `sfparse_parser_list`,
|
|
* `sfparse_parser_inner_list`, `sfparse_parser_item`, or
|
|
* `sfparse_parser_param`, otherwise the behavior is undefined.
|
|
*
|
|
* :member:`dest->base <sfparse_vec.base>` must point to the buffer
|
|
* that has sufficient space to store the decoded byte string. The
|
|
* memory areas pointed by :member:`dest->base <sfparse_vec.base>` and
|
|
* :member:`src->base <sfparse_vec.base>` must not overlap.
|
|
*
|
|
* This function sets the length of decoded byte string to
|
|
* :member:`dest->len <sfparse_vec.len>`.
|
|
*/
|
|
void sfparse_pctdecode(sfparse_vec *dest, const sfparse_vec *src);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif /* defined(__cplusplus) */
|
|
|
|
#endif /* !defined(SFPARSE_H) */
|