OSDN Git Service

change http_contentdecoder_t I/F.
[bbk/bchanf.git] / src / http / http_contentdecoder.c
1 /*
2  * http_contentdecoder.c
3  *
4  * Copyright (c) 2012 project bchan
5  *
6  * This software is provided 'as-is', without any express or implied
7  * warranty. In no event will the authors be held liable for any damages
8  * arising from the use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not
15  *    claim that you wrote the original software. If you use this software
16  *    in a product, an acknowledgment in the product documentation would be
17  *    appreciated but is not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  *    misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source
23  *    distribution.
24  *
25  */
26
27 #include "http_contentdecoder.h"
28
29 #include        <basic.h>
30 #include        <bstdio.h>
31 #include        <util/zlib.h>
32
33 #include    "http_typedef.h"
34
35 #ifdef BCHAN_CONFIG_DEBUG
36 # define DP(arg) printf arg
37 # define DP_ER(msg, err) printf("%s (%d/%x)\n", msg, err>>16, err)
38 #else
39 # define DP(arg) /**/
40 # define DP_ER(msg, err) /**/
41 #endif
42
43 #if 0
44 # define DP_STATE(state) printf("%s\n", state)
45 #else
46 # define DP_STATE(state) /**/
47 #endif
48
49 LOCAL W http_contentdecoderidentity_inputentitybody(http_contentdecoderidentity_t *decoder, UB *data, W data_len)
50 {
51         decoder->state = HTTP_CONTENTDECODERIDENTITY_STATE_DATA;
52         decoder->data = data;
53         decoder->data_len = data_len;
54         return 0;
55 }
56
57 LOCAL W http_contentdecoderidentity_inputendofdata(http_contentdecoderidentity_t *decoder)
58 {
59         decoder->state = HTTP_CONTENTDECODERIDENTITY_STATE_END;
60         return 0;
61 }
62
63 LOCAL W http_contentdecoderidentity_outputdata(http_contentdecoderidentity_t *decoder, http_contentdecoder_result **result, W *result_len)
64 {
65         switch (decoder->state) {
66         case HTTP_CONTENTDECODERIDENTITY_STATE_DATA:
67                 decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_DATA;
68                 decoder->result[0].data = decoder->data;
69                 decoder->result[0].len = decoder->data_len;
70                 decoder->result[1].type = HTTP_CONTENTDECODER_RESULTTYPE_NEED_INPUT;
71                 decoder->result[1].data = NULL;
72                 decoder->result[1].len = 0;
73                 *result = decoder->result;
74                 *result_len = 2;
75                 break;
76         case HTTP_CONTENTDECODERIDENTITY_STATE_END:
77                 decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_END;
78                 decoder->result[0].data = NULL;
79                 decoder->result[0].len = 0;
80                 *result = decoder->result;
81                 *result_len = 1;
82                 break;
83         }
84
85         return 0;
86 }
87
88 LOCAL W http_contentdecoderidentity_initialize(http_contentdecoderidentity_t *decoder)
89 {
90         decoder->state = HTTP_CONTENTDECODERIDENTITY_STATE_DATA;
91         decoder->data = NULL;
92         decoder->data_len = 0;
93         return 0;
94 }
95
96 LOCAL VOID http_contentdecoderidentity_finalize(http_contentdecoderidentity_t *decoder)
97 {
98 }
99
100 /**/
101
102 LOCAL W gzip_headerskip_inputchar(gzip_headerskip_t *gzip, UB ch, Bool *is_end)
103 {
104         *is_end = False;
105
106         switch (gzip->state) {
107         case GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_FIRST:
108                 if (ch != 0x1F) {
109                         return -1; /* TODO: format error */
110                 }
111                 gzip->state = GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_SECOND;
112                 break;
113         case GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_SECOND:
114                 if (ch != 0x8B) {
115                         return -1; /* TODO: format error */
116                 }
117                 gzip->state = GZIP_HEADERSKIP_STATE_METHOD;
118                 break;
119         case GZIP_HEADERSKIP_STATE_METHOD:
120                 if (ch != Z_DEFLATED) {
121                         return -1; /* TODO: format error */
122                 }
123                 gzip->state = GZIP_HEADERSKIP_STATE_FLAGS;
124                 break;
125         case GZIP_HEADERSKIP_STATE_FLAGS:
126                 gzip->flags = ch;
127                 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_UNUSED_FIELD;
128                 break;
129           case GZIP_HEADERSKIP_STATE_SKIP_UNUSED_FIELD:
130                 gzip->unused--;
131                 if (gzip->unused != 0) {
132                         break;
133                 }
134                 if (gzip->flags & 0x04) {
135                         gzip->state = GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_FIRST;
136                 } else if (gzip->flags & 0x08) {
137                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_NAME;
138                 } else if (gzip->flags & 0x10) {
139                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT;
140                 } else if (gzip->flags & 0x02) {
141                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
142                 } else {
143                         *is_end = True;
144                 }
145                 break;
146         case GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_FIRST:
147                 gzip->extra_len = (W)ch;
148                 gzip->state = GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_SECOND;
149                 break;
150         case GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_SECOND:
151                 gzip->extra_len += (W)ch << 8;
152                 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_EXTRA_FIELD;
153                 break;
154         case GZIP_HEADERSKIP_STATE_SKIP_EXTRA_FIELD:
155                 gzip->extra_len--;
156                 if (gzip->extra_len != 0) {
157                         break;
158                 }
159                 if (gzip->flags & 0x08) {
160                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_NAME;
161                 } else if (gzip->flags & 0x10) {
162                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT;
163                 } else if (gzip->flags & 0x02) {
164                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
165                 } else {
166                         *is_end = True;
167                 }
168                 break;
169         case GZIP_HEADERSKIP_STATE_SKIP_FILE_NAME:
170                 if (ch != '\0') {
171                         break;
172                 }
173                 if (gzip->flags & 0x10) {
174                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT;
175                 } else if (gzip->flags & 0x02) {
176                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
177                 } else {
178                         *is_end = True;
179                 }
180                 break;
181           case GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT:
182                 if (ch != '\0') {
183                         break;
184                 }
185                 if (gzip->flags & 0x02) {
186                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
187                 } else {
188                         *is_end = True;
189                 }
190                 break;
191           case GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST:
192                 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_SECOND;
193                 break;
194           case GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_SECOND:
195                 *is_end = True;
196         }
197
198         return 0;
199 }
200
201 LOCAL VOID gzip_headerskip_initialize(gzip_headerskip_t *gzip)
202 {
203         gzip->state = GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_FIRST;
204         gzip->flags = 0;
205         gzip->extra_len = 0;
206         gzip->unused = 6;
207 }
208
209 LOCAL VOID gzip_headerskip_finalize(gzip_headerskip_t *gzip)
210 {
211 }
212
213 /**/
214
215 LOCAL W http_contentdecodergzip_inputentitybody(http_contentdecodergzip_t *decoder, UB *data, W data_len)
216 {
217         W i, err;
218         Bool is_end;
219
220         switch (decoder->state) {
221         case HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER:
222                 DP_STATE("HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER");
223                 for (i = 0; i < data_len; i++) {
224                         err = gzip_headerskip_inputchar(&decoder->gzipheader, data[i], &is_end);
225                         if (err < 0) {
226                                 return err;
227                         }
228                         if (is_end != False) {
229                                 decoder->state = HTTP_CONTENTDECODERGZIP_STATE_DECODE;
230                                 decoder->z.next_in = data + i + 1;
231                                 decoder->z.avail_in = data_len - (i + 1);
232                                 break;
233                         }
234                 }
235                 break;
236         case HTTP_CONTENTDECODERGZIP_STATE_DECODE:
237                 DP_STATE("HTTP_CONTENTDECODERGZIP_STATE_DECODE");
238                 decoder->z.next_in = data;
239                 decoder->z.avail_in = data_len;
240                 break;
241         case HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA:
242                 DP_STATE("HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA");
243                 return -1; /* TODO */
244         }
245
246         return 0;
247 }
248
249 LOCAL W http_contentdecodergzip_inputendofdata(http_contentdecodergzip_t *decoder)
250 {
251         decoder->state = HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA;
252         return 0;
253 }
254
255 LOCAL W http_contentdecodergzip_outputdata(http_contentdecodergzip_t *decoder, http_contentdecoder_result **result, W *result_len)
256 {
257         W err;
258
259         switch (decoder->state) {
260         case HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER:
261                 decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_NEED_INPUT;
262                 decoder->result[0].data = NULL;
263                 decoder->result[0].len = 0;
264                 *result = decoder->result;
265                 *result_len = 1;
266                 break;
267         case HTTP_CONTENTDECODERGZIP_STATE_DECODE:
268                 if (decoder->z.avail_in == 0) {
269                         decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_NEED_INPUT;
270                         decoder->result[0].data = NULL;
271                         decoder->result[0].len = 0;
272                         *result = decoder->result;
273                         *result_len = 1;
274                         break;
275                 }
276
277                 *result = decoder->result;
278
279                 err = inflate(&(decoder->z), Z_NO_FLUSH);
280                 if (err == Z_STREAM_END) {
281                         decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_DATA;
282                         decoder->result[0].data = decoder->buffer;
283                         decoder->result[0].len = HTTP_CONTENTDECODERGZIP_BUFLEN - decoder->z.avail_out;
284                         *result_len = 1;
285                         decoder->state = HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA;
286                         break;
287                 }
288                 if (err != Z_OK) {
289                         DP_ER("inflate error:", err);
290                         return -1;
291                 }
292                 if (decoder->z.avail_out == 0) {
293                         decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_DATA;
294                         decoder->result[0].data = decoder->buffer;
295                         decoder->result[0].len = HTTP_CONTENTDECODERGZIP_BUFLEN;
296                         *result_len = 1;
297                         decoder->z.next_out = decoder->buffer;
298                         decoder->z.avail_out = HTTP_CONTENTDECODERGZIP_BUFLEN;
299                         return 0;
300                 }
301
302                 *result_len = 0;
303
304                 break;
305         case HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA:
306                 decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_END;
307                 decoder->result[0].data = NULL;
308                 decoder->result[0].len = 0;
309                 *result_len = 1;
310                 break;
311         }
312
313         return 0;
314 }
315
316 LOCAL W http_contentdecodergzip_initialize(http_contentdecodergzip_t *decoder)
317 {
318         W err;
319
320         decoder->z.zalloc = Z_NULL;
321         decoder->z.zfree = Z_NULL;
322         decoder->z.opaque = Z_NULL;
323         decoder->z.next_in = Z_NULL;
324         decoder->z.avail_in = 0;
325         err = inflateInit2(&(decoder->z), -MAX_WBITS);
326         if (err != Z_OK) {
327                 DP_ER("inflateInit2 error:", err);
328                 return -1;
329         }
330         decoder->z.next_out = decoder->buffer;
331         decoder->z.avail_out = HTTP_CONTENTDECODERGZIP_BUFLEN;
332
333         gzip_headerskip_initialize(&decoder->gzipheader);
334         decoder->state = HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER;
335
336         return 0;
337 }
338
339 LOCAL VOID http_contentdecodergzip_finalize(http_contentdecodergzip_t *decoder)
340 {
341         gzip_headerskip_finalize(&decoder->gzipheader);
342         inflateEnd(&(decoder->z));
343 }
344
345 /**/
346
347 EXPORT W http_contentdecoder_inputentitybody(http_contentdecoder_t *decoder, UB *data, W data_len)
348 {
349         switch (decoder->type) {
350         case HTTP_CONTENTCODING_VALUE_IDENTITY:
351                 return http_contentdecoderidentity_inputentitybody(&decoder->d.identity, data, data_len);
352         case HTTP_CONTENTCODING_VALUE_GZIP:
353                 return http_contentdecodergzip_inputentitybody(&decoder->d.gzip, data, data_len);
354         case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
355         case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
356         }
357         return -1;
358 }
359
360 EXPORT W http_contentdecoder_inputendofdata(http_contentdecoder_t *decoder)
361 {
362         switch (decoder->type) {
363         case HTTP_CONTENTCODING_VALUE_IDENTITY:
364                 return http_contentdecoderidentity_inputendofdata(&decoder->d.identity);
365         case HTTP_CONTENTCODING_VALUE_GZIP:
366                 return http_contentdecodergzip_inputendofdata(&decoder->d.gzip);
367         case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
368         case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
369         }
370         return -1;
371 }
372
373 EXPORT W http_contentdecoder_outputdata(http_contentdecoder_t *decoder, http_contentdecoder_result **result, W *result_len)
374 {
375         switch (decoder->type) {
376         case HTTP_CONTENTCODING_VALUE_IDENTITY:
377                 return http_contentdecoderidentity_outputdata(&decoder->d.identity, result, result_len);
378         case HTTP_CONTENTCODING_VALUE_GZIP:
379                 return http_contentdecodergzip_outputdata(&decoder->d.gzip, result, result_len);
380         case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
381         case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
382         }
383         return -1;
384 }
385
386 EXPORT W http_contentdecoder_initialize(http_contentdecoder_t *decoder, HTTP_CONTENTCODING_VALUE type)
387 {
388         decoder->type = type;
389         switch (type) {
390         case HTTP_CONTENTCODING_VALUE_IDENTITY:
391                 return http_contentdecoderidentity_initialize(&decoder->d.identity);
392         case HTTP_CONTENTCODING_VALUE_GZIP:
393                 return http_contentdecodergzip_initialize(&decoder->d.gzip);
394         case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
395         case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
396         }
397         return -1;
398 }
399
400 EXPORT VOID http_contentdecoder_finalize(http_contentdecoder_t *decoder)
401 {
402         switch (decoder->type) {
403         case HTTP_CONTENTCODING_VALUE_IDENTITY:
404                 http_contentdecoderidentity_finalize(&decoder->d.identity);
405                 break;
406         case HTTP_CONTENTCODING_VALUE_GZIP:
407                 http_contentdecodergzip_finalize(&decoder->d.gzip);
408                 break;
409         case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
410         case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
411         }
412 }