+++ /dev/null
-/*********************************************************************************\r
- * PROJECT: MiMic\r
- * --------------------------------------------------------------------------------\r
- *\r
- * This file is part of MiMic\r
- * Copyright (C)2011 Ryo Iizuka\r
- *\r
- * MiMic is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU Lesser General Public License as published\r
- * by the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- * For further information please contact.\r
- * http://nyatla.jp/\r
- * <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>\r
- *\r
- *********************************************************************************/\r
-#include "cRemoteMcuRequestParser.h"\r
-\r
-\r
-#define ST_PARSE_PATH 1\r
-#define ST_PARSE_QUERY_NAME 2\r
-#define ST_PARSE_QUERY_VALUE 3 //Query読み出し中\r
-#define ST_PARSE_QUERY_VALUE_BC 4 //BC読み出し中\r
-#define ST_PARSE_QUERY_VALUE_DB 5\r
-\r
-\r
-/**\r
- * IDテーブル\r
- */\r
-struct TTextIdTbl{\r
- const char* n;\r
- NyLPC_TUInt8 id;\r
-};\r
-const struct TTextIdTbl TRemoteMcuRequest_content_id_table[]=\r
-{\r
- {"/",TRemoteMcuRequest_CONTENT_ID_INDEX},\r
- {"/setup.api",TRemoteMcuRequest_CONTENT_ID_SETUP},\r
- {"/mvm.api",TRemoteMcuRequest_CONTENT_ID_MIMICBC},\r
- {"/status.api",TRemoteMcuRequest_CONTENT_ID_STATUS},\r
- {"/mimic.css",TRemoteMcuRequest_CONTENT_ID_CSS},\r
- {"/mimiclogo.png",TRemoteMcuRequest_CONTENT_ID_LOGO},\r
- {NULL,TRemoteMcuRequest_CONTENT_ID_UNKNOWN}\r
-};\r
-const struct TTextIdTbl TRemoteMcuRequest_qname_id_table[]=\r
-{\r
- {"v",TRemoteMcuRequest_QNAME_ID_V},\r
- {"p",TRemoteMcuRequest_QNAME_ID_P},\r
- {"c",TRemoteMcuRequest_QNAME_ID_C},\r
- {"bc",TRemoteMcuRequest_QNAME_ID_BC},\r
- {NULL,TRemoteMcuRequest_CONTENT_ID_UNKNOWN}\r
-};\r
-\r
-\r
-static NyLPC_TBool updateQueryValue(TRemoteMcuRequest_CONTENT_ID i_content_id,TRemoteMcuRequest_QNAME_ID i_qid,const NyLPC_TcStr_t* i_qval,struct TRemoteMcuRequest* o_out);\r
-static void initQueryValue(TRemoteMcuRequest_CONTENT_ID i_content_id,struct TRemoteMcuRequest* o_out);\r
-\r
-\r
-\r
-static NyLPC_TBool message_handler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,const NyLPC_TChar* i_name,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)\r
-{\r
- (void)i_inst;\r
- (void)i_name;\r
- (void)i_c;\r
- (void)o_out;\r
- return NyLPC_TBool_TRUE;\r
-}\r
-\r
-\r
-NyLPC_TUInt8 TTextIdTbl_getMatchId(const NyLPC_TcStr_t* i_str,const struct TTextIdTbl i_tbl[])\r
-{\r
- int i;\r
- for(i=0;i_tbl[i].n!=NULL;i++){\r
- if(NyLPC_cStr_isEqual(i_str,i_tbl[i].n)){\r
- break;\r
- }\r
- }\r
- return i_tbl[i].id;\r
-}\r
-\r
-\r
-\r
-/**\r
- * RESTパーサ。\r
- * 構文エラーの場合は、FALSEを返します。\r
- * TRUEの場合は、返却したデータの構成をチェックしてください。\r
- */\r
-static NyLPC_TBool urlHandler(NyLPC_TcHttpBasicHeaderParser_t* i_inst,NyLPC_TChar i_c,struct NyLPC_THttpBasicHeader* o_out)\r
-{\r
- NyLPC_TUInt16 ol;\r
- TcRemoteMcuRequestParser_t* inst=(TcRemoteMcuRequestParser_t*)i_inst;\r
- struct TRemoteMcuRequest* out=(struct TRemoteMcuRequest*)o_out;\r
- switch(inst->_astate){\r
- case ST_PARSE_PATH:\r
- switch(i_c){\r
- case '\0':\r
- case '?':\r
- out->_content_id=TTextIdTbl_getMatchId(&(inst->_tstr),TRemoteMcuRequest_content_id_table);\r
- //未知のパス文字列なら、PATH部分を保存\r
- if(out->_content_id==TRemoteMcuRequest_CONTENT_ID_UNKNOWN){\r
- strcpy(out->content.unknown.path,NyLPC_cStr_str(&(inst->_tstr)));\r
- }\r
- initQueryValue(out->_content_id,out);//初期化\r
- NyLPC_cStr_clear(&(inst->_tstr));\r
- inst->_astate=ST_PARSE_QUERY_NAME;//クエリ名解析へ\r
- return NyLPC_TBool_TRUE;\r
- default:\r
- break;\r
- }\r
- break;\r
- case ST_PARSE_QUERY_NAME:\r
- switch(i_c){\r
- case '\0':\r
- case '&':\r
- case '=':\r
- //Query確定。\r
- inst->_content_qery_name_id=TTextIdTbl_getMatchId(&(inst->_tstr),TRemoteMcuRequest_qname_id_table);\r
- NyLPC_cStr_clear(&(inst->_tstr));\r
- if(i_c=='='){\r
- //クエリ値がある場合\r
- if(inst->_content_qery_name_id==TRemoteMcuRequest_QNAME_ID_BC && out->_content_id==TRemoteMcuRequest_CONTENT_ID_MIMICBC){\r
- inst->_astate=ST_PARSE_QUERY_VALUE_BC;//MIMICBCのBCパラメータの場合\r
- //binary出力バッファのセットアップ\r
- NyLPC_TUInt32ArrayPtr_setBuf(&(inst->bin_ptr),out->content.mvm.vm_instruction.bc_buf,TRemoteMcuRequest_SIZE_OF_IBUF);\r
- } else if(inst->_content_qery_name_id==TRemoteMcuRequest_QNAME_ID_P && out->_content_id==TRemoteMcuRequest_CONTENT_ID_SETUP){\r
- inst->_astate=ST_PARSE_QUERY_VALUE_DB;//MIMICBCのDBパラメータパーサを借用。\r
- NyLPC_TUInt32ArrayPtr_setBuf(&(inst->bin_ptr),out->content.setup.param_buf,TRemoteMcuRequest_SIZE_OF_SETUP_PARAM);\r
- }else{\r
- inst->_astate=ST_PARSE_QUERY_VALUE;//それ以外の場合\r
- }\r
- }else{\r
- if(!updateQueryValue(out->_content_id,inst->_content_qery_name_id,NULL,out)){\r
- //ERROR\r
- NyLPC_OnErrorGoto(ERROR);\r
- }\r
- }\r
- return NyLPC_TBool_TRUE;\r
- default:\r
- break;\r
- }\r
- break;\r
- case ST_PARSE_QUERY_VALUE:\r
- switch(i_c){\r
- case '&':\r
- case '\0':\r
- //クエリ値確定。状態を更新する。\r
- if(!updateQueryValue(out->_content_id,inst->_content_qery_name_id,&(inst->_tstr),out)){\r
- //ERROR\r
- NyLPC_OnErrorGoto(ERROR);\r
- }\r
- NyLPC_cStr_clear(&(inst->_tstr));\r
- inst->_astate=ST_PARSE_QUERY_NAME;//クエリ名解析へ\r
- return NyLPC_TBool_TRUE;\r
- default:\r
- break;\r
- }\r
- break;\r
- case ST_PARSE_QUERY_VALUE_DB:\r
- NyLPC_Assert(\r
- (TRemoteMcuRequest_CONTENT_ID_MIMICBC==out->_content_id)||\r
- (TRemoteMcuRequest_CONTENT_ID_SETUP==out->_content_id));\r
- switch(i_c){\r
- case '&':\r
- case '\0':\r
- //区切りのいいところで終わってる?\r
- if(NyLPC_cMiMicDbCompiler_hasFragment(&(inst->_dbcmp))){\r
- //ERROR\r
- NyLPC_OnErrorGoto(ERROR);\r
- }\r
- //データの長さを計算\r
- switch(out->_content_id){\r
- case TRemoteMcuRequest_CONTENT_ID_MIMICBC:\r
- out->content.mvm.vm_instruction.db_len=((NyLPC_TUInt8*)(inst->bin_ptr.ptr)-(NyLPC_TUInt8*)(out->content.mvm.vm_instruction.db_part))/sizeof(NyLPC_TUInt32);\r
- break;\r
- case TRemoteMcuRequest_CONTENT_ID_SETUP:\r
- out->content.setup.param_len=TRemoteMcuRequest_SIZE_OF_SETUP_PARAM-inst->bin_ptr.len;\r
- break;\r
- default:\r
- NyLPC_Abort();\r
- }\r
- //終端しているなら、次のクエリへ\r
- inst->_astate=ST_PARSE_QUERY_NAME;\r
- break;\r
- default:\r
- switch(NyLPC_cMiMicDbCompiler_compileFragment2(&(inst->_dbcmp),i_c,inst->bin_ptr.ptr))\r
- {\r
- case NyLPC_TcMiMicDbCompiler_RET_CONTINUE:\r
- break;\r
- case NyLPC_TcMiMicDbCompiler_RET_OK:\r
- //\r
- if(!NyLPC_TUInt32ArrayPtr_seek(&(inst->bin_ptr),1)){\r
- //ERROR\r
- NyLPC_OnErrorGoto(ERROR);\r
- }\r
- break;\r
- case NyLPC_TcMiMicDbCompiler_RET_ERROR:\r
- default:\r
- //ERROR\r
- NyLPC_OnErrorGoto(ERROR);\r
- }\r
- }\r
- return NyLPC_TBool_TRUE;\r
- case ST_PARSE_QUERY_VALUE_BC:\r
- //このケースはTRemoteMcuRequest_CONTENT_ID_MIMICBC==out->_content_idの時だけ使える。\r
- NyLPC_Assert(TRemoteMcuRequest_CONTENT_ID_MIMICBC==out->_content_id);\r
- switch(i_c){\r
- case '&':\r
- case '\0':\r
- //突然終わるのはダメです。\r
- //ERROR\r
- NyLPC_OnErrorGoto(ERROR);\r
- default:\r
- //コンパイル\r
- switch(NyLPC_cMiMicBcCompiler_compileFragment2(&(inst->_txtcmp),i_c,&(inst->bin_ptr),&ol))\r
- {\r
- case NyLPC_TcMiMicTxtCompiler_RET_OK:\r
- //命令確定。\r
- break;\r
- case NyLPC_TcMiMicTxtCompiler_RET_OK_END:\r
- //命令終端検出->モード切替\r
- out->content.mvm.vm_instruction.txt_len=TRemoteMcuRequest_SIZE_OF_IBUF-inst->bin_ptr.len+ol;\r
- out->content.mvm.vm_instruction.db_part=inst->bin_ptr.ptr;\r
- inst->_astate=ST_PARSE_QUERY_VALUE_DB;\r
- break;\r
- case NyLPC_TcMiMicTxtCompiler_RET_CONTINUE:\r
- //何もしない\r
- break;\r
- case NyLPC_TcMiMicTxtCompiler_RET_NG:\r
- default:\r
- //ERROR\r
- NyLPC_OnErrorGoto(ERROR);\r
- }\r
- break;\r
- }\r
- return NyLPC_TBool_TRUE;\r
- }\r
- //パースしているフラグメントの追記\r
- if(!NyLPC_cStr_put(&(inst->_tstr),i_c)){\r
- //ERROR\r
- NyLPC_OnErrorGoto(ERROR);\r
- }\r
- return NyLPC_TBool_TRUE;\r
-ERROR:\r
- return NyLPC_TBool_FALSE;\r
-}\r
-/**\r
- * デフォルトハンドラ\r
- */\r
-static const struct NyLPC_TcHttpBasicHeaderParser_Handler _handler=\r
-{\r
- message_handler,\r
- urlHandler\r
-};\r
-\r
-\r
-\r
-void cRemoteMcuRequestParser_initialize(TcRemoteMcuRequestParser_t* i_inst)\r
-{\r
- NyLPC_cHttpBasicHeaderParser_initialize(&(i_inst->super),&_handler);\r
-\r
- NyLPC_cStr_initialize(&(i_inst->_tstr),i_inst->_tstr_buf,16);\r
- NyLPC_cMiMicBcCompiler_initialize(&(i_inst->_txtcmp));\r
- NyLPC_cMiMicDbCompiler_initialize(&(i_inst->_dbcmp));\r
-}\r
-void cRemoteMcuRequestParser_finalize(TcRemoteMcuRequestParser_t* i_inst)\r
-{\r
- (void)i_inst;\r
- NyLPC_cHttpBasicHeaderParser_finalize(&(i_inst->super));\r
- NyLPC_cStr_finalize(&(i_inst->_tstr));\r
- NyLPC_cMiMicBcCompiler_finalize(&(i_inst->_txtcmp));\r
- NyLPC_cMiMicDbCompiler_finalize(&(i_inst->_dbcmp));\r
-}\r
-\r
-\r
-NyLPC_TUInt16 cRemoteMcuRequestParser_parse(TcRemoteMcuRequestParser_t* i_inst,NyLPC_TcHttpStream_t* i_stream,struct TRemoteMcuRequest* o_out)\r
-{\r
- TcRemoteMcuRequestParser_t* inst=(TcRemoteMcuRequestParser_t*)i_inst;\r
- //状態の初期化\r
- inst->_astate=ST_PARSE_PATH;\r
-\r
- //パースに失敗した。\r
- if(!NyLPC_cHttpBasicHeaderParser_parse(&(i_inst->super),i_stream,&(o_out->super)))\r
- {\r
- //エラーした。\r
- return 400;\r
- }\r
- NyLPC_cStr_clear(&(inst->_tstr));\r
-\r
- //HTTPリクエストではない。\r
- if(o_out->super.type!=NyLPC_THttpHeaderType_REQUEST){\r
- //エラーした。\r
- return 400;\r
- }\r
- //メソッドの制限\r
- if(o_out->super.startline.req.method!=NyLPC_THttpMethodType_GET){\r
- return 405;\r
- }\r
- //パースの整合性をテスト。\r
- switch(o_out->_content_id)\r
- {\r
- case TRemoteMcuRequest_CONTENT_ID_SETUP:\r
- //とりあえず7フラグメントあればOK\r
- switch(o_out->content.setup.cval){\r
- case TRemoteMcuRequest_QVAL_C_UPDATE:\r
- if(o_out->content.setup.param_len!=7){\r
- return 400;\r
- }\r
- break;\r
- default:\r
- break;\r
- }\r
- break;\r
- case TRemoteMcuRequest_CONTENT_ID_INDEX:\r
- case TRemoteMcuRequest_CONTENT_ID_UNKNOWN:\r
- //整合テスト無し\r
- break;\r
- case TRemoteMcuRequest_CONTENT_ID_MIMICBC:\r
- //バージョンは想定内?\r
- if(o_out->content.mvm.v==TRemoteMcuRequest_QVAL_VERSION_UNKNOWN){\r
- //エラー。バージョンミスマッチ\r
- return 406;\r
- }\r
- //TXT,BCの受信が出来ている?\r
- if(o_out->content.mvm.vm_instruction.db_part==NULL)\r
- {\r
- //ERROR\r
- return 400;\r
- }\r
- //命令長とストリーム長は計算済み\r
- break;\r
- default:\r
- NyLPC_Warning();\r
- break;\r
- }\r
- return 200;\r
-}\r
-static void initQueryValue(TRemoteMcuRequest_CONTENT_ID i_content_id,struct TRemoteMcuRequest* o_out)\r
-{\r
- switch(i_content_id){\r
- case TRemoteMcuRequest_CONTENT_ID_SETUP:\r
- o_out->content.setup.param_len=0;\r
- o_out->content.setup.cval=TRemoteMcuRequest_QVAL_C_UNKNOWN;\r
- break;\r
- case TRemoteMcuRequest_CONTENT_ID_MIMICBC:\r
- o_out->content.mvm.v=TRemoteMcuRequest_QVAL_VERSION_UNKNOWN;\r
- o_out->content.mvm.o=TRemoteMcuRequest_QVAL_O_JSON;\r
- o_out->content.mvm.vm_instruction.db_part=NULL;\r
- o_out->content.mvm.vm_instruction.db_len=0;\r
- o_out->content.mvm.vm_instruction.txt_len=0;\r
- break;\r
- case TRemoteMcuRequest_CONTENT_ID_INDEX:\r
- break;\r
- case TRemoteMcuRequest_CONTENT_ID_UNKNOWN:\r
- //やることなす\r
- break;\r
- default:\r
- //ウェーイ\r
- break;\r
- }\r
- return;\r
-\r
-}\r
-\r
-static NyLPC_TBool updateQueryValue(TRemoteMcuRequest_CONTENT_ID i_content_id,TRemoteMcuRequest_QNAME_ID i_qid,const NyLPC_TcStr_t* i_qval,struct TRemoteMcuRequest* o_out)\r
-{\r
- switch(i_content_id){\r
- case TRemoteMcuRequest_CONTENT_ID_SETUP:\r
- switch(i_qid){\r
- case TRemoteMcuRequest_QNAME_ID_C:\r
- if(i_qval!=NULL){\r
- if(NyLPC_cStr_isEqual(i_qval,"get")){\r
- o_out->content.setup.cval=TRemoteMcuRequest_QVAL_C_GET;\r
- }else if(NyLPC_cStr_isEqual(i_qval,"update")){\r
- o_out->content.setup.cval=TRemoteMcuRequest_QVAL_C_UPDATE;\r
- }\r
- }\r
- break;\r
- default:\r
- //知らない子は無視\r
- break;\r
- }\r
-\r
- //やることなす\r
- break;\r
- case TRemoteMcuRequest_CONTENT_ID_MIMICBC:\r
- //vパラメータとbcパラメータ。\r
- switch(i_qid){\r
- case TRemoteMcuRequest_QNAME_ID_V:\r
- if(i_qval!=NULL){\r
- if(NyLPC_cStr_isEqual(i_qval,"1")){\r
- o_out->content.mvm.v=TRemoteMcuRequest_QVAL_VERSION_1;\r
- }\r
- }\r
- break;\r
- case TRemoteMcuRequest_QNAME_ID_O:\r
- if(i_qval!=NULL){\r
- if(NyLPC_cStr_isEqual(i_qval,"j")){\r
- o_out->content.mvm.o=TRemoteMcuRequest_QVAL_O_JSON;\r
- }else if(NyLPC_cStr_isEqual(i_qval,"x")){\r
- o_out->content.mvm.o=TRemoteMcuRequest_QVAL_O_XML;\r
- }\r
- }\r
- break;\r
- default:\r
- //知らない子は無視\r
- break;\r
- }\r
- break;\r
- case TRemoteMcuRequest_CONTENT_ID_INDEX:\r
- //やることなす\r
- break;\r
- case TRemoteMcuRequest_CONTENT_ID_UNKNOWN:\r
- //やることなす\r
- break;\r
- case TRemoteMcuRequest_CONTENT_ID_STATUS:\r
- break;\r
- default:\r
- //ウェーイ\r
- return NyLPC_TBool_FALSE;\r
- }\r
- return NyLPC_TBool_TRUE;\r
-}\r
-#define TEST\r
-#ifndef TEST\r
-\r
-NyLPC_TBool test(char* test_patt,struct TRemoteMcuRequest* req)\r
-{\r
- NyLPC_TcHttpStream_t st;\r
- NyLPC_TcTcpSocket_t ts;\r
- TcRemoteMcuRequestParser_t inst;\r
- //TCPのオープン\r
- NyLPC_cTcpSocket_initialized(&ts,test_patt,strlen(test_patt));\r
- NyLPC_cHttpStream_initialize(&st,&ts);\r
-\r
- //各CGIの呼び出しをチェックする。\r
-\r
- cRemoteMcuRequestParser_initialize(&inst);\r
- if(cRemoteMcuRequestParser_parse(&inst,&st,req)!=200){\r
- return NyLPC_TBool_FALSE;\r
- }else{\r
- return NyLPC_TBool_TRUE;\r
- }\r
-// cRemoteMcuRequestParser_finalize(&inst);\r
-}\r
-\r
-\r
-\r
-#define PFX "GET "\r
-#define SFX " HTTP/1.1\r\n\r\n"\r
-void main(void)\r
-{\r
- struct TRemoteMcuRequest req;\r
-/* puts("TEST /");\r
- if( test(PFX"/"SFX,&req)&&\r
- (req._content_id==TRemoteMcuRequest_CONTENT_ID_INDEX)\r
- )\r
- {\r
- puts("OK");\r
- }else{\r
- puts("NG");\r
- }\r
-\r
-*/\r
- puts("TEST /setup.api");\r
- if( test(PFX"/setup.api?p=0001020300010203000102030001020300010203000102030001020300010203000102030001020300010203000102030001020300010203000102030001"SFX,&req)&&\r
- (req._content_id==TRemoteMcuRequest_CONTENT_ID_SETUP)\r
- )\r
- {\r
- puts("OK");\r
- }else{\r
- puts("NG");\r
- }\r
-\r
-/*\r
- puts("TEST /mvm.api?v=1&bc=ZADA0500000003ZA.E00000032");\r
- if( test(PFX"/mvm.api?v=1&bc=ZADA0500000003.E00000032"SFX,&req)&&\r
- (req._content_id==TRemoteMcuRequest_CONTENT_ID_MIMICBC)\r
- )\r
- {\r
- puts("OK");\r
- }else{\r
- puts("NG");\r
- }\r
-*/\r
-/*\r
- puts("TEST /unknown");\r
- if( test(PFX"/unknown"SFX,&req)&&\r
- (req._content_id==TRemoteMcuRequest_CONTENT_ID_UNKNOWN)\r
- )\r
- {\r
- puts("OK");\r
- }else{\r
- puts("NG");\r
- }\r
-*/\r
- return;\r
-\r
-}\r
-#endif\r