From 0308b0cc9fab95f0f12aa874ae1fcded31d7f573 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Sun, 28 Aug 2016 23:23:10 -0400 Subject: add content-type parser --- Makefile | 2 +- ct-parser.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ ctx.c | 6 ++++++ env.c | 3 +++ header-value-parser.c | 19 +++++++++++++++++++ include/fhp/fhp.h | 33 ++++++++++++++++++++++++++++++++- internal.h | 3 +++ test.c | 1 + token.c | 1 + 9 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 ct-parser.c diff --git a/Makefile b/Makefile index 29e9424..b36c1b3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC ?= cc CFLAGS=-std=c99 -W -Wall -pedantic -O2 -Iinclude -fPIC -OBJS=ctx.o hash.o error.o token.o env.o te-parser.o cl-parser.o header-value-parser.o +OBJS=ctx.o hash.o error.o token.o env.o te-parser.o cl-parser.o ct-parser.o header-value-parser.o SONAME=libfhp.so LIB=libfhp.so STATIC_LIB=libfhp.a diff --git a/ct-parser.c b/ct-parser.c new file mode 100644 index 0000000..0eb98b3 --- /dev/null +++ b/ct-parser.c @@ -0,0 +1,49 @@ +#include "internal.h" + +// +// content-type parser +// + +fhp_err_t +fhp_ct_parser_init( + fhp_ct_parser_t * const p, + fhp_env_t * const env +) { + // init parser + p->env = env; + p->hash = fhp_hash_init(); + + // return succes + return FHP_OK; +} + +fhp_err_t +fhp_ct_parser_push( + fhp_ct_parser_t *p, + uint8_t * const buf, + size_t len +) { + p->hash = fhp_lc_hash_push(p->hash, buf, len); + + // return succes + return FHP_OK; +} + +fhp_err_t +fhp_ct_parser_done( + fhp_ct_parser_t * const p, + fhp_content_type_t * const ret_val +) { + if (ret_val) { + if (p->hash == p->env->hashes[FHP_STR_APPLICATION_X_WWW_FORM_URLENCODED]) { + *ret_val = FHP_CONTENT_TYPE_APPLICATION_X_WWW_FORM_URLENCODED; + } else if (p->hash == p->env->hashes[FHP_STR_MULTIPART_FORM_DATA]) { + *ret_val = FHP_CONTENT_TYPE_MULTIPART_FORM_DATA; + } else { + *ret_val = FHP_CONTENT_TYPE_OTHER; + } + } + + // return success + return FHP_OK; +} diff --git a/ctx.c b/ctx.c index d2d7245..60b379e 100644 --- a/ctx.c +++ b/ctx.c @@ -112,6 +112,7 @@ static const fhp_ctx_t FHP_CTX_DEFAULT = { .body_type = FHP_BODY_TYPE_NONE, .content_length = 0, .num_tes = 0, + .content_type = FHP_CONTENT_TYPE_NONE, }; fhp_err_t @@ -884,3 +885,8 @@ uint64_t fhp_ctx_get_content_length(fhp_ctx_t * const ctx) { return ctx->content_length; } + +fhp_content_type_t +fhp_ctx_get_content_type(fhp_ctx_t * const ctx) { + return ctx->content_type; +} diff --git a/env.c b/env.c index 6b94f0c..77c90f9 100644 --- a/env.c +++ b/env.c @@ -11,6 +11,7 @@ fhp_strings[] = { "HTTP/1.0", "HTTP/1.1", "content-length", + "content-type", "transfer-encoding", "gzip", "x-gzip", @@ -19,6 +20,8 @@ fhp_strings[] = { "compress", "x-compress", "chunked", + "application/x-www-form-urlencoded", + "multipart/form-data", NULL }; diff --git a/header-value-parser.c b/header-value-parser.c index e3c4107..d899889 100644 --- a/header-value-parser.c +++ b/header-value-parser.c @@ -33,6 +33,13 @@ fhp_header_value_parser_init(fhp_ctx_t * const ctx) { // 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; @@ -60,6 +67,9 @@ fhp_header_value_parser_push( 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; @@ -151,6 +161,15 @@ fhp_header_value_parser_done(fhp_ctx_t * const ctx) { 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; diff --git a/include/fhp/fhp.h b/include/fhp/fhp.h index 3aa020d..6225843 100644 --- a/include/fhp/fhp.h +++ b/include/fhp/fhp.h @@ -96,6 +96,7 @@ typedef enum { FHP_TOKEN_HEADER_TRANSFER_ENCODING, FHP_TOKEN_HEADER_CONTENT_LENGTH, + FHP_TOKEN_HEADER_CONTENT_TYPE, FHP_TOKEN_HEADERS_END, @@ -127,7 +128,7 @@ typedef enum { // env functions // -#define FHP_ENV_NUM_HASHES 17 +#define FHP_ENV_NUM_HASHES 20 typedef struct { uint32_t hashes[FHP_ENV_NUM_HASHES]; @@ -164,6 +165,32 @@ 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); +// +// content-type parser functions +// + +typedef enum { + FHP_CONTENT_TYPE_NONE, + FHP_CONTENT_TYPE_APPLICATION_X_WWW_FORM_URLENCODED, + FHP_CONTENT_TYPE_MULTIPART_FORM_DATA, + FHP_CONTENT_TYPE_OTHER, + FHP_CONTENT_TYPE_LAST +} fhp_content_type_t; + +typedef struct { + fhp_env_t *env; + uint32_t hash; +} fhp_ct_parser_t; + +fhp_err_t +fhp_ct_parser_init(fhp_ct_parser_t * const, fhp_env_t * const); + +fhp_err_t +fhp_ct_parser_push(fhp_ct_parser_t *, uint8_t * const, size_t); + +fhp_err_t +fhp_ct_parser_done(fhp_ct_parser_t * const, fhp_content_type_t * const); + // // transfer-encoding parser functions // @@ -257,6 +284,7 @@ typedef enum { FHP_HEADER_VALUE_PARSER_NONE, FHP_HEADER_VALUE_PARSER_TRANSFER_ENCODING, FHP_HEADER_VALUE_PARSER_CONTENT_LENGTH, + FHP_HEADER_VALUE_PARSER_CONTENT_TYPE, FHP_HEADER_VALUE_PARSER_LAST } fhp_header_value_parser_t; @@ -302,6 +330,7 @@ struct fhp_ctx_t_ { union { fhp_te_parser_t te; fhp_cl_parser_t cl; + fhp_ct_parser_t ct; } parsers; // request body type @@ -310,6 +339,8 @@ struct fhp_ctx_t_ { // content length uint64_t content_length; + fhp_content_type_t content_type; + // transfer encodings uint32_t tes[FHP_CTX_MAX_TRANSFER_ENCODINGS]; size_t num_tes; diff --git a/internal.h b/internal.h index 1e2733a..0f557a9 100644 --- a/internal.h +++ b/internal.h @@ -194,6 +194,7 @@ typedef enum { FHP_STR_HTTP_10, FHP_STR_HTTP_11, FHP_STR_CONTENT_LENGTH, + FHP_STR_CONTENT_TYPE, FHP_STR_TRANSFER_ENCODING, FHP_STR_GZIP, FHP_STR_X_GZIP, @@ -202,6 +203,8 @@ typedef enum { FHP_STR_COMPRESS, FHP_STR_X_COMPRESS, FHP_STR_CHUNKED, + FHP_STR_APPLICATION_X_WWW_FORM_URLENCODED, + FHP_STR_MULTIPART_FORM_DATA, FHP_STR_LAST } fhp_str_t; diff --git a/test.c b/test.c index 7bcb360..280eab0 100644 --- a/test.c +++ b/test.c @@ -31,6 +31,7 @@ static const char * basic_str = "GET / HTTP/1.1\r\n" "Host: pablotron.org\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" "Connection: close\r\n" "Content-Length: 15\r\n" "\r\n" diff --git a/token.c b/token.c index 721740d..d061692 100644 --- a/token.c +++ b/token.c @@ -40,6 +40,7 @@ fhp_tokens[] = { "HEADER_TRANSFER_ENCODING", "HEADER_CONTENT_LENGTH", + "HEADER_CONTENT_TYPE", "HEADERS_END", -- cgit v1.2.3