OSDN Git Service

git-svn-id: http://svn.osdn.jp/svnroot/mimic/trunk@198 47198e57-cb75-475f-84c4-a814cd...
[mimic/MiMicSDK.git] / lib / src / http / NyLPC_cHttpBodyWriter.c
1 /*********************************************************************************\r
2  * PROJECT: MiMic\r
3  * --------------------------------------------------------------------------------\r
4  *\r
5  * This file is part of MiMic\r
6  * Copyright (C)2011 Ryo Iizuka\r
7  *\r
8  * MiMic is free software: you can redistribute it and/or modify\r
9  * it under the terms of the GNU Lesser General Public License as published\r
10  * by the Free Software Foundation, either version 3 of the License, or\r
11  * (at your option) any later version.\r
12  *\r
13  * This program is distributed in the hope that it will be useful,\r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  * GNU General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU Lesser General Public License\r
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
20  *\r
21  * For further information please contact.\r
22  *      http://nyatla.jp/\r
23  *      <airmail(at)ebony.plala.or.jp> or <nyatla(at)nyatla.jp>\r
24  *\r
25  *********************************************************************************/\r
26 \r
27 \r
28 #include <stdlib.h>\r
29 #include "NyLPC_cHttpBodyWriter.h"\r
30 \r
31 \r
32 \r
33 \r
34 \r
35 \r
36 static NyLPC_TBool print(void* i_inst,const char* i_fmt,va_list args);\r
37 \r
38 \r
39 void NyLPC_cHttpBodyWriter_initialize(NyLPC_TcHttpBodyWriter_t* i_inst,NyLPC_TcHttpStream_t* i_stream)\r
40 {\r
41         i_inst->_ref_stream=i_stream;\r
42         i_inst->_is_chunked=NyLPC_TUInt8_FALSE;\r
43         i_inst->_is_error=NyLPC_TUInt8_FALSE;\r
44         i_inst->_size_of_sent=0;\r
45         i_inst->_content_length=0;\r
46         NyLPC_iHttpPtrStream_setWriteEncoding(i_inst->_ref_stream,NyLPC_TiHttpPtrStream_ET_NONE);\r
47 }\r
48 \r
49 void NyLPC_cHttpBodyWriter_setChunked(NyLPC_TcHttpBodyWriter_t* i_inst)\r
50 {\r
51         i_inst->_is_chunked=NyLPC_TUInt8_TRUE;\r
52         NyLPC_iHttpPtrStream_setWriteEncoding(i_inst->_ref_stream,NyLPC_TiHttpPtrStream_ET_CHUNKED);\r
53 }\r
54 void NyLPC_cHttpBodyWriter_setContentLength(NyLPC_TcHttpBodyWriter_t* i_inst,NyLPC_TUInt32 i_content_length)\r
55 {\r
56         i_inst->_is_chunked=NyLPC_TUInt8_FALSE;\r
57         i_inst->_content_length=i_content_length;\r
58         NyLPC_iHttpPtrStream_setWriteEncoding(i_inst->_ref_stream,NyLPC_TiHttpPtrStream_ET_NONE);\r
59 }\r
60 \r
61 \r
62 /**\r
63  * HttpBodyを書き込みます。\r
64  * @return\r
65  * 偽を返した場合は、コネクションを切断してください。\r
66  */\r
67 NyLPC_TBool NyLPC_cHttpBodyWriter_write(NyLPC_TcHttpBodyWriter_t* i_inst,const void* i_buf,NyLPC_TUInt32 i_len)\r
68 {\r
69         //エラー状態ならFALSE\r
70         if(i_inst->_is_error){\r
71                 return NyLPC_TBool_FALSE;\r
72         }\r
73         i_inst->_size_of_sent+=i_len;\r
74         if(!NyLPC_iHttpPtrStream_write(i_inst->_ref_stream,i_buf,i_len)){\r
75                 i_inst->_is_error=NyLPC_TUInt8_TRUE;\r
76                 return NyLPC_TBool_FALSE;\r
77         }\r
78         return NyLPC_TBool_TRUE;\r
79 }\r
80 /**\r
81  * HttpBodyの書き込みを完了します。\r
82  * @return\r
83  */\r
84 NyLPC_TBool NyLPC_cHttpBodyWriter_close(NyLPC_TcHttpBodyWriter_t* i_inst)\r
85 {\r
86         //エラー状態ならFALSE\r
87         if(i_inst->_is_error){\r
88                 return NyLPC_TBool_FALSE;\r
89         }\r
90         //chunkedの場合、フッタを書き込む\r
91         if(i_inst->_is_chunked){\r
92                 //エンコーディングを戻す。\r
93                 NyLPC_iHttpPtrStream_setWriteEncoding(i_inst->_ref_stream,NyLPC_TiHttpPtrStream_ET_NONE);\r
94                 //フッタを書き込む。\r
95                 if(!NyLPC_iHttpPtrStream_write(i_inst->_ref_stream,"0\r\n\r\n",5)){\r
96                         i_inst->_is_error=NyLPC_TUInt8_TRUE;\r
97                         return NyLPC_TBool_FALSE;\r
98                 }\r
99         }\r
100         //エラーでないときはストリームをフラッシュ\r
101         NyLPC_iHttpPtrStream_flush(i_inst->_ref_stream);\r
102         //クローズのステータスで状態を変える。\r
103         return NyLPC_TBool_TRUE;\r
104 }\r
105 \r
106 /**\r
107  * printfライクな書式出力を提供します。\r
108  * @i_fmt\r
109  * 書式文字列です。%d,%x,%s,%c,%%をサポートします。\r
110  */\r
111 NyLPC_TBool NyLPC_cHttpBodyWriter_format(NyLPC_TcHttpBodyWriter_t* i_inst,const NyLPC_TChar* i_fmt,...)\r
112 {\r
113         NyLPC_TBool ret;\r
114         va_list a;\r
115         //エラー状態ならFALSE\r
116         if(i_inst->_is_error){\r
117                 return NyLPC_TBool_FALSE;\r
118         }\r
119         va_start(a,i_fmt);\r
120         ret=print(i_inst,i_fmt,a);\r
121         va_end(a);\r
122         return ret;\r
123 }\r
124 \r
125 NyLPC_TBool NyLPC_cHttpBodyWriter_formatV(NyLPC_TcHttpBodyWriter_t* i_inst,const NyLPC_TChar* i_fmt,va_list i_args)\r
126 {\r
127         NyLPC_TBool ret;\r
128         //エラー状態ならFALSE\r
129         if(i_inst->_is_error){\r
130                 return NyLPC_TBool_FALSE;\r
131         }\r
132         ret=print(i_inst,i_fmt,i_args);\r
133         return ret;\r
134 }\r
135 \r
136 #define NUM_OF_WORK 16\r
137 \r
138 static NyLPC_TBool print(void* i_inst,const char* i_fmt,va_list args)\r
139 {\r
140         const char* rp=i_fmt;\r
141         const char* sp;\r
142         char wk[NUM_OF_WORK];\r
143         NyLPC_TUInt32 ut;\r
144         int ol=0;\r
145         while(*rp!='\0'){\r
146                 if(*rp=='%'){\r
147                         rp++;\r
148                         switch (*rp){\r
149                         case 's':\r
150                                 sp=va_arg(args,const char*);\r
151                                 while(*sp!=0){\r
152                                         wk[ol]=*sp;\r
153                                         ol++;\r
154                                         sp++;\r
155                                         //バッファフルなら書込み。\r
156                                         if(ol>=NUM_OF_WORK){\r
157                                                 NyLPC_cHttpBodyWriter_write((NyLPC_TcHttpBodyWriter_t*)i_inst,wk,NUM_OF_WORK);\r
158                                                 ol=0;\r
159                                         }\r
160                                 }\r
161                                 rp++;\r
162                                 continue;\r
163                         case 'c':\r
164                                 wk[ol]=(char)va_arg(args,int);\r
165                                 rp++;\r
166                                 ol++;\r
167                                 break;\r
168                         case 'd':\r
169                                 //ワークを空にする。\r
170                                 if(ol>0){\r
171                                         NyLPC_cHttpBodyWriter_write((NyLPC_TcHttpBodyWriter_t*)i_inst,wk,ol);\r
172                                         ol=0;\r
173                                 }\r
174                                 NyLPC_itoa((va_arg(args,int)),wk,10);\r
175                                 //強制コミット\r
176                                 NyLPC_cHttpBodyWriter_write((NyLPC_TcHttpBodyWriter_t*)i_inst,wk,strlen(wk));\r
177                                 rp++;\r
178                                 continue;\r
179                         case 'u':\r
180                                 //ワークを空にする。\r
181                                 if(ol>0){\r
182                                         NyLPC_cHttpBodyWriter_write((NyLPC_TcHttpBodyWriter_t*)i_inst,wk,ol);\r
183                                 }\r
184                                 ut=va_arg(args,NyLPC_TUInt32);\r
185                                 ol=15;\r
186                                 wk[ol--]='\0';\r
187                                 do{\r
188                                         wk[ol--]='0'+(ut%10);\r
189                                         ut/=10;\r
190                                 }while(ut>0);\r
191                                 NyLPC_cHttpBodyWriter_write((NyLPC_TcHttpBodyWriter_t*)i_inst,(wk+ol+1),14-ol);\r
192                                 ol=0;\r
193                                 rp++;\r
194                                 continue;\r
195                         case 'x':\r
196                                 //ワークを空にする。\r
197                                 if(ol>0){\r
198                                         NyLPC_cHttpBodyWriter_write((NyLPC_TcHttpBodyWriter_t*)i_inst,wk,ol);\r
199                                         ol=0;\r
200                                 }\r
201                                 NyLPC_itoa((va_arg(args,int)),wk,16);\r
202                                 //強制コミット\r
203                                 NyLPC_cHttpBodyWriter_write((NyLPC_TcHttpBodyWriter_t*)i_inst,wk,strlen(wk));\r
204                                 rp++;\r
205                                 continue;\r
206 //                      case 'X':\r
207                         case '%':\r
208                                 wk[ol]='%';\r
209                                 ol++;\r
210                                 rp++;\r
211                                 break;\r
212                         case '\0':\r
213                                 //オワタ(ループ抜けるためにrpはそのまま。)\r
214                                 break;\r
215                         default:\r
216                                 wk[ol]=*rp;\r
217                                 ol++;\r
218                         }\r
219                         //バッファフルなら書込み。\r
220                         if(ol>=NUM_OF_WORK){\r
221                                 NyLPC_cHttpBodyWriter_write((NyLPC_TcHttpBodyWriter_t*)i_inst,wk,NUM_OF_WORK);\r
222                                 ol=0;\r
223                         }\r
224                 }else if(*rp==0){\r
225                         //オワタ\r
226                         break;\r
227                 }else{\r
228                         wk[ol]=*rp;\r
229                         ol++;\r
230                         rp++;\r
231                         if(ol>=NUM_OF_WORK){\r
232                                 NyLPC_cHttpBodyWriter_write((NyLPC_TcHttpBodyWriter_t*)i_inst,wk,NUM_OF_WORK);\r
233                                 ol=0;\r
234                         }\r
235                 }\r
236         }\r
237         //どこかでエラーが起こってればFALSE返す。\r
238         return NyLPC_cHttpBodyWriter_write((NyLPC_TcHttpBodyWriter_t*)i_inst,wk,ol);\r
239 }\r
240 \r
241 \r
242 \r
243 /**\r
244  * テスト用のコード。\r
245  */\r
246 #define TEST\r
247 #ifndef TEST\r
248 //テスト\r
249 #include "NyLPC_cHttpHeaderWriter.h"\r
250 \r
251 const char* TP1=\r
252                 "HTTP/0.9 200 OK\r\n"\r
253                 "HOST: 127.0.0.0.0.0.1\r\n"\r
254                 "CONTENt-LENGTH: 1285\r\n"\r
255                 "CONNECTION: CloSe\r\n"\r
256                 "ETAG: nyatla.jp\r\n"\r
257                 "ETAG: nyatla.jp\r\n"\r
258                 "Transfer-Encoding:chunked\r\n"\r
259                 "\r\n";\r
260 const char* TP2=\r
261                 "GET /nyanyanya!/nyoronnnnnnnnnnnn?m,fpeofjregnoegnr HTTP/1.1\r\n"\r
262                 "HOST: 127.0.0.0.0.0.1\r\n"\r
263                 "CONTENt-LENGTH: 1285\r\n"\r
264                 "CONNECTION: Keep\r\n"\r
265                 "ETAG: nyatla.jp\r\n"\r
266                 "ETAG: nyatla.jp\r\n"\r
267                 "\r\n";\r
268 const char* DT="0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789";\r
269 \r
270 \r
271 \r
272 \r
273 \r
274 \r
275 void main()\r
276 {\r
277         NyLPC_TcHttpStream_t st;\r
278         NyLPC_TcHttpBasicHeaderParser_t hp;\r
279         struct NyLPC_THttpBasicHeader reqheader;\r
280         NyLPC_TcHttpHeaderWriter_t hw;\r
281         NyLPC_TcHttpBodyWriter_t bw;\r
282         NyLPC_TcTcpSocket_t ts;\r
283         int body_len;\r
284         NyLPC_cTcpSocket_initialized(NULL,TP2,strlen(TP2));\r
285 \r
286         //TCPのオープン\r
287         if(!NyLPC_cHttpStream_initialize(&st,&ts)){\r
288                 //エラー\r
289         }\r
290         for(;;){\r
291                 //ヘッダ解析\r
292                 NyLPC_cHttpBasicHeaderParser_initialize(&hp);\r
293                 if(!NyLPC_cHttpShortRequestHeaderParser_parse(&hp,&st,&reqheader)){\r
294                         //エラー\r
295                         puts("Error");\r
296                 }\r
297                 //ヘッダの内容確認\r
298                 if(reqheader.type!=NyLPC_THttpHeaderType_REQUEST){\r
299                         //BadRequest\r
300                         puts("Error");\r
301                 }\r
302                 if(reqheader.startline.req.method!=NyLPC_THttpMethodType_GET){\r
303                         //リクエストサポートしてない\r
304                         puts("Error");\r
305                 }\r
306                 //\r
307                 NyLPC_cHttpHeaderWriter_initialize(&hw,&st,&reqheader);\r
308 //              NyLPC_cHttpResponseWriter_setClose(&hw);\r
309                 body_len=100;\r
310                 NyLPC_cHttpHeaderWriter_setContentLength(&hw,body_len);\r
311                 NyLPC_cHttpHeaderWriter_writeHeader(&hw,500);\r
312                 NyLPC_cHttpHeaderWriter_close(&hw);\r
313 \r
314                 NyLPC_cHttpBodyWriter_initialize(&bw,&st);\r
315                 NyLPC_cHttpBodyWriter_setChunked(&bw);\r
316                 NyLPC_cHttpBodyWriter_write(&bw,"TEST",4);\r
317                 NyLPC_cHttpBodyWriter_printf(&bw,"TEST");\r
318                 NyLPC_cHttpBodyWriter_printf(&bw,"TEST[%s][%d][%c],%%,[%x]","abcde",123,'s',0xff0011);\r
319                 NyLPC_cHttpBodyWriter_close(&bw);\r
320                 NyLPC_cHttpHttpWriter_finalize(&hw);\r
321         }\r
322         NyLPC_cHttpStream_finalize(&st);\r
323         //TCPのクローズ\r
324         return;\r
325 }\r
326 #endif\r