#ifndef FHP_H #define FHP_H #include // for uint8_t #include // for size_t #include // for size_t // // hash functions (djb2) // (see http://aras-p.info/blog/2016/08/02/Hash-Functions-all-the-way-down/) // uint32_t fhp_hash_init(void); uint32_t fhp_hash_push(uint32_t, uint8_t * const, size_t); uint32_t fhp_hash_string(char * const); uint32_t fhp_lc_hash_push(uint32_t, uint8_t * const, size_t); uint32_t fhp_lc_hash_string(char * const); // // error functions // typedef enum { FHP_OK, FHP_ERR_CB, FHP_ERR_BAD_STATE, FHP_ERR_INVALID_CHAR, FHP_ERR_INVALID_CHAR_IN_METHOD, FHP_ERR_INVALID_CHAR_IN_URL, FHP_ERR_INVALID_CHAR_IN_URL_PERCENT, FHP_ERR_INVALID_CHAR_IN_VERSION, FHP_ERR_INVALID_CHAR_AFTER_CR, FHP_ERR_INVALID_CHAR_IN_HEADER_NAME, FHP_ERR_INVALID_ERROR, FHP_ERR_BUFFER_TOO_SMALL, FHP_ERR_INVALID_BODY_TYPE, FHP_ERR_TOO_MANY_TES, FHP_ERR_INVALID_CHAR_IN_TE_NAME, FHP_ERR_INVALID_CHAR_IN_TE, FHP_ERR_BAD_TE_STATE, FHP_ERR_TE_PARSER_DONE, FHP_ERR_NULL_TE_BUF, FHP_ERR_SMALL_TE_BUF, FHP_ERR_INVALID_CHAR_BEFORE_CL, FHP_ERR_INVALID_CHAR_IN_CL, FHP_ERR_INVALID_CHAR_AFTER_CL, FHP_ERR_CL_PARSER_DONE, FHP_ERR_BAD_CL_STATE, FHP_ERR_CL_OVERFLOW, FHP_ERR_LAST } fhp_err_t; fhp_err_t fhp_strerror(fhp_err_t, char * const, size_t); // // token functions // typedef enum { FHP_TOKEN_METHOD_START, FHP_TOKEN_METHOD_FRAGMENT, FHP_TOKEN_METHOD_END, FHP_TOKEN_METHOD_GET, FHP_TOKEN_METHOD_POST, FHP_TOKEN_METHOD_HEAD, FHP_TOKEN_METHOD_PUT, FHP_TOKEN_METHOD_DELETE, FHP_TOKEN_METHOD_OPTIONS, FHP_TOKEN_METHOD_OTHER, FHP_TOKEN_URL_START, FHP_TOKEN_URL_FRAGMENT, FHP_TOKEN_URL_END, FHP_TOKEN_VERSION_START, FHP_TOKEN_VERSION_FRAGMENT, FHP_TOKEN_VERSION_END, FHP_TOKEN_VERSION_HTTP_10, FHP_TOKEN_VERSION_HTTP_11, FHP_TOKEN_VERSION_OTHER, FHP_TOKEN_HEADER_NAME_START, FHP_TOKEN_HEADER_NAME_FRAGMENT, FHP_TOKEN_HEADER_NAME_END, FHP_TOKEN_HEADER_VALUE_START, FHP_TOKEN_HEADER_VALUE_FRAGMENT, FHP_TOKEN_HEADER_VALUE_END, FHP_TOKEN_HEADER_TRANSFER_ENCODING, FHP_TOKEN_HEADER_CONTENT_LENGTH, FHP_TOKEN_LAST } fhp_token_t; fhp_err_t fhp_strtoken(fhp_token_t, char * const, size_t); typedef enum { FHP_BODY_TYPE_NONE, FHP_BODY_TYPE_CONTENT_LENGTH, FHP_BODY_TYPE_TRANSFER_ENCODING, FHP_BODY_TYPE_LAST } fhp_body_type_t; // // env functions // #define FHP_ENV_NUM_HASHES 17 typedef struct { uint32_t hashes[FHP_ENV_NUM_HASHES]; } fhp_env_t; void fhp_env_init(fhp_env_t * const env); fhp_env_t *fhp_get_default_env(void); // // content-length parser functions // typedef enum { FHP_CL_STATE_INIT, FHP_CL_STATE_DATA, FHP_CL_STATE_TRAILING_SPACES, FHP_CL_STATE_ERROR, FHP_CL_STATE_DONE, FHP_CL_STATE_LAST } fhp_cl_state_t; typedef struct { fhp_cl_state_t state; fhp_err_t err; uint64_t val; } fhp_cl_parser_t; fhp_err_t fhp_cl_parser_init(fhp_cl_parser_t * const); fhp_err_t fhp_cl_parser_push(fhp_cl_parser_t *, uint8_t * const, size_t); fhp_err_t fhp_cl_parser_done(fhp_cl_parser_t * const, uint64_t * const); // // transfer-encoding parser functions // typedef enum { FHP_TE_STATE_INIT, FHP_TE_STATE_NAME, FHP_TE_STATE_IGNORE_UNTIL_COMMA, FHP_TE_STATE_SPACE, FHP_TE_STATE_ERROR, FHP_TE_STATE_DONE, FHP_TE_STATE_LAST } fhp_te_state_t; #define FHP_TE_MAX_BUF_SIZE 16 #define FHP_TE_MAX_TES 4 typedef struct { fhp_te_state_t state; uint8_t buf[FHP_TE_MAX_BUF_SIZE]; size_t len; uint32_t buf_hash; uint32_t tes[FHP_TE_MAX_TES]; size_t num_tes; fhp_err_t err; } fhp_te_parser_t; fhp_err_t fhp_te_parser_init(fhp_te_parser_t * const); fhp_err_t fhp_te_parser_push(fhp_te_parser_t *, uint8_t * const, size_t); fhp_err_t fhp_te_parser_done(fhp_te_parser_t * const, size_t * const); fhp_err_t fhp_te_parser_get_tes(fhp_te_parser_t * const, uint32_t * const, size_t); // // context functions // typedef struct fhp_ctx_t_ fhp_ctx_t; typedef bool (*fhp_cb_t)( fhp_ctx_t * const, fhp_token_t, uint8_t * const, size_t ); typedef enum { FHP_STATE_INIT, FHP_STATE_ERROR, FHP_STATE_METHOD, FHP_STATE_METHOD_END, FHP_STATE_URL, FHP_STATE_URL_PERCENT, FHP_STATE_URL_PERCENT_LAST, FHP_STATE_URL_END, FHP_STATE_VERSION, FHP_STATE_VERSION_END, FHP_STATE_VERSION_END_CR, FHP_STATE_STATUS_END, FHP_STATE_STATUS_END_CR, FHP_STATE_HEADER_NAME, FHP_STATE_HEADER_NAME_END, FHP_STATE_HEADER_NAME_END_CR, FHP_STATE_HEADER_VALUE, FHP_STATE_HEADER_VALUE_END_CR, FHP_STATE_HEADER_VALUE_END, FHP_STATE_HEADERS_END, FHP_STATE_HEADERS_END_CR, FHP_STATE_LAST } fhp_state_t; typedef enum { FHP_HEADER_VALUE_PARSER_NONE, FHP_HEADER_VALUE_PARSER_TRANSFER_ENCODING, FHP_HEADER_VALUE_PARSER_CONTENT_LENGTH, FHP_HEADER_VALUE_PARSER_LAST } fhp_header_value_parser_t; #define FHP_CTX_MAX_BUF_SIZE 1024 #define FHP_CTX_MAX_TRANSFER_ENCODINGS 4 struct fhp_ctx_t_ { // env pointer fhp_env_t *env; // opaque user data void *user_data; // current parser state fhp_state_t state; // user callback fhp_cb_t cb; // last error fhp_err_t err; // number of bytes read uint64_t ofs; // fragment data buffer uint8_t buf[FHP_CTX_MAX_BUF_SIZE]; size_t buf_len; // buffer hashing state bool is_hashing; uint32_t buf_hash; // cached http method and version fhp_token_t http_method, http_version; // hash of last header name uint32_t header_name_hash; // header value parser fhp_header_value_parser_t header_value_parser; union { fhp_te_parser_t te; fhp_cl_parser_t cl; } parsers; // request body type fhp_body_type_t body_type; // content length uint64_t content_length; // transfer encodings uint32_t tes[FHP_CTX_MAX_TRANSFER_ENCODINGS]; size_t num_tes; // state for url hex decoder uint32_t hex; }; fhp_err_t fhp_ctx_init(fhp_ctx_t * const, fhp_env_t * const, fhp_cb_t, void * const); fhp_err_t fhp_ctx_push(fhp_ctx_t * const, uint8_t * const, size_t); fhp_env_t * fhp_ctx_get_env(fhp_ctx_t * const); void * fhp_ctx_get_user_data(fhp_ctx_t * const); #endif /* FHP_H */