OSDN Git Service

update libMiMic
[mimic/MiMicSDK.git] / lib / src / net / httpcl / NyLPC_cHttpClient.c
1 /*\r
2  * NyLPC_cHttpClient.c\r
3  *\r
4  *  Created on: 2013/08/24\r
5  *      Author: nyatla\r
6  */\r
7 #include "NyLPC_cHttpClient.h"\r
8 typedef NyLPC_TUInt8 NyLPC_TcHttpClient_ST;\r
9 #define NyLPC_TcHttpClient_ST_CLOSED 0x00       //ソケット切断\r
10 #define NyLPC_TcHttpClient_ST_IDLE   0x01       //メソッド選択待ち\r
11 \r
12 #define NyLPC_TcHttpClient_ST_SEND_REQ_BODY     0x21 //POSTリクエスト送信中\r
13 #define NyLPC_TcHttpClient_ST_RECV_RES_HEAD     0x23\r
14 #define NyLPC_TcHttpClient_ST_RECV_RES_BODY     0x24\r
15 \r
16 \r
17 \r
18 NyLPC_TBool NyLPC_cHttpClient_initialize(NyLPC_TcHttpClient_t* i_inst,void* i_rx_buf,NyLPC_TUInt16 i_rx_size)\r
19 {\r
20         i_inst->_sock=NyLPC_cNet_createTcpSocketEx(NyLPC_TSocketType_TCP_NORMAL);\r
21         if(i_inst->_sock==NULL){\r
22                 return NyLPC_TBool_FALSE;\r
23         }\r
24         i_inst->_state=NyLPC_TcHttpClient_ST_CLOSED;\r
25         return NyLPC_TBool_TRUE;\r
26 }\r
27 void NyLPC_cHttpClient_finalize(NyLPC_TcHttpClient_t* i_inst)\r
28 {\r
29         NyLPC_cHttpClient_close(i_inst);\r
30         NyLPC_iTcpSocket_finalize(i_inst->_sock);\r
31 }\r
32 \r
33 void NyLPC_cHttpClient_close(NyLPC_TcHttpClient_t* i_inst)\r
34 {\r
35         //ステータスをclosedへ遷移\r
36         switch(i_inst->_state){\r
37         case NyLPC_TcHttpClient_ST_RECV_RES_BODY:\r
38                 NyLPC_cHttpBodyParser_finalize(&i_inst->pw.body_parser);\r
39                 break;\r
40         case NyLPC_TcHttpClient_ST_SEND_REQ_BODY:\r
41                 NyLPC_cHttpBodyWriter_finalize(&(i_inst->pw.body_writer));\r
42                 break;\r
43         case NyLPC_TcHttpClient_ST_RECV_RES_HEAD:\r
44                 //開放するものとくにない\r
45                 break;\r
46         case NyLPC_TcHttpClient_ST_IDLE:\r
47                 break;\r
48         case NyLPC_TcHttpClient_ST_CLOSED:\r
49                 return;\r
50         }\r
51         NyLPC_iTcpSocket_close(i_inst->_sock,1000);\r
52         i_inst->_state=NyLPC_TcHttpClient_ST_CLOSED;\r
53 }\r
54 \r
55 /**\r
56  * サーバに接続する。\r
57  * 関数はステータスをIDLEへ遷移する。\r
58  * インスタンスのステータスは何でも構わない。\r
59  * @return\r
60  * TRUE - ステータスはIDLEへ遷移する。\r
61  * FALSE - ステータスはCLOSEDへ遷移する。\r
62  */\r
63 NyLPC_TBool NyLPC_cHttpClient_connect(NyLPC_TcHttpClient_t* i_inst,const struct NyLPC_TIPv4Addr* i_addr,NyLPC_TUInt16 i_port)\r
64 {\r
65         //ステータスをclosedへ遷移\r
66         NyLPC_cHttpClient_close(i_inst);\r
67         //接続\r
68         if(!NyLPC_iTcpSocket_connect(i_inst->_sock,i_addr,i_port,3000)){\r
69                 return NyLPC_TBool_FALSE;\r
70         }\r
71         //streamの生成\r
72         if(!NyLPC_cHttpStream_initialize(&i_inst->_stream,i_inst->_sock)){\r
73                 NyLPC_OnErrorGoto(ERROR);\r
74         }\r
75         //ステータス遷移\r
76         i_inst->_state=NyLPC_TcHttpClient_ST_IDLE;\r
77         return NyLPC_TBool_TRUE;\r
78 ERROR:\r
79         return NyLPC_TBool_FALSE;\r
80 }\r
81 \r
82 \r
83 \r
84 /**\r
85  * POSTリクエストを送信する。\r
86  * @return\r
87  * 引き続き処理が可能かを返す。\r
88  */\r
89 NyLPC_TBool NyLPC_cHttpClient_sendMethod(\r
90         NyLPC_TcHttpClient_t* i_inst,\r
91         NyLPC_THttpMethodType i_method,\r
92         const NyLPC_TChar* i_path,\r
93         NyLPC_TUInt32 i_content_length,\r
94         const NyLPC_TChar* i_mime_type,\r
95         const NyLPC_TChar* i_additional_header)\r
96 {\r
97         //ステータスチェック\r
98         if(i_inst->_state!=NyLPC_TcHttpClient_ST_IDLE){\r
99                 NyLPC_OnErrorGoto(Error_0);\r
100         }\r
101         //POSTリクエストの送信\r
102         if(!NyLPC_cHttpHeaderWriter_initialize(&i_inst->pw.head_writer,&i_inst->_stream.super,NULL)){\r
103                 NyLPC_OnErrorGoto(Error_0);\r
104         }\r
105         //ヘッダを送信\r
106         NyLPC_cHttpHeaderWriter_setConnectionClose(&i_inst->pw.head_writer,NyLPC_TBool_TRUE);//Connection closeを強制\r
107         if(i_content_length==NyLPC_cHttpHeaderWriter_CONTENT_LENGTH_UNLIMITED){\r
108                 NyLPC_cHttpHeaderWriter_setChunked(&i_inst->pw.head_writer);\r
109         }else{\r
110                 NyLPC_cHttpHeaderWriter_setContentLength(&i_inst->pw.head_writer,i_content_length);\r
111         }\r
112         if(!NyLPC_cHttpHeaderWriter_writeRequestHeader(\r
113                 &i_inst->pw.head_writer,\r
114                 i_method,\r
115                 NyLPC_iTcpSocket_getPeerAddr((i_inst->_sock)),\r
116                 NyLPC_iTcpSocket_getPeerPort((i_inst->_sock)),i_path)){\r
117                 NyLPC_OnErrorGoto(Error_1);\r
118         }\r
119         //MimeType\r
120         if(i_mime_type!=NULL){\r
121                 if(!NyLPC_cHttpHeaderWriter_writeMessage(&i_inst->pw.head_writer,"Content-type",i_mime_type)){\r
122                         NyLPC_OnErrorGoto(Error_1);\r
123                 }\r
124         }\r
125         if(i_additional_header!=NULL){\r
126                 if(!NyLPC_cHttpHeaderWriter_writeRawMessage(&i_inst->pw.head_writer,i_additional_header)){\r
127                         NyLPC_OnErrorGoto(Error_1);\r
128                 }\r
129         }\r
130         NyLPC_cHttpHeaderWriter_close(&i_inst->pw.head_writer);\r
131         NyLPC_cHttpHeaderWriter_finalize(&i_inst->pw.head_writer);\r
132 \r
133         //BodyWriter生成\r
134         NyLPC_cHttpBodyWriter_initialize(&(i_inst->pw.body_writer),&(i_inst->_stream));\r
135         //bodyのchunkedもセット\r
136         if(i_content_length==0xffffffff){\r
137                 NyLPC_cHttpBodyWriter_setChunked(&(i_inst->pw.body_writer));\r
138         }else{\r
139                 NyLPC_cHttpBodyWriter_setContentLength(&(i_inst->pw.body_writer),i_content_length);\r
140         }\r
141         i_inst->_state=NyLPC_TcHttpClient_ST_SEND_REQ_BODY;\r
142         return NyLPC_TBool_TRUE;\r
143 Error_0:\r
144         return NyLPC_TBool_FALSE;\r
145 Error_1:\r
146         NyLPC_cHttpHeaderWriter_finalize(&i_inst->pw.head_writer);\r
147         return NyLPC_TBool_FALSE;\r
148 }\r
149 \r
150 /**\r
151  * POSTリクエストのデータを送信する。\r
152  * @return\r
153  * 0:EOF\r
154  */\r
155 NyLPC_TBool NyLPC_cHttpClient_write(NyLPC_TcHttpClient_t* i_inst,const void* i_buf,NyLPC_TUInt32 i_buf_size)\r
156 {\r
157         if(i_inst->_state!=NyLPC_TcHttpClient_ST_SEND_REQ_BODY){\r
158                 return NyLPC_TBool_FALSE;\r
159         }\r
160         if(!NyLPC_cHttpBodyWriter_write(&i_inst->pw.body_writer,i_buf,i_buf_size)){\r
161                 //ERROR\r
162                 NyLPC_cHttpClient_close(i_inst);\r
163                 NyLPC_OnErrorGoto(Error);\r
164         }\r
165         return NyLPC_TBool_TRUE;\r
166 Error:\r
167         return NyLPC_TBool_FALSE;\r
168 }\r
169 \r
170 NyLPC_TBool NyLPC_cHttpClient_writeFormat(NyLPC_TcHttpClient_t* i_inst,const NyLPC_TChar* i_fmt,...)\r
171 {\r
172         NyLPC_TBool ret;\r
173         va_list a;\r
174         if(i_inst->_state!=NyLPC_TcHttpClient_ST_SEND_REQ_BODY){\r
175                 return NyLPC_TBool_FALSE;\r
176         }\r
177         va_start(a,i_fmt);\r
178         ret=NyLPC_cHttpBodyWriter_formatV(&i_inst->pw.body_writer,i_fmt,a);\r
179         va_end(a);\r
180         if(!ret){\r
181                 NyLPC_cHttpClient_close(i_inst);\r
182         }\r
183         return ret;\r
184 }\r
185 NyLPC_TBool NyLPC_cHttpClient_writeFormatV(NyLPC_TcHttpClient_t* i_inst,const NyLPC_TChar* i_fmt,va_list i_args)\r
186 {\r
187         NyLPC_TBool ret;\r
188         if(i_inst->_state!=NyLPC_TcHttpClient_ST_SEND_REQ_BODY){\r
189                 return NyLPC_TBool_FALSE;\r
190         }\r
191         ret=NyLPC_cHttpBodyWriter_formatV(&i_inst->pw.body_writer,i_fmt,i_args);\r
192         if(!ret){\r
193                 NyLPC_cHttpClient_close(i_inst);\r
194         }\r
195         return ret;\r
196 }\r
197 \r
198 \r
199 /**\r
200  * ステータスコードを返す。\r
201  * @return\r
202  * ステータスコード\r
203  */\r
204 NyLPC_TUInt16 NyLPC_cHttpClient_getStatus(NyLPC_TcHttpClient_t* i_inst)\r
205 {\r
206         struct NyLPC_THttpBasicHeader header;\r
207         if(i_inst->_state!=NyLPC_TcHttpClient_ST_SEND_REQ_BODY){\r
208                 return 0;\r
209         }\r
210         //\r
211         if(!NyLPC_cHttpBodyWriter_close(&i_inst->pw.body_writer)){\r
212                 NyLPC_OnErrorGoto(Error_1);\r
213         }\r
214         i_inst->_state=NyLPC_TcHttpClient_ST_RECV_RES_HEAD;\r
215         //100を無視してHTTPヘッダをパース\r
216         //@todo POSTの時だけに制限したら?\r
217         do{\r
218                 NyLPC_cHttpBasicHeaderParser_initialize(&i_inst->pw.head_parser,NULL);\r
219                 NyLPC_cHttpBasicHeaderParser_parseInit(&i_inst->pw.head_parser,&header);\r
220                 if(!NyLPC_cHttpBasicHeaderParser_parseStream(&i_inst->pw.head_parser,&i_inst->_stream.super,&header)){\r
221                         NyLPC_OnErrorGoto(Error_2);\r
222                 }\r
223                 if(!NyLPC_cHttpBasicHeaderParser_parseFinish(&i_inst->pw.head_parser,&header)){\r
224                         NyLPC_OnErrorGoto(Error_2);\r
225                 }\r
226                 NyLPC_cHttpBasicHeaderParser_finalize(&i_inst->pw.head_parser);\r
227                 //レスポンスヘッダか確認\r
228                 if(header.type!=NyLPC_THttpHeaderType_RESPONSE){\r
229                         NyLPC_OnErrorGoto(Error_1);\r
230                 }\r
231         }while(header.startline.res.status==100);\r
232         //BodyParserを起動\r
233         NyLPC_cHttpBodyParser_initialize(&i_inst->pw.body_parser);\r
234         NyLPC_cHttpBodyParser_parseInit(&i_inst->pw.body_parser,&header);\r
235         i_inst->_state=NyLPC_TcHttpClient_ST_RECV_RES_BODY;\r
236         return header.startline.res.status;\r
237 Error_1:\r
238         NyLPC_cHttpClient_close(i_inst);\r
239         return 0;\r
240 Error_2:\r
241         NyLPC_cHttpBasicHeaderParser_finalize(&i_inst->pw.head_parser);\r
242         NyLPC_cHttpClient_close(i_inst);\r
243         return 0;\r
244 }\r
245 \r
246 \r
247 /**\r
248  * GET/POSTリクエストで受信したデータを読み出す。\r
249  * @param o_read_len\r
250  * 戻り値TRUEの場合のみ有効。\r
251  * 終端の場合は0\r
252  * @return\r
253  * TRUE:正常読み出し。o_read_lenの値で終端判定\r
254  * FALSE:失敗。コネクションはクローズされる。\r
255  */\r
256 NyLPC_TBool NyLPC_cHttpClient_read(NyLPC_TcHttpClient_t* i_inst,void* i_buf,NyLPC_TUInt32 i_buf_size,NyLPC_TInt16* o_read_len)\r
257 {\r
258         if(i_inst->_state!=NyLPC_TcHttpClient_ST_RECV_RES_BODY){\r
259                 return NyLPC_TBool_FALSE;\r
260         }\r
261         if(!NyLPC_cHttpBodyParser_parseStream(&i_inst->pw.body_parser,&i_inst->_stream.super,i_buf,i_buf_size,o_read_len)){\r
262                 NyLPC_cHttpClient_close(i_inst);\r
263                 return NyLPC_TBool_FALSE;\r
264         }\r
265         return NyLPC_TBool_TRUE;\r
266 }\r
267 \r