summaryrefslogtreecommitdiff
path: root/cl-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'cl-parser.c')
-rw-r--r--cl-parser.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/cl-parser.c b/cl-parser.c
new file mode 100644
index 0000000..83863c5
--- /dev/null
+++ b/cl-parser.c
@@ -0,0 +1,150 @@
+#include "internal.h"
+
+//
+// content length functions
+//
+
+static const fhp_cl_parser_t FHP_DEFAULT_CL_PARSER = {
+ .state = FHP_CL_STATE_INIT,
+ .val = 0,
+ .err = FHP_OK,
+};
+
+fhp_err_t
+fhp_cl_parser_init(fhp_cl_parser_t * const p) {
+ // init parser
+ *p = FHP_DEFAULT_CL_PARSER;
+
+ // return succes
+ return FHP_OK;
+}
+
+static fhp_err_t
+fhp_cl_parser_push_byte(
+ fhp_cl_parser_t * const p,
+ uint8_t byte
+) {
+retry:
+ switch (p->state) {
+ case FHP_CL_STATE_INIT:
+ switch (byte) {
+ CASE_OWS_CHARS
+ // ignore
+ break;
+ CASE_DIGIT_CHARS
+ // set state
+ p->state = FHP_CL_STATE_DATA;
+ goto retry;
+
+ break;
+ default:
+ // invalid character before content-length
+ return FHP_ERR_INVALID_CHAR_BEFORE_CL;
+ }
+
+ break;
+ case FHP_CL_STATE_DATA:
+ switch (byte) {
+ CASE_OWS_CHARS
+ // set state
+ p->state = FHP_CL_STATE_TRAILING_SPACES;
+ goto retry;
+
+ break;
+ CASE_DIGIT_CHARS
+ {
+ // cache old value
+ uint64_t old_val = p->val;
+
+ // update value
+ p->val = p->val * 10 + (byte - '0');
+
+ // check for overflow
+ if (p->val < old_val)
+ return FHP_ERR_CL_OVERFLOW;
+ }
+
+ break;
+ default:
+ // invalid character in content-length
+ return FHP_ERR_INVALID_CHAR_IN_CL;
+ }
+
+ break;
+ case FHP_CL_STATE_TRAILING_SPACES:
+ switch (byte) {
+ CASE_OWS_CHARS
+ // ignore trailing spaces
+
+ break;
+ default:
+ // invalid character after content-length
+ return FHP_ERR_INVALID_CHAR_AFTER_CL;
+ }
+
+ break;
+ case FHP_CL_STATE_ERROR:
+ // return last error
+ return p->err;
+
+ break;
+ case FHP_CL_STATE_DONE:
+ // shouldn't be reached
+ return FHP_ERR_CL_PARSER_DONE;
+
+ break;
+ default:
+ // never reached
+ return FHP_ERR_BAD_CL_STATE;
+ }
+
+ // return succes
+ return FHP_OK;
+}
+
+fhp_err_t
+fhp_cl_parser_push(
+ fhp_cl_parser_t *p,
+ uint8_t * const buf,
+ size_t len
+) {
+ for (size_t i = 0; i < len; i++) {
+ // push byte
+ fhp_err_t err = fhp_cl_parser_push_byte(p, buf[i]);
+
+ // check error
+ if (err != FHP_OK) {
+ // cache error
+ p->err = err;
+
+ // set state
+ p->state = FHP_CL_STATE_ERROR;
+
+ // return error
+ return err;
+ }
+ }
+
+ // return succes
+ return FHP_OK;
+}
+
+fhp_err_t
+fhp_cl_parser_done(
+ fhp_cl_parser_t * const p,
+ uint64_t * const ret_val
+) {
+ // check for error
+ if (p->err != FHP_OK)
+ return p->err;
+
+ // set state
+ p->state = FHP_TE_STATE_DONE;
+
+ // save number of tes
+ if (ret_val)
+ *ret_val = p->val;
+
+ // return success
+ return FHP_OK;
+}