Jun Furutani / libMiMic

Fork of libMiMic by Ryo Iizuka

Revision:
41:2389bd6b6f74
Child:
109:18f12ac01097
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/http/NyLPC_cHttpBasicBodyParser.c	Sun Jun 30 14:17:42 2013 +0000
@@ -0,0 +1,191 @@
+#include "NyLPC_cHttpBasicBodyParser.h"
+#include <ctype.h>
+
+void NyLPC_cHttpBasicBodyParser_initialize(NyLPC_TcHttpBasicBodyParser_t* i_inst,struct NyLPC_TcHttpBasicBodyParser_Handler* i_handler)
+{
+    i_inst->_handler=i_handler;
+    i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_NULL;
+}
+#define NyLPC_cHttpBasicBodyParser_finalize(i_inst)
+
+/**
+ * パーサの開始処理をします。
+ * 関数は、parseInit->parseChar[n回]->(parseStream)->parseFinishの順でコールします。
+ * parseChar、又はparseStreamでエラーが発生した場合は、後続の関数を呼び出すことは出来ません。
+ * parseCharでEOHに達した場合、parseCharまたはparseStreamを続けて呼ぶことは出来ません。
+ * parseFinishはparseCharまたはparseStreamでEOHに達した場合のみ呼び出すことが出来ます。
+ */
+void NyLPC_cHttpBasicBodyParser_parseInit(NyLPC_TcHttpBasicBodyParser_t* i_inst,const struct NyLPC_THttpBasicHeader* i_info)
+{
+    switch(i_info->transfer_encoding)
+    {
+    case NyLPC_THttpMessgeHeader_TransferEncoding_CHUNKED:
+        i_inst->_encode_type=NyLPC_THttpMessgeHeader_TransferEncoding_CHUNKED;
+        i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_CHUNK_HEADER_START;
+        i_inst->_data.chunked.recv_len=0;
+        break;
+    default:
+        i_inst->_encode_type=NyLPC_THttpMessgeHeader_TransferEncoding_NONE;
+        i_inst->_data.normal.content_length=i_info->content_length;
+        i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_BODY;
+        break;
+    }
+}
+
+/**
+ * パーサの処理を閉じます。
+ * @return
+ * パース処理が正常に終了したかの真偽値
+ */
+NyLPC_TBool NyLPC_cHttpBasicBodyParser_parseFinish(NyLPC_TcHttpBasicBodyParser_t* i_inst)
+{
+    NyLPC_TBool ret=(i_inst->_status==NyLPC_TcHttpBasicBodyParser_ST_EOB);
+    i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_NULL;
+    return ret;
+}
+#define HTTP_CR 0x0D
+#define HTTP_LF 0x0A
+#define HTTP_SP 0x20
+/**
+ * HTTPストリームをパースします。
+ * @return
+ * 処理した文字列の長さ。-1の場合エラーである。
+ * それ以外の場合ステータスをチェックすること。
+ * NyLPC_TcHttpBasicBodyParser_ST_ERROR
+ */
+NyLPC_TInt32 NyLPC_cHttpBasicBodyParser_parseChar(NyLPC_TcHttpBasicBodyParser_t* i_inst,const NyLPC_TChar* i_c,NyLPC_TInt32 i_size)
+{
+    NyLPC_TInt32 i;
+    NyLPC_TChar c;
+    switch(i_inst->_encode_type){
+    case NyLPC_THttpMessgeHeader_TransferEncoding_CHUNKED:
+        for(i=0;i<i_size;)
+        {
+            c=*(i_c+i);
+            //[:START:][:SP:][:EXT:][:BODY:][:END:]
+            switch(i_inst->_status)
+            {
+            case NyLPC_TcHttpBasicBodyParser_ST_CHUNK_BODY:
+                //OnRecv
+                if(!i_inst->_handler->bodyHandler(i_inst,c)){
+                    i_inst->_data.chunked.recv_len--;
+                    //中断
+                    if(i_inst->_data.chunked.recv_len==0){
+                        //content length分だけ読み取った
+                        i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_CHUNK_FOOTER;
+                    }
+                    return i+1;
+                }
+                i_inst->_data.chunked.recv_len--;
+                if(i_inst->_data.chunked.recv_len==0){
+                    //content length分だけ読み取った
+                    i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_CHUNK_FOOTER;
+                }
+                i++;//次の文字へ
+                break;
+            // HEX
+            case NyLPC_TcHttpBasicBodyParser_ST_CHUNK_HEADER_START:
+                if(isxdigit(c)){
+                    i_inst->_data.chunked.recv_len=i_inst->_data.chunked.recv_len*16+NyLPC_ctox(c);
+                    //一応最大チャンクサイズは決めておこうか。
+                    if(i_inst->_data.chunked.recv_len>0x0fffffff){
+                        NyLPC_OnErrorGoto(ERROR);
+                    }
+                    i++;//次の文字へ
+                }else if(c==HTTP_SP){
+                    i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_CHUNK_HEADER_SP;
+                    i++;//次の文字へ
+                }else if(c==HTTP_CR || c==HTTP_LF){
+                    i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_CHUNK_HEADER_EXT;
+                    //読取位置を変化させずにEXTへ
+                }else{
+                    NyLPC_OnErrorGoto(ERROR);
+                }
+                break;
+            case NyLPC_TcHttpBasicBodyParser_ST_CHUNK_HEADER_SP:
+                if(c==HTTP_SP){
+                    i++;//次の文字へ
+                }else{
+                    //ext
+                    i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_CHUNK_HEADER_EXT;
+                }
+                break;
+            case NyLPC_TcHttpBasicBodyParser_ST_CHUNK_HEADER_EXT:
+                //EXTの内容は読まない。
+                if(c==HTTP_LF){
+                    if(i_inst->_data.chunked.recv_len==0){
+                        //chunksize=0でCRLFを検出したらend-chunk
+                        i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_CHUNK_END;
+                    }else{
+                        //chunksize>0でCRLFを検出したらBODY検出
+                        i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_CHUNK_BODY;
+                    }
+                }else{
+                    //nothing to do
+                }
+                i++;//次の文字へ
+                break;
+            case NyLPC_TcHttpBasicBodyParser_ST_CHUNK_FOOTER:
+                //CRLF待ち
+                if(c==HTTP_CR){
+                    //無視
+                }else if(c==HTTP_LF){
+                    //確定
+                    i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_CHUNK_HEADER_START;
+                }else{
+                    NyLPC_OnErrorGoto(ERROR);
+                }
+                i++;
+                break;
+            case NyLPC_TcHttpBasicBodyParser_ST_CHUNK_END:
+                //CRLF待ち
+                if(c==HTTP_CR){
+                    //無視
+                }else if(c==HTTP_LF){
+                    //確定
+                    i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_EOB;
+                    return i+1;
+                }else{
+                    NyLPC_OnErrorGoto(ERROR);
+                }
+                i++;
+                break;
+            default:
+                NyLPC_OnErrorGoto(ERROR);
+            }
+        }
+        return i_size;
+        break;
+    case NyLPC_THttpMessgeHeader_TransferEncoding_NONE:
+        if(i_inst->_status!=NyLPC_TcHttpBasicBodyParser_ST_BODY){
+            NyLPC_OnErrorGoto(ERROR);
+        }
+        for(i=0;i<i_size;i++)
+        {
+            if(i_inst->_data.normal.content_length>0){
+                //OnRecv
+                if(!i_inst->_handler->bodyHandler(i_inst,*(i_c+i))){
+                    i++;
+                    i_inst->_data.normal.content_length--;
+                    break;//中断(遷移無し)
+                }
+                i_inst->_data.normal.content_length--;
+            }else{
+                //content-length==0;全て受信
+                break;
+            }
+        }
+        if(i_inst->_data.normal.content_length==0){
+            //content length分だけ読み取った
+            i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_EOB;
+            return i;
+        }
+        return i;
+    }
+ERROR:
+    //ERROR
+    i_inst->_status=NyLPC_TcHttpBasicBodyParser_ST_ERROR;
+    return -1;
+}
+
+