summaryrefslogtreecommitdiff
path: root/ctx.c
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2016-08-28 20:32:55 -0400
committerPaul Duncan <pabs@pablotron.org>2016-08-28 20:32:55 -0400
commit845ddb43da8aa2a8c80a9d9638d63386ddf97d7e (patch)
tree2dc0c914ac0625b8d8289d2b5d09269e6dd4ed65 /ctx.c
parent566fd0d75c4a46b8a69f67a75ecfb704e985db01 (diff)
downloadlibfhp-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.c233
1 files changed, 233 insertions, 0 deletions
diff --git a/ctx.c b/ctx.c
index 405223f..d2d7245 100644
--- a/ctx.c
+++ b/ctx.c
@@ -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: