OSDN Git Service

implement http transfer-coded data decoder.
authorornse01 <ornse01@users.sourceforge.jp>
Wed, 4 Jan 2012 11:13:18 +0000 (11:13 +0000)
committerornse01 <ornse01@users.sourceforge.jp>
Wed, 4 Jan 2012 11:13:18 +0000 (11:13 +0000)
but not tested.

git-svn-id: http://svn.sourceforge.jp/svnroot/bchan/bchanf/trunk@324 20a0b8eb-f62a-4a12-8fe1-b598822500fb

src/http/http_transferdecoder.c
src/http/http_transferdecoder.h

index e69de29..444ede7 100644 (file)
@@ -0,0 +1,302 @@
+/*
+ * http_transferdecoder.c
+ *
+ * Copyright (c) 2012 project bchan
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ */
+
+#include "http_transferdecoder.h"
+
+#include       <basic.h>
+#include       <bstdio.h>
+#include       <bctype.h>
+
+#ifdef BCHAN_CONFIG_DEBUG
+# define DP(arg) printf arg
+# define DP_ER(msg, err) printf("%s (%d/%x)\n", msg, err>>16, err)
+#else
+# define DP(arg) /**/
+# define DP_ER(msg, err) /**/
+#endif
+
+LOCAL W http_transferdecoderidentity_inputentitybody(http_transferdecoderidentity_t *decoder, UB *data, W data_len, http_transferdecoder_result **result, W *result_len)
+{
+       *result = decoder->result;
+
+       if (decoder->pushed_len + data_len >= decoder->content_length) {
+               decoder->result[0].type = HTTP_TRANSFERDECODER_RESULTTYPE_DATA;
+               decoder->result[0].data = data;
+               decoder->result[0].len = decoder->content_length - decoder->pushed_len;
+               decoder->result[0].type = HTTP_TRANSFERDECODER_RESULTTYPE_END;
+               decoder->pushed_len = decoder->content_length;
+               *result_len = 2;
+               return decoder->result[0].len;
+       }
+
+       decoder->result[0].type = HTTP_TRANSFERDECODER_RESULTTYPE_DATA;
+       decoder->result[0].data = data;
+       decoder->result[0].len = data_len;
+       *result_len = 1;
+       return data_len;
+}
+
+LOCAL VOID http_transferdecoderidentity_initialize(http_transferdecoderidentity_t *decoder, W content_length)
+{
+       decoder->content_length = content_length;
+       decoder->pushed_len = 0;
+}
+
+LOCAL VOID http_transferdecoderidentity_finalize(http_transferdecoderidentity_t *decoder)
+{
+}
+
+typedef enum {
+       HTTP_CHUNKEDBODYPARSER_RESULT_DATA,
+       HTTP_CHUNKEDBODYPARSER_RESULT_OTHER,
+       HTTP_CHUNKEDBODYPARSER_RESULT_END,
+       HTTP_CHUNKEDBODYPARSER_RESULT_ERROR
+} HTTP_CHUNKEDBODYPARSER_RESULT;
+
+LOCAL HTTP_CHUNKEDBODYPARSER_RESULT http_chunkedbodyparser_inputchar(http_chunkedbodyparser_t *parser, UB ch)
+{
+       switch (parser->state) {
+       case HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_SIZE:
+               if (isdigit(ch)) {
+                       parser->chunk_size = parser->chunk_size*16 + 0 + ch - '0';
+                       break;
+               }
+               if (('a' <= ch)&&(ch <= 'h')) {
+                       parser->chunk_size = parser->chunk_size*16 + 0xa + ch - 'a';
+                       break;
+               }
+               if (('A' <= ch)&&(ch <= 'H')) {
+                       parser->chunk_size = parser->chunk_size*16 + 0xa + ch - 'A';
+                       break;
+               }
+               if (ch == ';') {
+                       if (parser->chunk_size == 0) {
+                               parser->state = HTTP_CHUNKEDBODYPARSER_STATE_LAST_CHUNK_EXTENTION;
+                       } else {
+                               parser->state = HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_EXTENTION;
+                       }
+                       break;
+               }
+               if (ch == '\r') {
+                       if (parser->chunk_size == 0) {
+                               parser->state = HTTP_CHUNKEDBODYPARSER_STATE_AFTER_CHUNK;
+                       } else {
+                               parser->state = HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_SIZE_CR;
+                       }
+                       break;
+               }
+               return HTTP_CHUNKEDBODYPARSER_RESULT_ERROR;
+       case HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_SIZE_CR:
+               if (ch == '\n') {
+                       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_DATA;
+                       parser->chunk_pushed_len = 0;
+                       break;
+               }
+               return HTTP_CHUNKEDBODYPARSER_RESULT_ERROR;
+       case HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_DATA:
+               parser->chunk_pushed_len++;
+               if (parser->chunk_size == parser->chunk_pushed_len) {
+                       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_SIZE;
+               }
+               return HTTP_CHUNKEDBODYPARSER_RESULT_DATA;
+       case HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_EXTENTION:
+               if (ch == '\r') {
+                       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_EXTENTION_CR;
+                       break;
+               }
+               break;
+       case HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_EXTENTION_CR:
+               if (ch == '\n') {
+                       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_DATA;
+                       parser->chunk_pushed_len = 0;
+                       break;
+               }
+               break;
+       case HTTP_CHUNKEDBODYPARSER_STATE_LAST_CHUNK_EXTENTION:
+               if (ch == '\r') {
+                       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_LAST_CHUNK_EXTENTION_CR;
+                       break;
+               }
+               break;
+       case HTTP_CHUNKEDBODYPARSER_STATE_LAST_CHUNK_EXTENTION_CR:
+               if (ch == '\n') {
+                       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_AFTER_CHUNK;
+                       parser->chunk_pushed_len = 0;
+                       break;
+               }
+               return HTTP_CHUNKEDBODYPARSER_RESULT_ERROR;
+       case HTTP_CHUNKEDBODYPARSER_STATE_AFTER_CHUNK:
+               if (ch == '\r') {
+                       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_AFTER_CHUNK_CR;
+               } else {
+                       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_TRAILER;
+               }
+               break;
+       case HTTP_CHUNKEDBODYPARSER_STATE_AFTER_CHUNK_CR:
+               if (ch == '\n') {
+                       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_END;
+                       return HTTP_CHUNKEDBODYPARSER_RESULT_END;
+                       break;
+               }
+               return HTTP_CHUNKEDBODYPARSER_RESULT_ERROR;
+       case HTTP_CHUNKEDBODYPARSER_STATE_TRAILER:
+               if (ch == '\r') {
+                       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_TRAILER_CR;
+               }
+               break;
+       case HTTP_CHUNKEDBODYPARSER_STATE_TRAILER_CR:
+               if (ch == '\n') {
+                       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_AFTER_CHUNK;
+                       parser->chunk_pushed_len = 0;
+                       break;
+               }
+               return HTTP_CHUNKEDBODYPARSER_RESULT_END;
+       case HTTP_CHUNKEDBODYPARSER_STATE_END:
+       }
+
+       return HTTP_CHUNKEDBODYPARSER_RESULT_OTHER;
+}
+
+LOCAL VOID http_chunkedbodyparser_initialize(http_chunkedbodyparser_t *parser)
+{
+       parser->state = HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_SIZE;
+       parser->chunk_size = 0;
+       parser->chunk_pushed_len = 0;
+}
+
+LOCAL VOID http_chunkedbodyparser_finalize(http_chunkedbodyparser_t *parser)
+{
+}
+
+LOCAL W http_transferdecoderchunked_inputentitybody(http_transferdecoderchunked_t *decoder, UB *data, W data_len, http_transferdecoder_result **result, W *result_len)
+{
+       W i_data, i_result;
+       enum {
+               START,
+               READING_DATA,
+               READING_OTHER,
+       } state = START;
+       HTTP_CHUNKEDBODYPARSER_RESULT result_parser;
+
+       i_result = 0;
+
+       for (i_data = 0; i_data < data_len; i_data++) {
+               result_parser = http_chunkedbodyparser_inputchar(&decoder->parser, data[i_data]);
+               if (result_parser == HTTP_CHUNKEDBODYPARSER_RESULT_ERROR) {
+                       return -1; /* TODO */
+               }
+
+               if (state == START) {
+                       if (result_parser == HTTP_CHUNKEDBODYPARSER_RESULT_DATA) {
+                               state = READING_DATA;
+                               decoder->result[i_result].type = HTTP_TRANSFERDECODER_RESULTTYPE_DATA;
+                               decoder->result[i_result].data = data;
+                       } else if (result_parser == HTTP_CHUNKEDBODYPARSER_RESULT_OTHER) {
+                               state = READING_OTHER;
+                       } else if (result_parser == HTTP_CHUNKEDBODYPARSER_RESULT_END) {
+                               decoder->result[i_result].type = HTTP_TRANSFERDECODER_RESULTTYPE_END;
+                               i_result++;
+                               break;
+                       }
+               } else if (state == READING_DATA) {
+                       if (result_parser == HTTP_CHUNKEDBODYPARSER_RESULT_OTHER) {
+                               state = READING_OTHER;
+                               decoder->result[i_result].len = data + i_data - decoder->result[i_result].data;
+                               i_result++;
+                               if (i_result >= HTTP_TRANSFERDECODER_CHUNKED_RESULTBUFLEN - 1) {
+                                       break;
+                               }
+                       } else if (result_parser == HTTP_CHUNKEDBODYPARSER_RESULT_END) {
+                               decoder->result[i_result].len = data + i_data - decoder->result[i_result].data;
+                               i_result++;
+                               decoder->result[i_result].type = HTTP_TRANSFERDECODER_RESULTTYPE_END;
+                               i_result++;
+                               break;
+                       }
+               } else if (state == READING_OTHER) {
+                       if (result_parser == HTTP_CHUNKEDBODYPARSER_RESULT_DATA) {
+                               state = READING_DATA;
+                               decoder->result[i_result].type = HTTP_TRANSFERDECODER_RESULTTYPE_DATA;
+                               decoder->result[i_result].data = data + i_data;
+                       } else if (result_parser == HTTP_CHUNKEDBODYPARSER_RESULT_END) {
+                               decoder->result[i_result].type = HTTP_TRANSFERDECODER_RESULTTYPE_END;
+                               i_result++;
+                               break;
+                       }
+               }
+       }
+
+       *result = decoder->result;
+       *result_len = i_result; 
+
+       return i_data;
+}
+
+LOCAL VOID http_transferdecoderchunked_initialize(http_transferdecoderchunked_t *decoder)
+{
+       http_chunkedbodyparser_initialize(&decoder->parser);
+}
+
+LOCAL VOID http_transferdecoderchunked_finalize(http_transferdecoderchunked_t *decoder)
+{
+       http_chunkedbodyparser_finalize(&decoder->parser);
+}
+
+EXPORT W http_transferdecoder_inputentitybody(http_transferdecoder_t *decoder, UB *data, W data_len, http_transferdecoder_result **result, W *result_len)
+{
+       switch (decoder->type) {
+       case HTTP_TRANSFERCODING_TYPE_IDENTITY:
+               return http_transferdecoderidentity_inputentitybody(&decoder->d.identity, data, data_len, result, result_len);
+       case HTTP_TRANSFERCODING_TYPE_CHUNKED:
+               return http_transferdecoderchunked_inputentitybody(&decoder->d.chunked, data, data_len, result, result_len);
+       }
+       return -1; /* TODO */
+}
+
+EXPORT VOID http_transferdecoder_initialize(http_transferdecoder_t *decoder, HTTP_TRANSFERCODING_TYPE type, W content_length)
+{
+       switch (type) {
+       case HTTP_TRANSFERCODING_TYPE_IDENTITY:
+               http_transferdecoderidentity_initialize(&decoder->d.identity, content_length);
+               break;
+       case HTTP_TRANSFERCODING_TYPE_CHUNKED:
+               http_transferdecoderchunked_initialize(&decoder->d.chunked);
+               break;
+       }
+       decoder->type = type;
+}
+
+EXPORT VOID http_transferdecoder_finalize(http_transferdecoder_t *decoder)
+{
+       switch (decoder->type) {
+       case HTTP_TRANSFERCODING_TYPE_IDENTITY:
+               http_transferdecoderidentity_finalize(&decoder->d.identity);
+               break;
+       case HTTP_TRANSFERCODING_TYPE_CHUNKED:
+               http_transferdecoderchunked_finalize(&decoder->d.chunked);
+               break;
+       }
+}
index e69de29..cf5b0df 100644 (file)
@@ -0,0 +1,114 @@
+/*
+ * http_transferdecoder.h
+ *
+ * Copyright (c) 2012 project bchan
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ */
+
+/* Vendor name: */
+/* Functionality name: http */
+/* Detail name: transferdecoder */
+
+#include    <basic.h>
+
+/* rfc2616 3.6 Transfer Codings */
+
+#ifndef __HTTP_TRANSFERDECODER_H__
+#define __HTTP_TRANSFERDECODER_H__
+
+/* Functionality name: http */
+/* Detail name: transfercoding */
+/* Data structure identifier: type */
+typedef enum {
+       HTTP_TRANSFERCODING_TYPE_IDENTITY,
+       HTTP_TRANSFERCODING_TYPE_CHUNKED,
+} HTTP_TRANSFERCODING_TYPE;
+
+/* Functionality name: http */
+/* Detail name: transferdecoder */
+/* Data structure identifier: result */
+struct http_transferdecoder_result_ {
+       enum {
+               HTTP_TRANSFERDECODER_RESULTTYPE_DATA,
+               HTTP_TRANSFERDECODER_RESULTTYPE_END,
+       } type;
+       UB *data;
+       W len;
+};
+typedef struct http_transferdecoder_result_ http_transferdecoder_result;
+
+/* Functionality name: http */
+/* Detail name: transferdecoderidentity */
+struct http_transferdecoderidentity_t_ {
+       http_transferdecoder_result result[2];
+       W content_length;
+       W pushed_len;
+};
+typedef struct http_transferdecoderidentity_t_ http_transferdecoderidentity_t;
+
+/* Functionality name: http */
+/* Detail name: chuhkedbodyparser */
+struct http_chunkedbodyparser_t_ {
+       enum {
+               HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_SIZE,
+               HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_SIZE_CR,
+               HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_DATA,
+               HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_EXTENTION,
+               HTTP_CHUNKEDBODYPARSER_STATE_CHUNK_EXTENTION_CR,
+               HTTP_CHUNKEDBODYPARSER_STATE_LAST_CHUNK_EXTENTION,
+               HTTP_CHUNKEDBODYPARSER_STATE_LAST_CHUNK_EXTENTION_CR,
+               HTTP_CHUNKEDBODYPARSER_STATE_AFTER_CHUNK,
+               HTTP_CHUNKEDBODYPARSER_STATE_AFTER_CHUNK_CR,
+               HTTP_CHUNKEDBODYPARSER_STATE_TRAILER,
+               HTTP_CHUNKEDBODYPARSER_STATE_TRAILER_CR,
+               HTTP_CHUNKEDBODYPARSER_STATE_END,
+       } state;
+       W chunk_size;
+       W chunk_pushed_len;
+};
+typedef struct http_chunkedbodyparser_t_ http_chunkedbodyparser_t;
+
+/* Functionality name: http */
+/* Detail name: transferdecoderchunked */
+#define HTTP_TRANSFERDECODER_CHUNKED_RESULTBUFLEN 4
+struct http_transferdecoderchunked_t_ {
+       http_transferdecoder_result result[HTTP_TRANSFERDECODER_CHUNKED_RESULTBUFLEN];
+       http_chunkedbodyparser_t parser;
+};
+typedef struct http_transferdecoderchunked_t_ http_transferdecoderchunked_t;
+
+/* Functionality name: http */
+/* Detail name: transferdecoder */
+struct http_transferdecoder_t_ {
+       HTTP_TRANSFERCODING_TYPE type;
+       union {
+               http_transferdecoderidentity_t identity;
+               http_transferdecoderchunked_t chunked;
+       } d;
+};
+typedef struct http_transferdecoder_t_ http_transferdecoder_t;
+
+IMPORT VOID http_transferdecoder_initialize(http_transferdecoder_t *decoder, HTTP_TRANSFERCODING_TYPE type, W content_length);
+IMPORT VOID http_transferdecoder_finalize(http_transferdecoder_t *decoder);
+IMPORT W http_transferdecoder_inputentitybody(http_transferdecoder_t *decoder, UB *data, W data_len, http_transferdecoder_result **result, W *result_len);
+
+#endif