diff options
author | Paul Duncan <pabs@pablotron.org> | 2016-08-28 20:32:55 -0400 |
---|---|---|
committer | Paul Duncan <pabs@pablotron.org> | 2016-08-28 20:32:55 -0400 |
commit | 845ddb43da8aa2a8c80a9d9638d63386ddf97d7e (patch) | |
tree | 2dc0c914ac0625b8d8289d2b5d09269e6dd4ed65 /ctx.c | |
parent | 566fd0d75c4a46b8a69f67a75ecfb704e985db01 (diff) | |
download | libfhp-845ddb43da8aa2a8c80a9d9638d63386ddf97d7e.tar.bz2 libfhp-845ddb43da8aa2a8c80a9d9638d63386ddf97d7e.zip |
add content-length handling and partial chunked transfer-encoding support (still need footers and compression)
Diffstat (limited to 'ctx.c')
-rw-r--r-- | ctx.c | 233 |
1 files changed, 233 insertions, 0 deletions
@@ -391,6 +391,7 @@ retry: case '\n': // set state ctx->state = FHP_STATE_HEADERS_END; + goto retry; break; } @@ -401,6 +402,7 @@ retry: case '\n': // set state ctx->state = FHP_STATE_HEADERS_END; + goto retry; break; default: @@ -568,6 +570,7 @@ retry: // set state ctx->state = FHP_STATE_HEADERS_END; + goto retry; break; default: @@ -579,6 +582,7 @@ retry: switch (byte) { case '\n': ctx->state = FHP_STATE_HEADERS_END; + goto retry; break; default: @@ -587,7 +591,236 @@ retry: break; case FHP_STATE_HEADERS_END: + // send end headers token + if (!ctx->cb(ctx, FHP_TOKEN_HEADERS_END, 0, 0)) + return FHP_ERR_CB; + + switch (ctx->body_type) { + case FHP_BODY_TYPE_NONE: + // no body + + // send request end token + if (!ctx->cb(ctx, FHP_TOKEN_REQUEST_END, 0, 0)) + return FHP_ERR_CB; + + // set state + ctx->state = FHP_STATE_REQUEST_END; + + break; + case FHP_BODY_TYPE_CONTENT_LENGTH: + // send body start token + if (!ctx->cb(ctx, FHP_TOKEN_BODY_START, 0, 0)) + return FHP_ERR_CB; + + if (ctx->content_length > 0) { + // grab content length and clear buffer + ctx->bytes_left = ctx->content_length; + ctx->buf_len = 0; + + // set state + ctx->state = FHP_STATE_CL_BODY; + } else { + // empty body + + // send body end token + if (!ctx->cb(ctx, FHP_TOKEN_BODY_END, 0, 0)) + return FHP_ERR_CB; + + // send request end token + if (!ctx->cb(ctx, FHP_TOKEN_REQUEST_END, 0, 0)) + return FHP_ERR_CB; + + // set state + ctx->state = FHP_STATE_REQUEST_END; + } + + break; + case FHP_BODY_TYPE_TRANSFER_ENCODING: + // send body start token + if (!ctx->cb(ctx, FHP_TOKEN_BODY_START, 0, 0)) + return FHP_ERR_CB; + + // clear chunk size + ctx->chunk_len = 0; + + // set state + ctx->state = FHP_STATE_CHUNK_LEN; + + break; + default: + // invalid body type (bug?) + return FHP_ERR_INVALID_BODY_TYPE; + } + + break; + case FHP_STATE_CL_BODY: + // add to buffer + if ((err = fhp_ctx_buf_push(ctx, FHP_TOKEN_BODY_FRAGMENT, byte)) != FHP_OK) + return err; + + // decriment remaining bytes + ctx->bytes_left--; + + if (!ctx->bytes_left) { + // flush buffer + if ((err = fhp_ctx_buf_flush(ctx, FHP_TOKEN_BODY_FRAGMENT)) != FHP_OK) + return err; + + // send body end token + if (!ctx->cb(ctx, FHP_TOKEN_BODY_END, 0, 0)) + return FHP_ERR_CB; + + // send request end token + if (!ctx->cb(ctx, FHP_TOKEN_REQUEST_END, 0, 0)) + return FHP_ERR_CB; + + // set state + ctx->state = FHP_STATE_REQUEST_END; + } + + break; + case FHP_STATE_CHUNK_LEN: + { + uint64_t old_chunk_len = ctx->chunk_len; + + switch (byte) { + case '\r': + // set state + ctx->state = FHP_STATE_CHUNK_LEN_CR; + + break; + case '\n': + // set state + ctx->state = FHP_STATE_CHUNK_LEN_CR; + goto retry; + + break; + CASE_DIGIT_CHARS + // update chunk length + ctx->chunk_len = (ctx->chunk_len << 4) + (byte - '0'); + + break; + CASE_HEX_LC_ALPHA_CHARS + // update chunk length + ctx->chunk_len = (ctx->chunk_len << 4) + (byte - 'a'); + + break; + CASE_HEX_UC_ALPHA_CHARS + // update chunk length + ctx->chunk_len = (ctx->chunk_len << 4) + (byte - 'A'); + + break; + default: + // invalid character + return FHP_ERR_INVALID_CHAR_IN_CHUNK_LEN; + } + + // check for overflow + if (ctx->chunk_len < old_chunk_len) { + // overflow in chunk length + return FHP_ERR_CHUNK_LEN_OVERFLOW; + } + } + + break; + case FHP_STATE_CHUNK_LEN_CR: + switch (byte) { + case '\n': + // TODO: check chunk len + + if (ctx->chunk_len > 0) { + ctx->bytes_left = ctx->chunk_len; + ctx->buf_len = 0; + + // send chunk start token + if (!ctx->cb(ctx, FHP_TOKEN_CHUNK_START, 0, 0)) + return FHP_ERR_CB; + + // set state + ctx->state = FHP_STATE_CHUNK_BODY; + } else { + // last chunk + + // send chunk start token + if (!ctx->cb(ctx, FHP_TOKEN_CHUNK_LAST, 0, 0)) + return FHP_ERR_CB; + + // set state + ctx->state = FHP_STATE_TE_FOOTER; + } + + break; + default: + return FHP_ERR_INVALID_CHAR_AFTER_CHUNK_LEN; + } + + break; + case FHP_STATE_CHUNK_BODY: + // add to buffer + if ((err = fhp_ctx_buf_push(ctx, FHP_TOKEN_BODY_FRAGMENT, byte)) != FHP_OK) + return err; + + // decriment remaining bytes + ctx->bytes_left--; + + if (!ctx->bytes_left) { + // flush buffer + if ((err = fhp_ctx_buf_flush(ctx, FHP_TOKEN_BODY_FRAGMENT)) != FHP_OK) + return err; + + // send body end token + if (!ctx->cb(ctx, FHP_TOKEN_CHUNK_END, 0, 0)) + return FHP_ERR_CB; + + // set state + ctx->state = FHP_STATE_CHUNK_BODY_END; + } + break; + case FHP_STATE_CHUNK_BODY_END: + switch (byte) { + case '\r': + // set state + ctx->state = FHP_STATE_CHUNK_BODY_END_CR; + + break; + case '\n': + // set state + ctx->state = FHP_STATE_CHUNK_BODY_END_CR; + goto retry; + + break; + default: + return FHP_ERR_INVALID_CHAR_AFTER_CHUNK_BODY; + } + + break; + case FHP_STATE_CHUNK_BODY_END_CR: + switch (byte) { + case '\n': + // clear chunk len, set state + ctx->chunk_len = 0; + ctx->state = FHP_STATE_CHUNK_LEN; + + break; + default: + return FHP_ERR_INVALID_CHAR_AFTER_CHUNK_BODY; + } + + break; + case FHP_STATE_TE_FOOTER: // TODO + break; + case FHP_STATE_REQUEST_END: + switch (byte) { + case '\r': + case '\n': + // eat newlines + break; + default: + // set state + ctx->state = FHP_STATE_INIT; + goto retry; + } break; default: |