OSDN Git Service

fix detail I/F mistake.
[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 #ifdef BCHAN_CONFIG_DEBUG
34 # define DP(arg) printf arg
35 # define DP_ER(msg, err) printf("%s (%d/%x)\n", msg, err>>16, err)
36 #else
37 # define DP(arg) /**/
38 # define DP_ER(msg, err) /**/
39 #endif
40
41 #if 0
42 # define DP_STATE(state) printf("%s\n", state)
43 #else
44 # define DP_STATE(state) /**/
45 #endif
46
47 LOCAL W http_contentdecoderidentity_inputentitybody(http_contentdecoderidentity_t *decoder, UB *data, W data_len)
48 {
49         decoder->state = HTTP_CONTENTDECODERIDENTITY_STATE_DATA;
50         decoder->data = data;
51         decoder->data_len = data_len;
52         return 0;
53 }
54
55 LOCAL W http_contentdecoderidentity_inputendofdata(http_contentdecoderidentity_t *decoder)
56 {
57         decoder->state = HTTP_CONTENTDECODERIDENTITY_STATE_END;
58         return 0;
59 }
60
61 LOCAL W http_contentdecoderidentity_outputdata(http_contentdecoderidentity_t *decoder, http_contentdecoder_result **result, W *result_len, Bool *need_next)
62 {
63         switch (decoder->state) {
64         case HTTP_CONTENTDECODERIDENTITY_STATE_DATA:
65                 decoder->result.type = HTTP_CONTENTDECODER_RESULTTYPE_DATA;
66                 decoder->result.data = decoder->data;
67                 decoder->result.len = decoder->data_len;
68                 *result = &decoder->result;
69                 *result_len = 1;
70                 *need_next = True;
71                 break;
72         case HTTP_CONTENTDECODERIDENTITY_STATE_END:
73                 decoder->result.type = HTTP_CONTENTDECODER_RESULTTYPE_END;
74                 decoder->result.data = NULL;
75                 decoder->result.len = 0;
76                 *result = &decoder->result;
77                 *result_len = 1;
78                 *need_next = False;
79                 break;
80         }
81
82         return 0;
83 }
84
85 LOCAL W http_contentdecoderidentity_initialize(http_contentdecoderidentity_t *decoder)
86 {
87         decoder->state = HTTP_CONTENTDECODERIDENTITY_STATE_DATA;
88         decoder->data = NULL;
89         decoder->data_len = 0;
90         return 0;
91 }
92
93 LOCAL VOID http_contentdecoderidentity_finalize(http_contentdecoderidentity_t *decoder)
94 {
95 }
96
97 /**/
98
99 LOCAL W gzip_headerskip_inputchar(gzip_headerskip_t *gzip, UB ch, Bool *is_end)
100 {
101         *is_end = False;
102
103         switch (gzip->state) {
104         case GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_FIRST:
105                 if (ch != 0x1F) {
106                         return -1; /* TODO: format error */
107                 }
108                 gzip->state = GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_SECOND;
109                 break;
110         case GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_SECOND:
111                 if (ch != 0x8B) {
112                         return -1; /* TODO: format error */
113                 }
114                 gzip->state = GZIP_HEADERSKIP_STATE_METHOD;
115                 break;
116         case GZIP_HEADERSKIP_STATE_METHOD:
117                 if (ch != Z_DEFLATED) {
118                         return -1; /* TODO: format error */
119                 }
120                 gzip->state = GZIP_HEADERSKIP_STATE_FLAGS;
121                 break;
122         case GZIP_HEADERSKIP_STATE_FLAGS:
123                 gzip->flags = ch;
124                 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_UNUSED_FIELD;
125                 break;
126           case GZIP_HEADERSKIP_STATE_SKIP_UNUSED_FIELD:
127                 gzip->unused--;
128                 if (gzip->unused != 0) {
129                         break;
130                 }
131                 if (gzip->flags & 0x04) {
132                         gzip->state = GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_FIRST;
133                 } else if (gzip->flags & 0x08) {
134                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_NAME;
135                 } else if (gzip->flags & 0x10) {
136                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT;
137                 } else if (gzip->flags & 0x02) {
138                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
139                 } else {
140                         *is_end = True;
141                 }
142                 break;
143         case GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_FIRST:
144                 gzip->extra_len = (W)ch;
145                 gzip->state = GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_SECOND;
146                 break;
147         case GZIP_HEADERSKIP_STATE_EXTRA_FIELD_LEN_SECOND:
148                 gzip->extra_len += (W)ch << 8;
149                 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_EXTRA_FIELD;
150                 break;
151         case GZIP_HEADERSKIP_STATE_SKIP_EXTRA_FIELD:
152                 gzip->extra_len--;
153                 if (gzip->extra_len != 0) {
154                         break;
155                 }
156                 if (gzip->flags & 0x08) {
157                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_NAME;
158                 } else if (gzip->flags & 0x10) {
159                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT;
160                 } else if (gzip->flags & 0x02) {
161                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
162                 } else {
163                         *is_end = True;
164                 }
165                 break;
166         case GZIP_HEADERSKIP_STATE_SKIP_FILE_NAME:
167                 if (ch != '\0') {
168                         break;
169                 }
170                 if (gzip->flags & 0x10) {
171                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT;
172                 } else if (gzip->flags & 0x02) {
173                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
174                 } else {
175                         *is_end = True;
176                 }
177                 break;
178           case GZIP_HEADERSKIP_STATE_SKIP_FILE_COMMENT:
179                 if (ch != '\0') {
180                         break;
181                 }
182                 if (gzip->flags & 0x02) {
183                         gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST;
184                 } else {
185                         *is_end = True;
186                 }
187                 break;
188           case GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_FIRST:
189                 gzip->state = GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_SECOND;
190                 break;
191           case GZIP_HEADERSKIP_STATE_SKIP_HEADER_CRC_SECOND:
192                 *is_end = True;
193         }
194
195         return 0;
196 }
197
198 LOCAL VOID gzip_headerskip_initialize(gzip_headerskip_t *gzip)
199 {
200         gzip->state = GZIP_HEADERSKIP_STATE_MAGIC_NUMBER_FIRST;
201         gzip->flags = 0;
202         gzip->extra_len = 0;
203         gzip->unused = 6;
204 }
205
206 LOCAL VOID gzip_headerskip_finalize(gzip_headerskip_t *gzip)
207 {
208 }
209
210 /**/
211
212 LOCAL W http_contentdecodergzip_inputentitybody(http_contentdecodergzip_t *decoder, UB *data, W data_len)
213 {
214         W i, err;
215         Bool is_end;
216
217         switch (decoder->state) {
218         case HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER:
219                 DP_STATE("HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER");
220                 for (i = 0; i < data_len; i++) {
221                         err = gzip_headerskip_inputchar(&decoder->gzipheader, data[i], &is_end);
222                         if (err < 0) {
223                                 return err;
224                         }
225                         if (is_end != False) {
226                                 decoder->state = HTTP_CONTENTDECODERGZIP_STATE_DECODE;
227                                 decoder->z.next_in = data + i + 1;
228                                 decoder->z.avail_in = data_len - (i + 1);
229                                 break;
230                         }
231                 }
232                 break;
233         case HTTP_CONTENTDECODERGZIP_STATE_DECODE:
234                 DP_STATE("HTTP_CONTENTDECODERGZIP_STATE_DECODE");
235                 decoder->z.next_in = data;
236                 decoder->z.avail_in = data_len;
237                 break;
238         case HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA:
239                 DP_STATE("HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA");
240                 return -1; /* TODO */
241         }
242
243         return 0;
244 }
245
246 LOCAL W http_contentdecodergzip_inputendofdata(http_contentdecodergzip_t *decoder)
247 {
248         decoder->state = HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA;
249         return 0;
250 }
251
252 LOCAL W http_contentdecodergzip_outputdata(http_contentdecodergzip_t *decoder, http_contentdecoder_result **result, W *result_len, Bool *need_input)
253 {
254         W err;
255
256         switch (decoder->state) {
257         case HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER:
258                 *need_input = True;
259                 *result = NULL;
260                 *result_len = 0;
261                 break;
262         case HTTP_CONTENTDECODERGZIP_STATE_DECODE:
263                 if (decoder->z.avail_in == 0) {
264                         *need_input = True;
265                         *result = NULL;
266                         *result_len = 0;
267                         break;
268                 }
269                 *need_input = False;
270
271                 *result = decoder->result;
272
273                 err = inflate(&(decoder->z), Z_NO_FLUSH);
274                 if (err == Z_STREAM_END) {
275                         decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_DATA;
276                         decoder->result[0].data = decoder->buffer;
277                         decoder->result[0].len = HTTP_CONTENTDECODERGZIP_BUFLEN - decoder->z.avail_out;
278                         *result_len = 1;
279                         decoder->state = HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA;
280                         break;
281                 }
282                 if (err != Z_OK) {
283                         DP_ER("inflate error:", err);
284                         return -1;
285                 }
286                 if (decoder->z.avail_out == 0) {
287                         decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_DATA;
288                         decoder->result[0].data = decoder->buffer;
289                         decoder->result[0].len = HTTP_CONTENTDECODERGZIP_BUFLEN;
290                         *result_len = 1;
291                         decoder->z.next_out = decoder->buffer;
292                         decoder->z.avail_out = HTTP_CONTENTDECODERGZIP_BUFLEN;
293                         return 0;
294                 }
295
296                 *result_len = 0;
297
298                 break;
299         case HTTP_CONTENTDECODERGZIP_STATE_END_OF_DATA:
300                 decoder->result[0].type = HTTP_CONTENTDECODER_RESULTTYPE_END;
301                 decoder->result[0].data = NULL;
302                 decoder->result[0].len = 0;
303                 *result_len = 1;
304                 *need_input = False;
305                 break;
306         }
307
308         return 0;
309 }
310
311 LOCAL W http_contentdecodergzip_initialize(http_contentdecodergzip_t *decoder)
312 {
313         W err;
314
315         decoder->z.zalloc = Z_NULL;
316         decoder->z.zfree = Z_NULL;
317         decoder->z.opaque = Z_NULL;
318         decoder->z.next_in = Z_NULL;
319         decoder->z.avail_in = 0;
320         err = inflateInit2(&(decoder->z), -MAX_WBITS);
321         if (err != Z_OK) {
322                 DP_ER("inflateInit2 error:", err);
323                 return -1;
324         }
325         decoder->z.next_out = decoder->buffer;
326         decoder->z.avail_out = HTTP_CONTENTDECODERGZIP_BUFLEN;
327
328         gzip_headerskip_initialize(&decoder->gzipheader);
329         decoder->state = HTTP_CONTENTDECODERGZIP_STATE_SKIP_HEADER;
330
331         return 0;
332 }
333
334 LOCAL VOID http_contentdecodergzip_finalize(http_contentdecodergzip_t *decoder)
335 {
336         gzip_headerskip_finalize(&decoder->gzipheader);
337         inflateEnd(&(decoder->z));
338 }
339
340 /**/
341
342 EXPORT W http_contentdecoder_inputentitybody(http_contentdecoder_t *decoder, UB *data, W data_len)
343 {
344         switch (decoder->type) {
345         case HTTP_CONTENTCODING_VALUE_IDENTITY:
346                 return http_contentdecoderidentity_inputentitybody(&decoder->d.identity, data, data_len);
347         case HTTP_CONTENTCODING_VALUE_GZIP:
348                 return http_contentdecodergzip_inputentitybody(&decoder->d.gzip, data, data_len);
349         case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
350         case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
351         }
352         return -1;
353 }
354
355 EXPORT W http_contentdecoder_inputendofdata(http_contentdecoder_t *decoder)
356 {
357         switch (decoder->type) {
358         case HTTP_CONTENTCODING_VALUE_IDENTITY:
359                 return http_contentdecoderidentity_inputendofdata(&decoder->d.identity);
360         case HTTP_CONTENTCODING_VALUE_GZIP:
361                 return http_contentdecodergzip_inputendofdata(&decoder->d.gzip);
362         case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
363         case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
364         }
365         return -1;
366 }
367
368 EXPORT W http_contentdecoder_outputdata(http_contentdecoder_t *decoder, http_contentdecoder_result **result, W *result_len, Bool *need_input)
369 {
370         switch (decoder->type) {
371         case HTTP_CONTENTCODING_VALUE_IDENTITY:
372                 return http_contentdecoderidentity_outputdata(&decoder->d.identity, result, result_len, need_input);
373         case HTTP_CONTENTCODING_VALUE_GZIP:
374                 return http_contentdecodergzip_outputdata(&decoder->d.gzip, result, result_len, need_input);
375         case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
376         case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
377         }
378         return -1;
379 }
380
381 EXPORT W http_contentdecoder_initialize(http_contentdecoder_t *decoder, HTTP_CONTENTCODING_VALUE type)
382 {
383         decoder->type = type;
384         switch (type) {
385         case HTTP_CONTENTCODING_VALUE_IDENTITY:
386                 return http_contentdecoderidentity_initialize(&decoder->d.identity);
387         case HTTP_CONTENTCODING_VALUE_GZIP:
388                 return http_contentdecodergzip_initialize(&decoder->d.gzip);
389         case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
390         case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
391         }
392         return -1;
393 }
394
395 EXPORT VOID http_contentdecoder_finalize(http_contentdecoder_t *decoder)
396 {
397         switch (decoder->type) {
398         case HTTP_CONTENTCODING_VALUE_IDENTITY:
399                 http_contentdecoderidentity_finalize(&decoder->d.identity);
400                 break;
401         case HTTP_CONTENTCODING_VALUE_GZIP:
402                 http_contentdecodergzip_finalize(&decoder->d.gzip);
403                 break;
404         case HTTP_CONTENTCODING_VALUE_COMPRESS: /* unsupported yet */
405         case HTTP_CONTENTCODING_VALUE_DEFLATE: /* unsupported yet */
406         }
407 }