1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4
5 #include "dechunk.h"
6 #include <string.h>
7 #include <stdlib.h>
8
9 #define CHUNK_INIT() \
10 do { \
11 g_is_chunkbegin = 0; \
12 g_chunk_len = 0; \
13 g_chunk_read = 0; \
14 } while (0)
15
16 #define DC_MIN(x, y) ((x) > (y) ? (y) : (x))
17
18 static char *g_buff_out = NULL;
19 static char *g_buff_pt = NULL;
20
21 static size_t g_buff_outlen = 0;
22 static size_t g_chunk_len = 0;
23 static size_t g_chunk_read = 0;
24
25 static int g_is_running = 0;
26 static int g_is_first = 1;
27 static int g_is_chunkbegin = 0;
28
memstr(void * src,size_t src_len,char * sub)29 void *memstr(void *src, size_t src_len, char *sub)
30 {
31 if (NULL == src || NULL == sub || src_len < strlen(sub))
32 return NULL;
33
34 char *p = src;
35 char *q = sub;
36 size_t indx = src_len;
37 size_t sub_len = strlen(sub);
38
39 while (indx > 0) {
40 int i = 0;
41
42 while (i < sub_len) {
43 char cp = *(p + i);
44 char cq = *(q + i);
45 // case ignore
46 if (cq >= 'A' && cq <= 'Z')
47 cq |= 0x20;
48
49 if (cp >= 'A' && cp <= 'Z')
50 cp |= 0x20;
51
52 if (cq != cp)
53 break;
54
55 i++;
56 }
57
58 if (i == sub_len)
59 return p;
60
61 p++;
62 indx--;
63 }
64
65 return NULL;
66 }
67
dechunk_init()68 int dechunk_init()
69 {
70 if (g_is_running)
71 return DCE_ISRUNNING;
72
73 g_buff_out = NULL;
74 g_buff_pt = NULL;
75
76 g_buff_outlen = 0;
77 g_chunk_len = 0;
78 g_chunk_read = 0;
79
80 g_is_running = 1;
81 g_is_first = 1;
82 g_is_chunkbegin = 0;
83
84 return DCE_OK;
85 }
86
dechunk(void * input,size_t inlen)87 int dechunk(void *input, size_t inlen)
88 {
89 if (!g_is_running)
90 return DCE_LOCK;
91
92 if (NULL == input || inlen == 0)
93 return DCE_ARGUMENT;
94
95 void *data_start = input;
96 size_t data_len = inlen;
97
98 if (g_is_first) {
99 data_start = memstr(data_start, data_len, "\r\n\r\n");
100 if (NULL == data_start)
101 return DCE_FORMAT;
102
103 data_start += 4;
104 data_len -= (data_start - input);
105
106 g_is_first = 0;
107 }
108
109 if (!g_is_chunkbegin) {
110 char *stmp = data_start;
111 int itmp = 0;
112
113 sscanf(stmp, "%x", &itmp);
114 // exclude the terminate "\r\n"
115 itmp = (itmp > 0 ? itmp - 2 : itmp);
116 data_start = memstr(stmp, data_len, "\r\n");
117 data_start += 2; // strlen("\r\n")
118
119 data_len -= (data_start - (void *)stmp);
120 g_chunk_len = itmp;
121 g_buff_outlen += g_chunk_len;
122 g_is_chunkbegin = 1;
123 g_chunk_read = 0;
124
125 if (g_chunk_len > 0 && 0 != g_buff_outlen) {
126 if (NULL == g_buff_out) {
127 g_buff_out = (char *)malloc(g_buff_outlen);
128 g_buff_pt = g_buff_out;
129 } else {
130 g_buff_out = realloc(g_buff_out, g_buff_outlen);
131 }
132
133 if (NULL == g_buff_out)
134 return DCE_MEM;
135
136 }
137 }
138
139 if (g_chunk_read < g_chunk_len) {
140 size_t cpsize = DC_MIN(g_chunk_len - g_chunk_read, data_len);
141 memcpy(g_buff_pt, data_start, cpsize);
142
143 g_buff_pt += cpsize;
144 g_chunk_read += cpsize;
145 data_len -= (cpsize + 2);
146 data_start += (cpsize + 2);
147
148 if (g_chunk_read >= g_chunk_len) {
149 CHUNK_INIT();
150 if (data_len > 0)
151 return dechunk(data_start, data_len);
152
153 }
154 } else {
155 CHUNK_INIT();
156 }
157
158 return DCE_OK;
159 }
160
dechunk_free()161 int dechunk_free()
162 {
163 free(g_buff_out);
164
165 g_buff_out = NULL;
166 g_buff_pt = NULL;
167
168 g_buff_outlen = 0;
169 g_chunk_len = 0;
170 g_chunk_read = 0;
171
172 g_is_running = 0;
173 g_is_first = 1;
174 g_is_chunkbegin = 0;
175
176 return DCE_OK;
177 }
178
dechunk_getbuff(void ** buff,size_t * buf_size)179 int dechunk_getbuff(void **buff, size_t *buf_size)
180 {
181 *buff = g_buff_out;
182 *buf_size = g_buff_outlen;
183
184 return DCE_OK;
185 }
186