| #include <string.h> |
| |
| #include "mbtk_http_chunks.h" |
| #include "mbtk_http_base.h" |
| |
| static bool http_isxdigit(char digit) |
| { |
| return (digit >= 0x30 && digit <= 0x39) /* 0-9 */ |
| || (digit >= 0x41 && digit <= 0x46) /* A-F */ |
| || (digit >= 0x61 && digit <= 0x66); /* a-f */ |
| } |
| |
| void http_chunk_init(http_chunker_t *chunker) |
| { |
| chunker->hexindex = 0; /* start at 0 */ |
| chunker->dataleft = 0; /* no data left yet! */ |
| chunker->state = CHUNK_HEX; /* we get hex first! */ |
| } |
| |
| http_chunk_code http_chunk_parse(http_chunker_t *chunker, char *src, int src_len, |
| char *dest,int *dest_len) |
| { |
| int piece; |
| char *datap = src; |
| int length = src_len; |
| |
| *dest_len = 0; |
| |
| while(length > 0) |
| { |
| switch(chunker->state) |
| { |
| case CHUNK_HEX: |
| if(http_isxdigit(*datap)) |
| { |
| if(chunker->hexindex < MAXNUM_SIZE) |
| { |
| chunker->hexbuffer[chunker->hexindex] = *datap; |
| datap++; |
| length--; |
| chunker->hexindex++; |
| } |
| else |
| { |
| return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */ |
| } |
| } |
| else // Not hex char. ('\r') |
| { |
| if(0 == chunker->hexindex) |
| return CHUNKE_ILLEGAL_HEX; |
| |
| chunker->hexbuffer[chunker->hexindex] = '\0'; |
| sscanf(chunker->hexbuffer,"%x",&chunker->datasize); |
| |
| LOGD("Chunk len:%s -> %d",chunker->hexbuffer,chunker->datasize); |
| |
| chunker->state = CHUNK_LF; /* now wait for the CRLF */ |
| } |
| break; |
| case CHUNK_LF: |
| if(*datap == 0x0a) // '\n' |
| { |
| if(0 == chunker->datasize) { // Chunk lenght is '0' (Is last chunk) |
| chunker->state = CHUNK_TRAILER; |
| } else { |
| chunker->state = CHUNK_DATA; |
| } |
| } |
| |
| datap++; |
| length--; |
| break; |
| case CHUNK_DATA: |
| /* We expect 'datasize' of data. We have 'length' right now, it can be |
| more or less than 'datasize'. Get the smallest piece. |
| */ |
| piece = (chunker->datasize >= length)?length:chunker->datasize; |
| |
| memcpy(dest + *dest_len,datap,piece); |
| *dest_len += piece; |
| |
| chunker->datasize -= piece; /* decrease amount left to expect */ |
| datap += piece; /* move read pointer forward */ |
| length -= piece; /* decrease space left in this round */ |
| |
| if(0 == chunker->datasize) // Next chunk |
| chunker->state = CHUNK_POSTLF; |
| break; |
| case CHUNK_POSTLF: |
| if(*datap == 0x0a) |
| { |
| http_chunk_init(chunker); |
| } |
| else if(*datap != 0x0d) |
| return CHUNKE_BAD_CHUNK; |
| datap++; |
| length--; |
| break; |
| case CHUNK_TRAILER: |
| if((*datap != 0x0d) && (*datap != 0x0a)) |
| { |
| return CHUNKE_BAD_CHUNK; |
| } |
| if(*datap == 0x0d) |
| { |
| /* skip if CR */ |
| datap++; |
| length--; |
| } |
| chunker->state = CHUNK_STOP; |
| break; |
| case CHUNK_STOP: // Complete |
| if(*datap == 0x0a) |
| { |
| length--; |
| |
| /* Record the length of any data left in the end of the buffer |
| even if there's no more chunks to read */ |
| chunker->dataleft = length; |
| |
| return CHUNKE_STOP; /* return stop */ |
| } |
| else |
| return CHUNKE_BAD_CHUNK; |
| } |
| } |
| return CHUNKE_OK; |
| } |
| |
| |