OSDN Git Service

参考演算子のカッコ追加
[mimic/MiMicSDK.git] / lib / src / net / httpd / NyLPC_cHttpdConnection.c
1 #include "NyLPC_cHttpdConnection_protected.h"\r
2 #include "NyLPC_http.h"\r
3 #include "NyLPC_cHttpdUtils.h"\r
4 #include "./NyLPC_cHttpd_protected.h"\r
5 \r
6 \r
7 \r
8 void NyLPC_cHttpdConnection_initialize(NyLPC_TcHttpdConnection_t* i_inst,NyLPC_TcHttpd_t* i_parent_httpd)\r
9 {\r
10         NyLPC_cTcpSocket_initialize(&(i_inst->_socket),i_inst->_rxbuf,NyLPC_NyLPC_TcHttpdConnection_SIZE_OF_RX_BUF);\r
11         NyLPC_cHttpRequestPrefixParser_initialize(&(i_inst->_pparser));\r
12         i_inst->_parent_httpd=i_parent_httpd;\r
13         i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_CLOSED;\r
14         i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_LISTEN;\r
15 }\r
16 \r
17 void NyLPC_cHttpdConnection_finalize(NyLPC_TcHttpdConnection_t* i_inst)\r
18 {\r
19         NyLPC_cHttpdConnection_closeResponse(i_inst);\r
20         NyLPC_cHttpdConnection_closeSocket(i_inst);\r
21         NyLPC_cHttpRequestPrefixParser_finalize(i_inst);\r
22         NyLPC_cTcpSocket_finalize(&(i_inst->_socket));\r
23 }\r
24 \r
25 const NyLPC_TChar* NyLPC_cHttpdConnection_getUrlPrefix(const NyLPC_TcHttpdConnection_t* i_inst)\r
26 {\r
27         return NyLPC_cHttpRequestPrefixParser_getUrlPrefix(&i_inst->_pparser);\r
28 }\r
29 void NyLPC_cHttpdConnection_setReqStatusParsed(NyLPC_TcHttpdConnection_t* i_inst)\r
30 {\r
31         i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_END;\r
32 }\r
33 \r
34 #define NyLPC_cHttpHeaderWriter_CONTENT_LENGTH_UNLIMITED 0xFFFFFFFF\r
35 \r
36 \r
37 NyLPC_TBool NyLPC_cHttpdConnection_send100Continue(NyLPC_TcHttpdConnection_t* i_inst)\r
38 {\r
39         //状態の確認\r
40         if(i_inst->_res_status!=NyLPC_cHttpdConnection_ResStatus_HEAD)\r
41         {\r
42                 NyLPC_OnErrorGoto(Error_Status);\r
43         }\r
44         //ステータスラインの記述\r
45         if(!NyLPC_iHttpPtrStream_write(&(i_inst->_in_stream.super),"HTTP/1.1 100 Continue\r\n\r\n",25)){\r
46                 NyLPC_OnErrorGoto(Error);\r
47         }\r
48         return NyLPC_TBool_TRUE;\r
49 Error:\r
50 Error_Status:\r
51         i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_ERROR;\r
52         return NyLPC_TBool_FALSE;\r
53 }\r
54 \r
55 /**\r
56  * レスポンスヘッダを送信します。\r
57  */\r
58 NyLPC_TBool NyLPC_cHttpdConnection_sendResponseHeader(NyLPC_TcHttpdConnection_t* i_inst,NyLPC_TUInt16 i_response_code,const NyLPC_TChar* i_content_type,const NyLPC_TChar* i_additional_header)\r
59 {\r
60         return NyLPC_cHttpdConnection_sendResponseHeader2(i_inst,i_response_code,i_content_type,NyLPC_cHttpHeaderWriter_CONTENT_LENGTH_UNLIMITED,i_additional_header);\r
61 }\r
62 \r
63 NyLPC_TBool NyLPC_cHttpdConnection_sendResponseHeader2(NyLPC_TcHttpdConnection_t* i_inst,NyLPC_TUInt16 i_response_code,const NyLPC_TChar* i_content_type,NyLPC_TUInt32 i_content_length,const NyLPC_TChar* i_additional_header)\r
64 {\r
65         NyLPC_TcHttpHeaderWriter_t* h=&(i_inst->_head_writer);\r
66         //状態の確認\r
67         if(i_inst->_res_status!=NyLPC_cHttpdConnection_ResStatus_HEAD)\r
68         {\r
69                 NyLPC_OnErrorGoto(Error_Status);\r
70         }\r
71         //ヘッダ送信\r
72         if(!NyLPC_cHttpHeaderWriter_initialize(h,&(i_inst->_in_stream.super),NULL)){\r
73                 NyLPC_OnErrorGoto(ERROR_SEND);\r
74         }\r
75         //Headerの転送モードセット\r
76         if(i_content_length==NyLPC_cHttpHeaderWriter_CONTENT_LENGTH_UNLIMITED){\r
77                 NyLPC_cHttpHeaderWriter_setChunked(h);\r
78         }else{\r
79                 NyLPC_cHttpHeaderWriter_setContentLength(h,i_content_length);\r
80         }\r
81         //continueにセットされていたらcloseをFALSEに\r
82         NyLPC_cHttpHeaderWriter_setConnectionClose(h,(i_inst->_connection_message_mode!=NyLPC_TcHttpdConnection_CONNECTION_MODE_CONTINUE));\r
83 \r
84         if(!NyLPC_cHttpHeaderWriter_writeResponseHeader(h,i_response_code)){\r
85                 NyLPC_OnErrorGoto(ERROR_SEND);\r
86         }\r
87         if(!NyLPC_cHttpHeaderWriter_writeMessage(h,"Content-type",i_content_type)){\r
88                 NyLPC_OnErrorGoto(ERROR_SEND);\r
89         }\r
90         if(i_additional_header!=NULL){\r
91                 if(!NyLPC_cHttpHeaderWriter_writeRawMessage(h,i_additional_header)){\r
92                         NyLPC_OnErrorGoto(ERROR_SEND);\r
93                 }\r
94         }\r
95         NyLPC_cHttpHeaderWriter_close(h);\r
96         NyLPC_cHttpHeaderWriter_finalize(h);\r
97         i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_BODY;\r
98         //BodyWriter生成\r
99         NyLPC_cHttpBodyWriter_initialize(&(i_inst->_body_writer),&(i_inst->_in_stream));\r
100         //bodyのchunkedもセット\r
101         if(i_content_length==NyLPC_cHttpHeaderWriter_CONTENT_LENGTH_UNLIMITED){\r
102                 NyLPC_cHttpBodyWriter_setChunked(&(i_inst->_body_writer));\r
103         }else{\r
104                 NyLPC_cHttpBodyWriter_setContentLength(&(i_inst->_body_writer),i_content_length);\r
105         }\r
106         return NyLPC_TBool_TRUE;\r
107 ERROR_SEND:\r
108         NyLPC_cHttpHeaderWriter_finalize(&(i_inst->_head_writer));\r
109 Error_Status:\r
110         i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_ERROR;\r
111         return NyLPC_TBool_FALSE;\r
112 }\r
113 \r
114 \r
115 /**\r
116  * レスポンスBodyを送信します。\r
117  * 関数を実行後、_res_statusはBODYかERRORに遷移します。\r
118  */\r
119 NyLPC_TBool NyLPC_cHttpdConnection_sendResponseBody(NyLPC_TcHttpdConnection_t* i_inst,const void* i_data,NyLPC_TUInt32 i_size)\r
120 {\r
121         if(i_inst->_res_status!=NyLPC_cHttpdConnection_ResStatus_BODY)\r
122         {\r
123                 NyLPC_OnErrorGoto(Error);\r
124         }\r
125         //Bodyの書込み\r
126         if(!NyLPC_cHttpBodyWriter_write(&(i_inst->_body_writer),i_data,i_size)){\r
127                 NyLPC_OnErrorGoto(Error_Send);\r
128         }\r
129         return NyLPC_TBool_TRUE;\r
130 Error_Send:\r
131         NyLPC_cHttpBodyWriter_finalize(&(i_inst->_in_stream));\r
132 Error:\r
133         i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_ERROR;\r
134         return NyLPC_TBool_FALSE;\r
135 }\r
136 /**\r
137  * レスポンスBodyを書式出力して送信します。\r
138  * 関数を実行後、_res_statusはBODYかERRORに遷移します。\r
139  */\r
140 NyLPC_TBool NyLPC_cHttpdConnection_sendResponseBodyF(NyLPC_TcHttpdConnection_t* i_inst,const char* i_fmt,...)\r
141 {\r
142         va_list a;\r
143         if(i_inst->_res_status!=NyLPC_cHttpdConnection_ResStatus_BODY)\r
144         {\r
145                 NyLPC_OnErrorGoto(Error);\r
146         }\r
147         //Bodyの書込み\r
148         va_start(a,i_fmt);\r
149         if(!NyLPC_cHttpBodyWriter_formatV(&(i_inst->_body_writer),i_fmt,a)){\r
150                 NyLPC_OnErrorGoto(Error_Send);\r
151         }\r
152         va_end(a);\r
153         return NyLPC_TBool_TRUE;\r
154 Error_Send:\r
155         va_end(a);\r
156         NyLPC_cHttpBodyWriter_finalize(&(i_inst->_in_stream));\r
157 Error:\r
158         i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_ERROR;\r
159         return NyLPC_TBool_FALSE;\r
160 }\r
161 \r
162 /**\r
163  * ヘッダのみのErrorレスポンスを送信する。\r
164  * この関数はワーク用のHeaderWriterを使います。\r
165  */\r
166 static void sendErrorResponse(NyLPC_TcHttpdConnection_t* i_inst,NyLPC_TInt16 i_status)\r
167 {\r
168         NyLPC_TcHttpHeaderWriter_t* h=&(i_inst->_head_writer);\r
169         if(NyLPC_cHttpHeaderWriter_initialize(h,&i_inst->_in_stream.super,NULL)){\r
170                 //ヘッダを送信\r
171                 NyLPC_cHttpHeaderWriter_setConnectionClose(h,NyLPC_TBool_TRUE);\r
172                 NyLPC_cHttpHeaderWriter_writeResponseHeader(h,i_status);\r
173                 NyLPC_cHttpHeaderWriter_close(h);\r
174                 NyLPC_cHttpHeaderWriter_finalize(h);\r
175         }\r
176 }\r
177 /**\r
178  * 関数を実行後、_res_statusはCLOSEDかHEADかERRORに遷移する。\r
179  */\r
180 NyLPC_TBool NyLPC_cHttpdConnection_closeResponse(NyLPC_TcHttpdConnection_t* i_inst)\r
181 {\r
182         NyLPC_TcHttpBodyWriter_t* b;\r
183         switch(i_inst->_res_status){\r
184         case NyLPC_cHttpdConnection_ResStatus_CLOSED:\r
185         case NyLPC_cHttpdConnection_ResStatus_ERROR:\r
186                 //何もせずにコネクションをクローズする。\r
187                 return NyLPC_TBool_FALSE;\r
188         case NyLPC_cHttpdConnection_ResStatus_HEAD:\r
189                 //エラー500を送信してクローズする。\r
190                 sendErrorResponse(i_inst,500);\r
191                 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_CLOSED;\r
192                 return NyLPC_TBool_FALSE;\r
193         case NyLPC_cHttpdConnection_ResStatus_BODY:\r
194                 //正常終了。BODYをクローズし、終了する。\r
195                 b=&(i_inst->_body_writer);\r
196                 NyLPC_cHttpBodyWriter_close(b);\r
197                 NyLPC_cHttpBodyWriter_finalize(&b);\r
198                 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_HEAD;\r
199                 if(i_inst->_connection_message_mode!=NyLPC_TcHttpdConnection_CONNECTION_MODE_CONTINUE)\r
200                 {\r
201                         i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_CLOSED;\r
202                         return NyLPC_TBool_FALSE;\r
203                 }\r
204                 return NyLPC_TBool_TRUE;\r
205         default:\r
206                 NyLPC_Abort();\r
207         }\r
208         return NyLPC_TBool_TRUE;\r
209 }\r
210 \r
211 /**\r
212  * コネクションのプリフェッチデータをヘッダパーサへpushします。\r
213  */\r
214 NyLPC_TBool NyLPC_cHttpdConnection_pushPrefetchInfo(NyLPC_TcHttpdConnection_t* i_inst,NyLPC_TcHttpBasicHeaderParser_t* i_header_parser,struct NyLPC_THttpBasicHeader* o_out)\r
215 {\r
216         const char* method=NyLPC_THttpMethodType_toString(i_inst->_pparser.method);\r
217         if(NyLPC_cHttpBasicHeaderParser_parseChar(i_header_parser,method,strlen(method),o_out)<0){\r
218                 NyLPC_OnErrorGoto(Error);\r
219         }\r
220         if(NyLPC_cHttpBasicHeaderParser_parseChar(i_header_parser," ",1,o_out)<0){\r
221                 NyLPC_OnErrorGoto(Error);\r
222         }\r
223         if(NyLPC_cHttpBasicHeaderParser_parseChar(i_header_parser,i_inst->_pparser._url,strlen(i_inst->_pparser._url),o_out)<0){\r
224                 NyLPC_OnErrorGoto(Error);\r
225         }\r
226         return NyLPC_TBool_TRUE;\r
227 Error:\r
228         return NyLPC_TBool_FALSE;\r
229 }\r
230 \r
231 #define NyLPC_cHttpdConnection_TIMEOUT_ACCEPT   3000\r
232 #define NyLPC_cHttpdConnection_TIMEOUT_CLOSE    5000\r
233 #define NyLPC_cHttpdConnection_TIMEOUT_LISTEN   5000\r
234 \r
235 \r
236 /**\r
237  * listenerでConnectionのソケットに接続を待ちます。\r
238  */\r
239 NyLPC_TBool NyLPC_cHttpdConnection_listenSocket(NyLPC_TcHttpdConnection_t* i_inst,NyLPC_TcTcpListener_t* i_listener)\r
240 {\r
241         NyLPC_Assert(i_inst->_req_status==NyLPC_cHttpdConnection_ReqStatus_LISTEN);\r
242         //リスニング\r
243         if(!NyLPC_cTcpListener_listen(i_listener,&(i_inst->_socket),NyLPC_cHttpdConnection_TIMEOUT_LISTEN)){\r
244                 return NyLPC_TBool_FALSE;\r
245         }\r
246         //成功したらステータス遷移\r
247         i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_ACCEPT;\r
248         return NyLPC_TBool_TRUE;\r
249 }\r
250 \r
251 /**\r
252  * コネクションのソケットをacceptします。\r
253  */\r
254 NyLPC_TBool NyLPC_cHttpdConnection_acceptSocket(NyLPC_TcHttpdConnection_t* i_inst)\r
255 {\r
256         NyLPC_Assert(i_inst->_req_status==NyLPC_cHttpdConnection_ReqStatus_ACCEPT);\r
257 \r
258         if(!NyLPC_cTcpSocket_accept(&(i_inst->_socket),NyLPC_cHttpdConnection_TIMEOUT_ACCEPT)){\r
259                 NyLPC_OnErrorGoto(Error);\r
260         }\r
261         //HttpStreamの生成\r
262         if(!NyLPC_cHttpStream_initialize(&i_inst->_in_stream,&(i_inst->_socket))){\r
263                 NyLPC_OnErrorGoto(Error_Connected);\r
264         }\r
265         //初回だけHEADに遷移\r
266         i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_HEAD;\r
267         i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_PREFETCH;\r
268         i_inst->_connection_message_mode=NyLPC_TcHttpdConnection_CONNECTION_MODE_CLOSE;\r
269         return NyLPC_TBool_TRUE;\r
270 Error_Connected:\r
271         NyLPC_cTcpSocket_close(&(i_inst->_socket),NyLPC_cHttpdConnection_TIMEOUT_CLOSE);\r
272         i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_LISTEN;\r
273 Error:\r
274         return NyLPC_TBool_FALSE;\r
275 }\r
276 \r
277 NyLPC_TBool NyLPC_cHttpdConnection_prefetch(NyLPC_TcHttpdConnection_t* i_inst)\r
278 {\r
279         NyLPC_Assert(i_inst->_req_status==NyLPC_cHttpdConnection_ReqStatus_PREFETCH);\r
280 \r
281         //Prefetchを実行\r
282         if(!NyLPC_cHttpRequestPrefixParser_parse(&i_inst->_pparser,&i_inst->_in_stream.super)){\r
283                 //400エラー\r
284                 sendErrorResponse(i_inst,400);\r
285                 NyLPC_OnErrorGoto(Error_Prefetch);\r
286         }\r
287         i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_REQPARSE;\r
288         return NyLPC_TBool_TRUE;\r
289 Error_Prefetch:\r
290         NyLPC_cTcpSocket_close(&(i_inst->_socket),NyLPC_cHttpdConnection_TIMEOUT_CLOSE);\r
291         i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_LISTEN;\r
292         return NyLPC_TBool_FALSE;\r
293 }\r
294 \r
295 \r
296 \r
297 \r
298 \r
299 \r
300 \r
301 NyLPC_TBool NyLPC_cHttpdConnection_prevNextPrefetch(NyLPC_TcHttpdConnection_t* i_inst)\r
302 {\r
303         NyLPC_TcHttpNullRequestHeaderParser_t parser;\r
304         switch(i_inst->_req_status)\r
305         {\r
306         case NyLPC_cHttpdConnection_ReqStatus_REQPARSE:\r
307                 //リクエストパース待ちなら前段のリクエストを吸収しておく。\r
308                 NyLPC_cHttpNullRequestHeaderParser_initialize(&parser);\r
309                 //プリフェッチしたデータを流す\r
310                 NyLPC_cHttpNullRequestHeaderParser_parseInit(&parser);\r
311                 NyLPC_cHttpNullRequestHeaderParser_parseChar(&parser,"GET ",4);//決め打ち\r
312                 NyLPC_cHttpNullRequestHeaderParser_parseChar(&parser,i_inst->_pparser._url,strlen(i_inst->_pparser._url));\r
313                 //後続をストリームから取り込む\r
314                 if(NyLPC_cHttpNullRequestHeaderParser_parseStream(&parser,&(i_inst->_in_stream.super))){\r
315                         if(NyLPC_cHttpNullRequestHeaderParser_parseFinish(&parser)){\r
316                                 NyLPC_cHttpNullRequestHeaderParser_finalize(&parser);\r
317                                 //OK:403\r
318                                 sendErrorResponse(i_inst,403);\r
319                                 break;//OK\r
320                         }\r
321                 }\r
322 \r
323                 NyLPC_cHttpNullRequestHeaderParser_finalize(&parser);\r
324                 //NG:400 Bad Request\r
325                 sendErrorResponse(i_inst,400);\r
326                 return NyLPC_TBool_FALSE;//吸収失敗\r
327         case NyLPC_cHttpdConnection_ReqStatus_END:\r
328                 //リクエストがパース済みならprefetchに戻す。\r
329                 i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_PREFETCH;\r
330         default:\r
331                 NyLPC_Abort();\r
332         }\r
333         //吸収成功\r
334         return NyLPC_TBool_TRUE;\r
335 }\r
336 \r
337 void NyLPC_cHttpdConnection_closeSocket(NyLPC_TcHttpdConnection_t* i_inst)\r
338 {\r
339         switch(i_inst->_req_status)\r
340         {\r
341         case NyLPC_cHttpdConnection_ReqStatus_LISTEN:\r
342                 //何も出来ない。\r
343                 break;\r
344         case NyLPC_cHttpdConnection_ReqStatus_END:\r
345         case NyLPC_cHttpdConnection_ReqStatus_REQPARSE:\r
346         case NyLPC_cHttpdConnection_ReqStatus_PREFETCH:\r
347                 NyLPC_cHttpStream_finalize(&i_inst->_in_stream);\r
348         case NyLPC_cHttpdConnection_ReqStatus_ACCEPT:\r
349                 NyLPC_cTcpSocket_close(&(i_inst->_socket),NyLPC_cHttpdConnection_TIMEOUT_CLOSE);\r
350         default:\r
351                 break;\r
352         }\r
353         i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_LISTEN;\r
354         i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_CLOSED;\r
355 }\r
356 \r
357 /**\r
358  * Httpd全体で唯一のロックを取得する。\r
359  */\r
360 void NyLPC_cHttpdConnection_lock(NyLPC_TcHttpdConnection_t* i_inst)\r
361 {\r
362         NyLPC_cHttpd_lock((NyLPC_TcHttpd_t*)(i_inst->_parent_httpd));\r
363 }\r
364 /**\r
365  * Httpd全体で唯一のロックを開放する。\r
366  */\r
367 void NyLPC_cHttpdConnection_unlock(NyLPC_TcHttpdConnection_t* i_inst)\r
368 {\r
369         NyLPC_cHttpd_unlock((NyLPC_TcHttpd_t*)(i_inst->_parent_httpd));\r
370 }\r