liubin | 281ac46 | 2023-07-19 14:22:54 +0800 | [diff] [blame] | 1 | #include <string.h> |
| 2 | |
| 3 | #include "mbtk_http_chunks.h" |
| 4 | #include "mbtk_http_base.h" |
| 5 | |
| 6 | static bool http_isxdigit(char digit) |
| 7 | { |
| 8 | return (digit >= 0x30 && digit <= 0x39) /* 0-9 */ |
| 9 | || (digit >= 0x41 && digit <= 0x46) /* A-F */ |
| 10 | || (digit >= 0x61 && digit <= 0x66); /* a-f */ |
| 11 | } |
| 12 | |
| 13 | void http_chunk_init(http_chunker_t *chunker) |
| 14 | { |
| 15 | chunker->hexindex = 0; /* start at 0 */ |
| 16 | chunker->dataleft = 0; /* no data left yet! */ |
| 17 | chunker->state = CHUNK_HEX; /* we get hex first! */ |
| 18 | } |
| 19 | |
| 20 | http_chunk_code http_chunk_parse(http_chunker_t *chunker, char *src, int src_len, |
| 21 | char *dest,int *dest_len) |
| 22 | { |
| 23 | int piece; |
| 24 | char *datap = src; |
| 25 | int length = src_len; |
| 26 | |
| 27 | *dest_len = 0; |
| 28 | |
| 29 | while(length > 0) |
| 30 | { |
| 31 | switch(chunker->state) |
| 32 | { |
| 33 | case CHUNK_HEX: |
| 34 | if(http_isxdigit(*datap)) |
| 35 | { |
| 36 | if(chunker->hexindex < MAXNUM_SIZE) |
| 37 | { |
| 38 | chunker->hexbuffer[chunker->hexindex] = *datap; |
| 39 | datap++; |
| 40 | length--; |
| 41 | chunker->hexindex++; |
| 42 | } |
| 43 | else |
| 44 | { |
| 45 | return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */ |
| 46 | } |
| 47 | } |
| 48 | else // Not hex char. ('\r') |
| 49 | { |
| 50 | if(0 == chunker->hexindex) |
| 51 | return CHUNKE_ILLEGAL_HEX; |
| 52 | |
| 53 | chunker->hexbuffer[chunker->hexindex] = '\0'; |
| 54 | sscanf(chunker->hexbuffer,"%x",&chunker->datasize); |
| 55 | |
| 56 | LOGD("Chunk len:%s -> %d",chunker->hexbuffer,chunker->datasize); |
| 57 | |
| 58 | chunker->state = CHUNK_LF; /* now wait for the CRLF */ |
| 59 | } |
| 60 | break; |
| 61 | case CHUNK_LF: |
| 62 | if(*datap == 0x0a) // '\n' |
| 63 | { |
| 64 | if(0 == chunker->datasize) { // Chunk lenght is '0' (Is last chunk) |
| 65 | chunker->state = CHUNK_TRAILER; |
| 66 | } else { |
| 67 | chunker->state = CHUNK_DATA; |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | datap++; |
| 72 | length--; |
| 73 | break; |
| 74 | case CHUNK_DATA: |
| 75 | /* We expect 'datasize' of data. We have 'length' right now, it can be |
| 76 | more or less than 'datasize'. Get the smallest piece. |
| 77 | */ |
| 78 | piece = (chunker->datasize >= length)?length:chunker->datasize; |
| 79 | |
| 80 | memcpy(dest + *dest_len,datap,piece); |
| 81 | *dest_len += piece; |
| 82 | |
| 83 | chunker->datasize -= piece; /* decrease amount left to expect */ |
| 84 | datap += piece; /* move read pointer forward */ |
| 85 | length -= piece; /* decrease space left in this round */ |
| 86 | |
| 87 | if(0 == chunker->datasize) // Next chunk |
| 88 | chunker->state = CHUNK_POSTLF; |
| 89 | break; |
| 90 | case CHUNK_POSTLF: |
| 91 | if(*datap == 0x0a) |
| 92 | { |
| 93 | http_chunk_init(chunker); |
| 94 | } |
| 95 | else if(*datap != 0x0d) |
| 96 | return CHUNKE_BAD_CHUNK; |
| 97 | datap++; |
| 98 | length--; |
| 99 | break; |
| 100 | case CHUNK_TRAILER: |
| 101 | if((*datap != 0x0d) && (*datap != 0x0a)) |
| 102 | { |
| 103 | return CHUNKE_BAD_CHUNK; |
| 104 | } |
| 105 | if(*datap == 0x0d) |
| 106 | { |
| 107 | /* skip if CR */ |
| 108 | datap++; |
| 109 | length--; |
| 110 | } |
| 111 | chunker->state = CHUNK_STOP; |
| 112 | break; |
| 113 | case CHUNK_STOP: // Complete |
| 114 | if(*datap == 0x0a) |
| 115 | { |
| 116 | length--; |
| 117 | |
| 118 | /* Record the length of any data left in the end of the buffer |
| 119 | even if there's no more chunks to read */ |
| 120 | chunker->dataleft = length; |
| 121 | |
| 122 | return CHUNKE_STOP; /* return stop */ |
| 123 | } |
| 124 | else |
| 125 | return CHUNKE_BAD_CHUNK; |
| 126 | } |
| 127 | } |
| 128 | return CHUNKE_OK; |
| 129 | } |
| 130 | |
| 131 | |