Line 8... |
Line 8... |
8 |
#include <stdlib.h> /* atol() */
|
8 |
#include <stdlib.h> /* atol() */
|
9 |
#include <string.h>
|
9 |
#include <string.h>
|
10 |
|
10 |
|
11 |
#include "unchunk.h"
|
11 |
#include "unchunk.h"
|
12 |
|
12 |
|
- |
|
13 |
|
13 |
/* transforms a http CHUNKED stream into actual data, returns the amount of raw data to read */
|
14 |
/* transforms a http CHUNKED stream into actual data, returns the amount of
|
14 |
int unchunk(unsigned char *buff, int bufflen) {
|
- |
|
15 |
static long bytesleft; /* how many bytes are expected yet in the ongoing chunk */
|
15 |
* raw data to read or -1 on error. st MUST be zeroed before first call. */
|
16 |
static char partial_hdr[16]; /* a small buffer for storing partial chunk headers, if these are transmitted in separate parts */
|
16 |
int unchunk(unsigned char *buff, int bufflen, struct unchunk_state *st) {
|
17 |
int hdrstart, hdrend;
|
17 |
int hdrstart, hdrend;
|
18 |
|
18 |
|
19 |
/* if chunk header was being in progress, try to decode it now */
|
19 |
/* if chunk header was being in progress, try to decode it now */
|
20 |
if (bytesleft == -1) {
|
20 |
if (st->bytesleft == -1) {
|
21 |
int partial_hdr_len = strlen(partial_hdr);
|
21 |
int partial_hdr_len = strlen(st->partial_hdr);
|
22 |
/* locate header terminator, if available */
|
22 |
/* locate header terminator, if available */
|
23 |
for (hdrend = 0; (hdrend < bufflen) && (buff[hdrend] != '\n'); hdrend++);
|
23 |
for (hdrend = 0; (hdrend < bufflen) && (buff[hdrend] != '\n'); hdrend++);
|
24 |
if (partial_hdr_len + hdrend > 15) return(-1); /* error: chunk header too long */
|
24 |
if (partial_hdr_len + hdrend > 15) return(-1); /* error: chunk header too long */
|
25 |
|
25 |
|
26 |
/* copy header to buffer */
|
26 |
/* copy header to buffer */
|
27 |
memcpy(partial_hdr + partial_hdr_len, buff, hdrend);
|
27 |
memcpy(st->partial_hdr + partial_hdr_len, buff, hdrend);
|
28 |
partial_hdr[partial_hdr_len + hdrend] = 0;
|
28 |
st->partial_hdr[partial_hdr_len + hdrend] = 0;
|
29 |
|
29 |
|
30 |
/* quit if header still no complete */
|
30 |
/* quit if header still no complete */
|
31 |
if (hdrend >= bufflen) return(0);
|
31 |
if (hdrend >= bufflen) return(0);
|
32 |
|
32 |
|
33 |
/* good, got whole header */
|
33 |
/* good, got whole header */
|
34 |
bufflen -= hdrend + 1;
|
34 |
bufflen -= hdrend + 1;
|
35 |
memmove(buff, buff + hdrend + 1, bufflen);
|
35 |
memmove(buff, buff + hdrend + 1, bufflen);
|
36 |
bytesleft = strtol(partial_hdr, NULL, 16);
|
36 |
st->bytesleft = strtol(st->partial_hdr, NULL, 16);
|
37 |
}
|
37 |
}
|
38 |
|
38 |
|
39 |
AGAIN:
|
39 |
AGAIN:
|
40 |
|
40 |
|
41 |
if (bufflen <= bytesleft) { /* bufflen <= bytesleft */
|
41 |
if (bufflen <= st->bytesleft) {
|
42 |
bytesleft -= bufflen;
|
42 |
st->bytesleft -= bufflen;
|
43 |
return(bufflen);
|
43 |
return(bufflen);
|
44 |
}
|
44 |
}
|
45 |
|
45 |
|
46 |
/* else bufflen > bytesleft */
|
46 |
/* else bufflen > bytesleft */
|
47 |
|
47 |
|
48 |
/* skip trailing \r\n after chunk */
|
48 |
/* skip trailing \r\n after chunk */
|
49 |
for (hdrstart = bytesleft; hdrstart < bufflen; hdrstart++) if ((buff[hdrstart] != '\r') && (buff[hdrstart] != '\n')) break;
|
49 |
for (hdrstart = st->bytesleft; hdrstart < bufflen; hdrstart++) if ((buff[hdrstart] != '\r') && (buff[hdrstart] != '\n')) break;
|
50 |
/* skip chunk size (look for its \n terminator) */
|
50 |
/* skip chunk size (look for its \n terminator) */
|
51 |
for (hdrend = hdrstart; (hdrend < bufflen) && (buff[hdrend] != '\n'); hdrend++);
|
51 |
for (hdrend = hdrstart; (hdrend < bufflen) && (buff[hdrend] != '\n'); hdrend++);
|
52 |
|
52 |
|
53 |
if (hdrend < bufflen) { /* full header found */
|
53 |
if (hdrend < bufflen) { /* full header found */
|
54 |
long newchunklen;
|
54 |
long newchunklen;
|
55 |
/* read the header length */
|
55 |
/* read the header length */
|
56 |
newchunklen = strtol((char *)buff + hdrstart, NULL, 16);
|
56 |
newchunklen = strtol((char *)buff + hdrstart, NULL, 16);
|
57 |
/* move data over header to get a contiguous block of data */
|
57 |
/* move data over header to get a contiguous block of data */
|
58 |
memmove(buff + bytesleft, buff + hdrend + 1, bufflen - (hdrend + 1));
|
58 |
memmove(buff + st->bytesleft, buff + hdrend + 1, bufflen - (hdrend + 1));
|
59 |
bufflen -= (hdrend + 1 - bytesleft);
|
59 |
bufflen -= (hdrend + 1 - st->bytesleft);
|
60 |
/* update bytesleft */
|
60 |
/* update bytesleft */
|
61 |
bytesleft += newchunklen;
|
61 |
st->bytesleft += newchunklen;
|
62 |
/* loop again */
|
62 |
/* loop again */
|
63 |
goto AGAIN;
|
63 |
goto AGAIN;
|
64 |
} else { /* partial header */
|
64 |
} else { /* partial header */
|
65 |
if ((bufflen - bytesleft) > 15) return(-1); /* error: chunk header appears to be longer than 15 characters */
|
65 |
if ((bufflen - st->bytesleft) > 15) return(-1); /* error: chunk header appears to be longer than 15 characters */
|
66 |
memset(partial_hdr, 0, sizeof(partial_hdr));
|
66 |
memset(st->partial_hdr, 0, sizeof(st->partial_hdr));
|
67 |
memcpy(partial_hdr, buff + bytesleft, bufflen - bytesleft);
|
67 |
memcpy(st->partial_hdr, buff + st->bytesleft, bufflen - st->bytesleft);
|
68 |
bufflen -= (bufflen - bytesleft);
|
68 |
bufflen -= (bufflen - st->bytesleft);
|
69 |
bytesleft = -1; /* "header in progress" */
|
69 |
st->bytesleft = -1; /* "header in progress" */
|
70 |
return(bufflen);
|
70 |
return(bufflen);
|
71 |
}
|
71 |
}
|
72 |
}
|
72 |
}
|