From ac9f95a91345561704c667ea387ee5efb2c67a8f Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Fri, 28 Jun 2013 20:41:42 +0200 Subject: chunked transfer getch done --- picohttp.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- picohttp.h | 4 +-- 2 files changed, 96 insertions(+), 9 deletions(-) diff --git a/picohttp.c b/picohttp.c index fe50424..1a01888 100644 --- a/picohttp.c +++ b/picohttp.c @@ -56,6 +56,14 @@ static char const PICOHTTP_STR_NAME__[] = " name=\""; static char const PICOHTTP_STR_CHUNKED[] = "chunked"; +/* compilation unit local function forward declarations */ +static int16_t picohttpProcessHeaders ( + struct picohttpRequest * const req, + picohttpHeaderFieldCallback headerfieldcallback, + void * const data, + int16_t ch ); + +/* compilation unit local helper functions */ #if !defined(PICOHTTP_CONFIG_HAVE_LIBDJB) /* Number formating functions modified from libdjb by * Daniel J. Bernstein, packaged at http://www.fefe.de/djb/ @@ -196,6 +204,23 @@ static int16_t picohttpIoB10ToU8 ( return ch; } +static int16_t picohttpIoB10ToU64 ( + uint64_t *i, + struct picohttpIoOps const * const ioops, + int16_t ch ) +{ + if( !ch ) + ch = picohttpIoGetch(ioops); + + while( ch >= '0' && ch <= '9' ) { + *i *= 10; + *i += (ch & 0x0f); + ch = picohttpIoGetch(ioops); + } + + return ch; +} + static int16_t picohttpIoGetPercentCh( struct picohttpIoOps const * const ioops ) { @@ -228,13 +253,75 @@ static int16_t picohttpIoGetPercentCh( int16_t picohttpGetch(struct picohttpRequest * const req) { - /* TODO: skipping over Chunked Transfer Boundaries + int16_t ch; + /* skipping over Chunked Transfer Boundaries * if Chunked Transfer Encoding is used */ - uint16_t ch = picohttpIoGetch(req->ioops); + if(req->query.transferencoding == PICOHTTP_CODING_CHUNKED ) { + if( !req->query.chunklength ) { + /* this is a new chunk; + * read the length and skip to after */ + if( 0 > (ch = picohttpIoGetch(req->ioops)) ) { + return -1; + } + uint64_t len; + if( 0 > (ch = picohttpIoB10ToU64( + &len, + req->ioops, + ch)) + ) { + return ch; + } + if( 0 > (ch = picohttpIoSkipOverCRLF(req->ioops, ch)) ) { + return ch; + } + req->query.chunklength = len; + return ch; + } + + if( req->query.chunklength <= req->received_octets ) { + /* If this happens the data is corrupted, or + * the client is nonconforming, or an attack is + * underway, or something entierely different, + * or all of that. + * Abort processing the query! + */ + return -1; + } + } - if( 0 <= ch ) { + if( 0 <= (ch = picohttpIoGetch(req->ioops)) ) { memmove(req->query.prev_ch + 1, req->query.prev_ch, 4); req->query.prev_ch[0] = ch; + req->received_octets++; + } else { + return ch; + } + + if(req->query.transferencoding == PICOHTTP_CODING_CHUNKED ) { + if( !req->query.chunklength <= req->received_octets ) { + /* end of chunk; + * skip over , make sure the trailing '0' is + * there and read the headers, err, I mean footers + * (whatever, the header processing code will do for + * chunk footers just fine). + */ + if( '0' != (ch = picohttpIoGetch(req->ioops)) ) { + return -1; + } + if( 0 > (ch = picohttpIoGetch(req->ioops)) ) { + return -1; + } + if( 0 > (ch = picohttpProcessHeaders( + req, + NULL, NULL, + ch)) + ) { + return ch; + } + + req->received_octets = + req->query.chunklength = 0; + } } return ch; @@ -634,6 +721,7 @@ static void picohttpProcessHeaderField( PICOHTTP_STR_CHUNKED, sizeof(PICOHTTP_STR_CHUNKED)-1)) { req->query.transferencoding = PICOHTTP_CODING_CHUNKED; + req->query.chunklength = 0; } return; } @@ -679,7 +767,7 @@ static int16_t picohttpProcessHeaders ( ch = picohttpIoGetch(req->ioops); } } else { - if( *headername && *headervalue ) + if( *headername && *headervalue && headerfieldcallback ) headerfieldcallback( data, headername, @@ -718,7 +806,7 @@ static int16_t picohttpProcessHeaders ( return -PICOHTTP_STATUS_400_BAD_REQUEST; } } - if( *headername && *headervalue ) + if( *headername && *headervalue && headerfieldcallback) headerfieldcallback( data, headername, @@ -763,6 +851,7 @@ void picohttpProcessRequest ( request.httpversion.minor = 0; request.sent.header = 0; request.sent.octets = 0; + request.received_octets = 0; request.method = picohttpProcessRequestMethod(ioops); if( !request.method ) { @@ -1035,7 +1124,7 @@ int16_t picohttpMultipartGetch( * preceeded by some * sequence that would * allow to be a valid multipart boundary. * In that case the exact replay parameters depend - * on the exact combination. + * on the specific combination. * * The replay code above also emits the last character * read from IO, but in this case that character is diff --git a/picohttp.h b/picohttp.h index 063ebd5..8afa022 100644 --- a/picohttp.h +++ b/picohttp.h @@ -122,6 +122,7 @@ struct picohttpRequest { uint8_t transferencoding; char multipartboundary[PICOHTTP_MULTIPARTBOUNDARY_MAX_LEN+1]; char prev_ch[5]; + size_t chunklength; } query; struct { char const *contenttype; @@ -132,9 +133,6 @@ struct picohttpRequest { uint8_t contentencoding; uint8_t transferencoding; } response; - struct { - size_t length; - } currentchunk; size_t received_octets; struct { size_t octets; -- cgit v1.2.3