#include "internal.h" // // header value parser // fhp_err_t fhp_header_value_parser_init(fhp_ctx_t * const ctx) { uint32_t hash = ctx->header_name_hash; fhp_header_value_parser_t parser = FHP_HEADER_VALUE_PARSER_NONE; fhp_err_t err; /* fprintf( stderr, "hashes: header = %u, env = %u, str = %u, str(lc) = %u\n", hash, fhp->env->hashes[FHP_STR_TRANSFER_ENCODING], fhp_hash_string("Transfer-Encoding"), fhp_lc_hash_string("Transfer-Encoding") ); */ if (hash == ctx->env->hashes[FHP_STR_TRANSFER_ENCODING]) { // set parser type parser = FHP_HEADER_VALUE_PARSER_TRANSFER_ENCODING; // init parser if ((err = fhp_te_parser_init(&(ctx->parsers.te))) != FHP_OK) return err; } else if (hash == ctx->env->hashes[FHP_STR_CONTENT_LENGTH]) { // set parser type parser = FHP_HEADER_VALUE_PARSER_CONTENT_LENGTH; // init parser if ((err = fhp_cl_parser_init(&(ctx->parsers.cl))) != FHP_OK) return err; } else if (hash == ctx->env->hashes[FHP_STR_CONTENT_TYPE]) { // set parser type parser = FHP_HEADER_VALUE_PARSER_CONTENT_TYPE; // init parser if ((err = fhp_ct_parser_init(&(ctx->parsers.ct), ctx->env)) != FHP_OK) return err; } else { // set default parser type parser = FHP_HEADER_VALUE_PARSER_NONE; } // set value parser ctx->header_value_parser = parser; // return success return FHP_OK; } fhp_err_t fhp_header_value_parser_push( fhp_ctx_t * const ctx, uint8_t * const buf, size_t len ) { fhp_err_t r = FHP_OK; switch (ctx->header_value_parser) { case FHP_HEADER_VALUE_PARSER_TRANSFER_ENCODING: r = fhp_te_parser_push(&(ctx->parsers.te), buf, len); break; case FHP_HEADER_VALUE_PARSER_CONTENT_LENGTH: r = fhp_cl_parser_push(&(ctx->parsers.cl), buf, len); break; case FHP_HEADER_VALUE_PARSER_CONTENT_TYPE: r = fhp_ct_parser_push(&(ctx->parsers.ct), buf, len); break; default: // do nothing r = FHP_OK; break; } // return result return r; } fhp_err_t fhp_header_value_parser_done(fhp_ctx_t * const ctx) { fhp_err_t r = FHP_OK; switch (ctx->header_value_parser) { case FHP_HEADER_VALUE_PARSER_TRANSFER_ENCODING: // finish parsing tes if ((r = fhp_te_parser_done(&(ctx->parsers.te), &(ctx->num_tes))) != FHP_OK) return r; // check number of tes if (ctx->num_tes > FHP_CTX_MAX_TRANSFER_ENCODINGS) return FHP_ERR_TOO_MANY_TES; // copy tes to context if ((r = fhp_te_parser_get_tes(&(ctx->parsers.te), ctx->tes, FHP_CTX_MAX_TRANSFER_ENCODINGS)) != FHP_OK) return r; // update body type // FIXME: follow RFC7230 3.3.3 // https://tools.ietf.org/html/rfc7230#section-3.3.3 switch (ctx->body_type) { case FHP_BODY_TYPE_NONE: // set body type ctx->body_type = FHP_BODY_TYPE_CONTENT_LENGTH; break; case FHP_BODY_TYPE_CONTENT_LENGTH: // duplicate content-length // FIXME: should print warning here break; case FHP_BODY_TYPE_TRANSFER_ENCODING: // already have transfer-encoding, ignore content-length // FIXME: should print warning here break; default: // never reached return FHP_ERR_INVALID_BODY_TYPE; } // notify callback if (!ctx->cb(ctx, FHP_TOKEN_HEADER_TRANSFER_ENCODING, 0, 0)) return FHP_ERR_CB; break; case FHP_HEADER_VALUE_PARSER_CONTENT_LENGTH: // finish parsing content-length and copy to context if ((r = fhp_cl_parser_done(&(ctx->parsers.cl), &(ctx->content_length))) != FHP_OK) return r; // update body type // FIXME: follow RFC7230 3.3.3 // https://tools.ietf.org/html/rfc7230#section-3.3.3 switch (ctx->body_type) { case FHP_BODY_TYPE_NONE: // set body type ctx->body_type = FHP_BODY_TYPE_CONTENT_LENGTH; break; case FHP_BODY_TYPE_CONTENT_LENGTH: // both content-type and transfer-encoding, ignore content-type // FIXME: should print warning here break; case FHP_BODY_TYPE_TRANSFER_ENCODING: // duplicate transfer-encoding // FIXME: should print warnings break; default: // never reached return FHP_ERR_INVALID_BODY_TYPE; } // notify callback if (!ctx->cb(ctx, FHP_TOKEN_HEADER_CONTENT_LENGTH, 0, 0)) return FHP_ERR_CB; break; case FHP_HEADER_VALUE_PARSER_CONTENT_TYPE: // finish parsing content-length and copy to context if ((r = fhp_ct_parser_done(&(ctx->parsers.ct), &(ctx->content_type))) != FHP_OK) return r; // notify callback if (!ctx->cb(ctx, FHP_TOKEN_HEADER_CONTENT_TYPE, 0, 0)) return FHP_ERR_CB; default: // do nothing r = FHP_OK; break; } // clear header value parser ctx->header_value_parser = FHP_HEADER_VALUE_PARSER_NONE; // return result return r; }