summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fhp.c217
-rw-r--r--include/fhp/fhp.h45
-rw-r--r--test.c42
3 files changed, 301 insertions, 3 deletions
diff --git a/fhp.c b/fhp.c
index 44c20e4..fd1f746 100644
--- a/fhp.c
+++ b/fhp.c
@@ -160,6 +160,10 @@
CASE_TOKEN_CHARS \
case '/':
+#define CASE_TE_CHARS \
+ CASE_ALNUM_CHARS \
+ case '-':
+
//
// rfc7230, Appendix B
// https://tools.ietf.org/html/rfc7230
@@ -235,8 +239,13 @@ fhp_errors[] = {
"invalid character after carriage return",
"invalid character in HTTP header name",
"invalid error code",
- "invalid body type",
"buffer too small",
+ "invalid body type",
+ "too many transfer encodings",
+ "invalid character in transfer encoding name",
+ "invalid character in transfer encoding",
+ "bad transfer encoding state",
+ "transfer encoding parser already done",
};
fhp_err_t
@@ -392,10 +401,212 @@ fhp_get_default_env(void) {
}
//
+// transfer encoding buffer functions
+//
+
+static void
+fhp_te_parser_buf_flush(fhp_te_parser_t * const te) {
+ te->buf_hash = fhp_lc_hash_push(te->buf_hash, te->buf, te->len);
+ te->len = 0;
+}
+
+static void
+fhp_te_parser_buf_push(
+ fhp_te_parser_t * const te,
+ uint8_t byte
+) {
+ // flush buffer (if necessary)
+ if (te->len + 1 >= FHP_TE_MAX_BUF_SIZE)
+ fhp_te_parser_buf_flush(te);
+
+ // push to buffer
+ te->buf[te->len] = byte;
+ te->len++;
+}
+
+//
+// transfer encoding parser functions
+//
+
+static const fhp_te_parser_t FHP_DEFAULT_TE_PARSER = {
+ .state = FHP_TE_STATE_INIT,
+ .len = 0,
+ .num_tes = 0,
+ .err = FHP_OK,
+};
+
+fhp_err_t
+fhp_te_parser_init(fhp_te_parser_t * const te) {
+ // init parser
+ *te = FHP_DEFAULT_TE_PARSER;
+
+ // return succes
+ return FHP_OK;
+}
+
+static fhp_err_t
+fhp_te_parser_push_byte(
+ fhp_te_parser_t * const te,
+ uint8_t byte
+) {
+retry:
+ switch (te->state) {
+ case FHP_TE_STATE_INIT:
+ // set state
+ te->state = FHP_TE_STATE_SPACE;
+ goto retry;
+
+ break;
+ case FHP_TE_STATE_NAME:
+ switch (byte) {
+ CASE_TE_CHARS
+ // add to buffer
+ fhp_te_parser_buf_push(te, byte);
+
+ break;
+ CASE_OWS_CHARS
+ // flush buffer (if necessary)
+ if (te->len > 0)
+ fhp_te_parser_buf_flush(te);
+
+ // check number of encodings
+ if (te->num_tes + 1 >= FHP_TE_MAX_TES)
+ return FHP_ERR_TOO_MANY_TES;
+
+ // add to list of transfer encodings
+ // FIXME: check length
+ te->tes[te->num_tes] = te->buf_hash;
+ te->num_tes++;
+
+ // set state
+ te->state = FHP_TE_STATE_IGNORE_UNTIL_COMMA;
+
+ break;
+ case ',':
+ // flush buffer (if necessary)
+ if (te->len > 0)
+ fhp_te_parser_buf_flush(te);
+
+ // check number of encodings
+ if (te->num_tes + 1 >= FHP_TE_MAX_TES)
+ return FHP_ERR_TOO_MANY_TES;
+
+ // add to list of transfer encodings
+ // FIXME: check length
+ te->tes[te->num_tes] = te->buf_hash;
+ te->num_tes++;
+
+ // set state
+ te->state = FHP_TE_STATE_SPACE;
+
+ break;
+ default:
+ // invalid transfer encoding character
+ return FHP_ERR_INVALID_CHAR_IN_TE_NAME;
+ }
+
+ break;
+ case FHP_TE_STATE_IGNORE_UNTIL_COMMA:
+ switch (byte) {
+ case ',':
+ // set state
+ te->state = FHP_TE_STATE_SPACE;
+
+ break;
+ default:
+ // do nothing (ignore)
+ NULL;
+ }
+
+ break;
+ case FHP_TE_STATE_SPACE:
+ switch (byte) {
+ CASE_OWS_CHARS
+ // ignore leading spaces
+ break;
+ CASE_TE_CHARS
+ // clear buffer, init hash
+ te->len = 0;
+ te->buf_hash = fhp_hash_init();
+
+ // set state
+ te->state = FHP_TE_STATE_NAME;
+ goto retry;
+
+ break;
+ default:
+ // return error
+ return FHP_ERR_INVALID_CHAR_IN_TE;
+ }
+
+ break;
+ case FHP_TE_STATE_ERROR:
+ // return last error
+ return te->err;
+
+ break;
+ case FHP_TE_STATE_DONE:
+ // shouldn't be reached
+ return FHP_ERR_TE_PARSER_DONE;
+
+ break;
+ default:
+ // never reached
+ return FHP_ERR_BAD_TE_STATE;
+ }
+
+ // return succes
+ return FHP_OK;
+}
+
+fhp_err_t
+fhp_te_parser_push(
+ fhp_te_parser_t *te,
+ uint8_t * const buf,
+ size_t len
+) {
+ for (size_t i = 0; i < len; i++) {
+ // push byte
+ fhp_err_t err = fhp_te_parser_push_byte(te, buf[len]);
+
+ // check error
+ if (err != FHP_OK) {
+ // cache error
+ te->err = err;
+
+ // set state
+ te->state = FHP_TE_STATE_ERROR;
+
+ // return error
+ return err;
+ }
+ }
+
+ // return succes
+ return FHP_OK;
+}
+
+fhp_err_t
+fhp_te_parser_done(fhp_te_parser_t * const te) {
+ uint8_t buf[1] = { 20 };
+
+ // flush data, check for error
+ fhp_err_t err = fhp_te_parser_push(te, buf, 1);
+ if (err != FHP_OK)
+ return err;
+
+ // set state
+ te->state = FHP_TE_STATE_DONE;
+
+ // return success
+ return FHP_OK;
+}
+
+//
// context functions
//
-static const fhp_t DEFAULT_CONTEXT = {
+static const fhp_t FHP_DEFAULT_CONTEXT = {
.state = FHP_STATE_INIT,
.user_data = NULL,
.cb = NULL,
@@ -416,7 +627,7 @@ fhp_init(
fhp_cb_t cb,
void * const user_data
) {
- *fhp = DEFAULT_CONTEXT;
+ *fhp = FHP_DEFAULT_CONTEXT;
fhp->env = env ? env : fhp_get_default_env();
fhp->user_data = user_data;
fhp->cb = cb;
diff --git a/include/fhp/fhp.h b/include/fhp/fhp.h
index 9d680a9..d537a6e 100644
--- a/include/fhp/fhp.h
+++ b/include/fhp/fhp.h
@@ -34,6 +34,11 @@ typedef enum {
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_LAST
} fhp_err_t;
@@ -104,6 +109,46 @@ void fhp_env_init(fhp_env_t * const env);
fhp_env_t *fhp_get_default_env(void);
//
+// 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 te);
+
+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);
+
+//
// context functions
//
diff --git a/test.c b/test.c
index fc209b9..98e09d3 100644
--- a/test.c
+++ b/test.c
@@ -145,12 +145,54 @@ test_percent(void) {
}
}
+/******************/
+/* te parser test */
+/******************/
+
+static const char *
+te_parser_tests[] = {
+ "gzip",
+ "deflate",
+ "gzip,deflate,chunked",
+ "gzip, deflate, chunked",
+ "deflate , gzip , chunked ",
+ " deflate , gzip , chunked ",
+ NULL
+};
+
+static void
+test_te_parser(void) {
+ for (size_t i = 0; te_parser_tests[i]; i++) {
+ fhp_err_t err;
+
+ // get test string
+ const char *s = te_parser_tests[i];
+
+ // init parser
+ fhp_te_parser_t p;
+ fhp_te_parser_init(&p);
+
+ // parse data
+ if ((err = fhp_te_parser_push(&p, s, strlen(s))) != FHP_OK) {
+ die("test_te_parser", "fhp_te_parser_push", err);
+ }
+
+ // finish parsing
+ if ((err = fhp_te_parser_done(&p)) != FHP_OK) {
+ die("test_te_parser", "fhp_te_parser_push", err);
+ }
+
+ fprintf(stderr, "te test: \"%s\", p->num_tes = %u\n", s, p.num_tes);
+ }
+}
+
int main(int argc, char *argv[]) {
UNUSED(argc);
UNUSED(argv);
test_basic();
test_percent();
+ test_te_parser();
return EXIT_SUCCESS;
}