1 #include "NyLPC_cHttpdConnection_protected.h"
\r
2 #include "NyLPC_http.h"
\r
3 #include "NyLPC_netif.h"
\r
4 #include "NyLPC_cHttpdUtils.h"
\r
5 #include "./NyLPC_cHttpd_protected.h"
\r
9 NyLPC_TBool NyLPC_cHttpdConnection_initialize(NyLPC_TcHttpdConnection_t* i_inst,NyLPC_TcHttpd_t* i_parent_httpd)
\r
11 i_inst->_socket=NyLPC_cNet_createTcpSocketEx(NyLPC_TSocketType_TCP_HTTP);
\r
12 if(i_inst->_socket==NULL){
\r
13 return NyLPC_TBool_FALSE;
\r
15 NyLPC_cHttpRequestPrefixParser_initialize(&(i_inst->_pparser));
\r
16 i_inst->_parent_httpd=i_parent_httpd;
\r
17 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_CLOSED;
\r
18 i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_LISTEN;
\r
19 return NyLPC_TBool_TRUE;
\r
22 void NyLPC_cHttpdConnection_finalize(NyLPC_TcHttpdConnection_t* i_inst)
\r
24 NyLPC_cHttpdConnection_closeResponse(i_inst);
\r
25 NyLPC_cHttpdConnection_closeSocket(i_inst);
\r
26 NyLPC_cHttpRequestPrefixParser_finalize(i_inst);
\r
27 NyLPC_iTcpSocket_finalize(i_inst->_socket);
\r
30 const NyLPC_TChar* NyLPC_cHttpdConnection_getUrlPrefix(const NyLPC_TcHttpdConnection_t* i_inst)
\r
32 return NyLPC_cHttpRequestPrefixParser_getUrlPrefix(&i_inst->_pparser);
\r
34 void NyLPC_cHttpdConnection_setReqStatusParsed(NyLPC_TcHttpdConnection_t* i_inst)
\r
36 i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_END;
\r
39 #define NyLPC_cHttpHeaderWriter_CONTENT_LENGTH_UNLIMITED 0xFFFFFFFF
\r
42 NyLPC_TBool NyLPC_cHttpdConnection_send100Continue(NyLPC_TcHttpdConnection_t* i_inst)
\r
45 if(i_inst->_res_status!=NyLPC_cHttpdConnection_ResStatus_HEAD)
\r
47 NyLPC_OnErrorGoto(Error_Status);
\r
50 if(!NyLPC_iHttpPtrStream_write(&(i_inst->_in_stream.super),"HTTP/1.1 100 Continue\r\n\r\n",25)){
\r
51 NyLPC_OnErrorGoto(Error);
\r
53 return NyLPC_TBool_TRUE;
\r
56 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_ERROR;
\r
57 return NyLPC_TBool_FALSE;
\r
63 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
65 return NyLPC_cHttpdConnection_sendResponseHeader2(i_inst,i_response_code,i_content_type,NyLPC_cHttpHeaderWriter_CONTENT_LENGTH_UNLIMITED,i_additional_header);
\r
68 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
70 NyLPC_TcHttpHeaderWriter_t* h=&(i_inst->_head_writer);
\r
72 if(i_inst->_res_status!=NyLPC_cHttpdConnection_ResStatus_HEAD)
\r
74 NyLPC_OnErrorGoto(Error_Status);
\r
77 if(!NyLPC_cHttpHeaderWriter_initialize(h,&(i_inst->_in_stream.super),NULL)){
\r
78 NyLPC_OnErrorGoto(ERROR_SEND);
\r
81 if(i_content_length==NyLPC_cHttpHeaderWriter_CONTENT_LENGTH_UNLIMITED){
\r
82 NyLPC_cHttpHeaderWriter_setChunked(h);
\r
84 NyLPC_cHttpHeaderWriter_setContentLength(h,i_content_length);
\r
86 //continueにセットされていたらcloseをFALSEに
\r
87 NyLPC_cHttpHeaderWriter_setConnectionClose(h,(i_inst->_connection_message_mode!=NyLPC_TcHttpdConnection_CONNECTION_MODE_CONTINUE));
\r
89 if(!NyLPC_cHttpHeaderWriter_writeResponseHeader(h,i_response_code)){
\r
90 NyLPC_OnErrorGoto(ERROR_SEND);
\r
92 if(!NyLPC_cHttpHeaderWriter_writeMessage(h,"Content-type",i_content_type)){
\r
93 NyLPC_OnErrorGoto(ERROR_SEND);
\r
95 if(i_additional_header!=NULL){
\r
96 if(!NyLPC_cHttpHeaderWriter_writeRawMessage(h,i_additional_header)){
\r
97 NyLPC_OnErrorGoto(ERROR_SEND);
\r
100 NyLPC_cHttpHeaderWriter_close(h);
\r
101 NyLPC_cHttpHeaderWriter_finalize(h);
\r
102 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_BODY;
\r
104 NyLPC_cHttpBodyWriter_initialize(&(i_inst->_body_writer),&(i_inst->_in_stream));
\r
106 if(i_content_length==NyLPC_cHttpHeaderWriter_CONTENT_LENGTH_UNLIMITED){
\r
107 NyLPC_cHttpBodyWriter_setChunked(&(i_inst->_body_writer));
\r
109 NyLPC_cHttpBodyWriter_setContentLength(&(i_inst->_body_writer),i_content_length);
\r
111 return NyLPC_TBool_TRUE;
\r
113 NyLPC_cHttpHeaderWriter_finalize(&(i_inst->_head_writer));
\r
115 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_ERROR;
\r
116 return NyLPC_TBool_FALSE;
\r
122 * 関数を実行後、_res_statusはBODYかERRORに遷移します。
\r
124 NyLPC_TBool NyLPC_cHttpdConnection_sendResponseBody(NyLPC_TcHttpdConnection_t* i_inst,const void* i_data,NyLPC_TUInt32 i_size)
\r
126 if(i_inst->_res_status!=NyLPC_cHttpdConnection_ResStatus_BODY)
\r
128 NyLPC_OnErrorGoto(Error);
\r
131 if(!NyLPC_cHttpBodyWriter_write(&(i_inst->_body_writer),i_data,i_size)){
\r
132 NyLPC_OnErrorGoto(Error_Send);
\r
134 return NyLPC_TBool_TRUE;
\r
136 NyLPC_cHttpBodyWriter_finalize(&(i_inst->_in_stream));
\r
138 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_ERROR;
\r
139 return NyLPC_TBool_FALSE;
\r
142 * レスポンスBodyを書式出力して送信します。
\r
143 * 関数を実行後、_res_statusはBODYかERRORに遷移します。
\r
145 NyLPC_TBool NyLPC_cHttpdConnection_sendResponseBodyF(NyLPC_TcHttpdConnection_t* i_inst,const char* i_fmt,...)
\r
148 if(i_inst->_res_status!=NyLPC_cHttpdConnection_ResStatus_BODY)
\r
150 NyLPC_OnErrorGoto(Error);
\r
154 if(!NyLPC_cHttpBodyWriter_formatV(&(i_inst->_body_writer),i_fmt,a)){
\r
155 NyLPC_OnErrorGoto(Error_Send);
\r
158 return NyLPC_TBool_TRUE;
\r
161 NyLPC_cHttpBodyWriter_finalize(&(i_inst->_in_stream));
\r
163 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_ERROR;
\r
164 return NyLPC_TBool_FALSE;
\r
168 * ヘッダのみのErrorレスポンスを送信する。
\r
169 * この関数はワーク用のHeaderWriterを使います。
\r
171 static void sendErrorResponse(NyLPC_TcHttpdConnection_t* i_inst,NyLPC_TInt16 i_status)
\r
173 NyLPC_TcHttpHeaderWriter_t* h=&(i_inst->_head_writer);
\r
174 if(NyLPC_cHttpHeaderWriter_initialize(h,&i_inst->_in_stream.super,NULL)){
\r
176 NyLPC_cHttpHeaderWriter_setConnectionClose(h,NyLPC_TBool_TRUE);
\r
177 NyLPC_cHttpHeaderWriter_writeResponseHeader(h,i_status);
\r
178 NyLPC_cHttpHeaderWriter_close(h);
\r
179 NyLPC_cHttpHeaderWriter_finalize(h);
\r
183 * 関数を実行後、_res_statusはCLOSEDかHEADかERRORに遷移する。
\r
185 NyLPC_TBool NyLPC_cHttpdConnection_closeResponse(NyLPC_TcHttpdConnection_t* i_inst)
\r
187 NyLPC_TcHttpBodyWriter_t* b;
\r
188 switch(i_inst->_res_status){
\r
189 case NyLPC_cHttpdConnection_ResStatus_CLOSED:
\r
190 case NyLPC_cHttpdConnection_ResStatus_ERROR:
\r
191 //何もせずにコネクションをクローズする。
\r
192 return NyLPC_TBool_FALSE;
\r
193 case NyLPC_cHttpdConnection_ResStatus_HEAD:
\r
194 //エラー500を送信してクローズする。
\r
195 sendErrorResponse(i_inst,500);
\r
196 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_CLOSED;
\r
197 return NyLPC_TBool_FALSE;
\r
198 case NyLPC_cHttpdConnection_ResStatus_BODY:
\r
199 //正常終了。BODYをクローズし、終了する。
\r
200 b=&(i_inst->_body_writer);
\r
201 NyLPC_cHttpBodyWriter_close(b);
\r
202 NyLPC_cHttpBodyWriter_finalize(&b);
\r
203 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_HEAD;
\r
204 if(i_inst->_connection_message_mode!=NyLPC_TcHttpdConnection_CONNECTION_MODE_CONTINUE)
\r
206 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_CLOSED;
\r
207 return NyLPC_TBool_FALSE;
\r
209 return NyLPC_TBool_TRUE;
\r
213 return NyLPC_TBool_TRUE;
\r
217 * コネクションのプリフェッチデータをヘッダパーサへpushします。
\r
219 NyLPC_TBool NyLPC_cHttpdConnection_pushPrefetchInfo(NyLPC_TcHttpdConnection_t* i_inst,NyLPC_TcHttpBasicHeaderParser_t* i_header_parser,struct NyLPC_THttpBasicHeader* o_out)
\r
221 const char* method=NyLPC_THttpMethodType_toString(i_inst->_pparser.method);
\r
222 if(NyLPC_cHttpBasicHeaderParser_parseChar(i_header_parser,method,strlen(method),o_out)<0){
\r
223 NyLPC_OnErrorGoto(Error);
\r
225 if(NyLPC_cHttpBasicHeaderParser_parseChar(i_header_parser," ",1,o_out)<0){
\r
226 NyLPC_OnErrorGoto(Error);
\r
228 if(NyLPC_cHttpBasicHeaderParser_parseChar(i_header_parser,i_inst->_pparser._url,strlen(i_inst->_pparser._url),o_out)<0){
\r
229 NyLPC_OnErrorGoto(Error);
\r
231 return NyLPC_TBool_TRUE;
\r
233 return NyLPC_TBool_FALSE;
\r
236 #define NyLPC_cHttpdConnection_TIMEOUT_ACCEPT 3000
\r
237 #define NyLPC_cHttpdConnection_TIMEOUT_CLOSE 5000
\r
238 #define NyLPC_cHttpdConnection_TIMEOUT_LISTEN 5000
\r
242 * listenerでConnectionのソケットに接続を待ちます。
\r
244 NyLPC_TBool NyLPC_cHttpdConnection_listenSocket(NyLPC_TcHttpdConnection_t* i_inst,NyLPC_TiTcpListener_t* i_listener)
\r
246 NyLPC_Assert(i_inst->_req_status==NyLPC_cHttpdConnection_ReqStatus_LISTEN);
\r
248 if(!NyLPC_iTcpListener_listen(i_listener,i_inst->_socket,NyLPC_cHttpdConnection_TIMEOUT_LISTEN)){
\r
249 return NyLPC_TBool_FALSE;
\r
252 i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_ACCEPT;
\r
253 return NyLPC_TBool_TRUE;
\r
257 * コネクションのソケットをacceptします。
\r
259 NyLPC_TBool NyLPC_cHttpdConnection_acceptSocket(NyLPC_TcHttpdConnection_t* i_inst)
\r
261 NyLPC_Assert(i_inst->_req_status==NyLPC_cHttpdConnection_ReqStatus_ACCEPT);
\r
263 if(!NyLPC_iTcpSocket_accept(i_inst->_socket,NyLPC_cHttpdConnection_TIMEOUT_ACCEPT)){
\r
264 NyLPC_OnErrorGoto(Error);
\r
267 if(!NyLPC_cHttpStream_initialize(&i_inst->_in_stream,i_inst->_socket)){
\r
268 NyLPC_OnErrorGoto(Error_Connected);
\r
271 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_HEAD;
\r
272 i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_PREFETCH;
\r
273 i_inst->_connection_message_mode=NyLPC_TcHttpdConnection_CONNECTION_MODE_CLOSE;
\r
274 return NyLPC_TBool_TRUE;
\r
276 NyLPC_iTcpSocket_close(i_inst->_socket,NyLPC_cHttpdConnection_TIMEOUT_CLOSE);
\r
277 i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_LISTEN;
\r
279 return NyLPC_TBool_FALSE;
\r
282 NyLPC_TBool NyLPC_cHttpdConnection_prefetch(NyLPC_TcHttpdConnection_t* i_inst)
\r
284 NyLPC_Assert(i_inst->_req_status==NyLPC_cHttpdConnection_ReqStatus_PREFETCH);
\r
287 if(!NyLPC_cHttpRequestPrefixParser_parse(&i_inst->_pparser,&i_inst->_in_stream.super)){
\r
289 sendErrorResponse(i_inst,400);
\r
290 NyLPC_OnErrorGoto(Error_Prefetch);
\r
292 i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_REQPARSE;
\r
293 return NyLPC_TBool_TRUE;
\r
295 NyLPC_iTcpSocket_close(i_inst->_socket,NyLPC_cHttpdConnection_TIMEOUT_CLOSE);
\r
296 i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_LISTEN;
\r
297 return NyLPC_TBool_FALSE;
\r
306 NyLPC_TBool NyLPC_cHttpdConnection_prevNextPrefetch(NyLPC_TcHttpdConnection_t* i_inst)
\r
308 NyLPC_TcHttpNullRequestHeaderParser_t parser;
\r
309 switch(i_inst->_req_status)
\r
311 case NyLPC_cHttpdConnection_ReqStatus_REQPARSE:
\r
312 //リクエストパース待ちなら前段のリクエストを吸収しておく。
\r
313 NyLPC_cHttpNullRequestHeaderParser_initialize(&parser);
\r
315 NyLPC_cHttpNullRequestHeaderParser_parseInit(&parser);
\r
316 NyLPC_cHttpNullRequestHeaderParser_parseChar(&parser,"GET ",4);//決め打ち
\r
317 NyLPC_cHttpNullRequestHeaderParser_parseChar(&parser,i_inst->_pparser._url,strlen(i_inst->_pparser._url));
\r
319 if(NyLPC_cHttpNullRequestHeaderParser_parseStream(&parser,&(i_inst->_in_stream.super))){
\r
320 if(NyLPC_cHttpNullRequestHeaderParser_parseFinish(&parser)){
\r
321 NyLPC_cHttpNullRequestHeaderParser_finalize(&parser);
\r
323 sendErrorResponse(i_inst,403);
\r
328 NyLPC_cHttpNullRequestHeaderParser_finalize(&parser);
\r
329 //NG:400 Bad Request
\r
330 sendErrorResponse(i_inst,400);
\r
331 return NyLPC_TBool_FALSE;//吸収失敗
\r
332 case NyLPC_cHttpdConnection_ReqStatus_END:
\r
333 //リクエストがパース済みならprefetchに戻す。
\r
334 i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_PREFETCH;
\r
339 return NyLPC_TBool_TRUE;
\r
342 void NyLPC_cHttpdConnection_closeSocket(NyLPC_TcHttpdConnection_t* i_inst)
\r
344 switch(i_inst->_req_status)
\r
346 case NyLPC_cHttpdConnection_ReqStatus_LISTEN:
\r
349 case NyLPC_cHttpdConnection_ReqStatus_END:
\r
350 case NyLPC_cHttpdConnection_ReqStatus_REQPARSE:
\r
351 case NyLPC_cHttpdConnection_ReqStatus_PREFETCH:
\r
352 NyLPC_cHttpStream_finalize(&i_inst->_in_stream);
\r
353 case NyLPC_cHttpdConnection_ReqStatus_ACCEPT:
\r
354 NyLPC_iTcpSocket_close(i_inst->_socket,NyLPC_cHttpdConnection_TIMEOUT_CLOSE);
\r
358 i_inst->_req_status=NyLPC_cHttpdConnection_ReqStatus_LISTEN;
\r
359 i_inst->_res_status=NyLPC_cHttpdConnection_ResStatus_CLOSED;
\r
363 * Httpd全体で唯一のロックを取得する。
\r
365 void NyLPC_cHttpdConnection_lock(NyLPC_TcHttpdConnection_t* i_inst)
\r
367 NyLPC_cHttpd_lock((NyLPC_TcHttpd_t*)(i_inst->_parent_httpd));
\r
370 * Httpd全体で唯一のロックを開放する。
\r
372 void NyLPC_cHttpdConnection_unlock(NyLPC_TcHttpdConnection_t* i_inst)
\r
374 NyLPC_cHttpd_unlock((NyLPC_TcHttpd_t*)(i_inst->_parent_httpd));
\r