diff options
author | jcid <devnull@localhost> | 2007-11-28 15:09:07 +0100 |
---|---|---|
committer | jcid <devnull@localhost> | 2007-11-28 15:09:07 +0100 |
commit | ba08ee0b4e87d71aae5c96aff1bd89e5c1dd6827 (patch) | |
tree | 20b43f3a6620db27b1a1efd7ae346b718eb93022 /src/decode.c | |
parent | b0358c3dea7a0f34dc494d82be08ae814a480a50 (diff) |
Added HTTP-1.1's chunked transfer support!
Diffstat (limited to 'src/decode.c')
-rw-r--r-- | src/decode.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/decode.c b/src/decode.c index 30000e05..f53901f1 100644 --- a/src/decode.c +++ b/src/decode.c @@ -2,6 +2,7 @@ #include <zlib.h> #include <iconv.h> #include <errno.h> +#include <stdlib.h> /* strtol */ #include "decode.h" #include "msg.h" @@ -22,6 +23,75 @@ static void Decode_null_free(Decode *dc) } /* + * Decode chunked data + */ +static Dstr *Decode_chunked(Decode *dc, Dstr *input) +{ + char *inputPtr, *eol; + int inputRemaining; + int chunkRemaining = *((int *)dc->state); + Dstr *output = dStr_sized_new(input->len); + + dStr_append_l(dc->leftover, input->str, input->len); + dStr_free(input, 1); + input = dc->leftover; + inputPtr = input->str; + inputRemaining = input->len; + + while (inputRemaining > 0) { + if (chunkRemaining > 2) { + /* chunk body to copy */ + int copylen = MIN(chunkRemaining - 2, inputRemaining); + dStr_append_l(output, inputPtr, copylen); + chunkRemaining -= copylen; + inputRemaining -= copylen; + inputPtr += copylen; + } + + if ((chunkRemaining == 2) && (inputRemaining > 0)) { + /* CR to discard */ + chunkRemaining--; + inputRemaining--; + inputPtr++; + } + if ((chunkRemaining == 1) && (inputRemaining > 0)) { + /* LF to discard */ + chunkRemaining--; + inputRemaining--; + inputPtr++; + } + + /* + * A chunk has a one-line header that begins with the chunk length + * in hexadecimal. + */ + if (!(eol = (char *)memchr(inputPtr, '\n', inputRemaining))) { + break; /* We don't have the whole line yet. */ + } + + if (!(chunkRemaining = strtol(inputPtr, NULL, 0x10))) { + break; /* A chunk length of 0 means we're done! */ + } + inputRemaining -= (eol - inputPtr) + 1; + inputPtr = eol + 1; + chunkRemaining += 2; /* CRLF at the end of every chunk */ + } + + /* If we have a partial chunk header, save it for next time. */ + dc->leftover = input; + dStr_erase(dc->leftover, 0, inputPtr - input->str); + + *(int *)dc->state = chunkRemaining; + return output; +} + +static void Decode_chunked_free(Decode *dc) +{ + dFree(dc->state); + dStr_free(dc->leftover, 1); +} + +/* * Decode gzipped data */ static Dstr *Decode_gzip(Decode *dc, Dstr *input) @@ -132,6 +202,33 @@ static void Decode_charset_free(Decode *dc) } /* + * Initialize transfer decoder. Currently handles "chunked". + */ +Decode *a_Decode_transfer_init(const char *format) +{ + Decode *dc = (Decode *)dMalloc(sizeof(Decode)); + + /* not used */ + dc->buffer = NULL; + + dc->leftover = dStr_new(""); + + if (format && !dStrncasecmp(format, "chunked", 7)) { + int *chunk_remaining = (int *)dMalloc(sizeof(int)); + *chunk_remaining = 0; + dc->state = chunk_remaining; + dc->decode = Decode_chunked; + dc->free = Decode_chunked_free; + MSG("chunked!\n"); + } else { + dc->state = NULL; + dc->decode = Decode_null; + dc->free = Decode_null_free; + } + return dc; +} + +/* * Initialize content decoder. Currently handles gzip. * * zlib is also capable of handling "deflate"/zlib-encoded data, but web |