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