gwenhywfar 4.0.3
|
00001 /*************************************************************************** 00002 begin : Wed Apr 28 2010 00003 copyright : (C) 2010 by Martin Preuss 00004 email : martin@libchipcard.de 00005 00006 *************************************************************************** 00007 * * 00008 * This library is free software; you can redistribute it and/or * 00009 * modify it under the terms of the GNU Lesser General Public * 00010 * License as published by the Free Software Foundation; either * 00011 * version 2.1 of the License, or (at your option) any later version. * 00012 * * 00013 * This library is distributed in the hope that it will be useful, * 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00016 * Lesser General Public License for more details. * 00017 * * 00018 * You should have received a copy of the GNU Lesser General Public * 00019 * License along with this library; if not, write to the Free Software * 00020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * 00021 * MA 02111-1307 USA * 00022 * * 00023 ***************************************************************************/ 00024 00025 #ifdef HAVE_CONFIG_H 00026 # include <config.h> 00027 #endif 00028 00029 #define DISABLE_DEBUGLOG 00030 00031 00032 00033 #include "syncio_http_p.h" 00034 #include "i18n_l.h" 00035 00036 #include <gwenhywfar/misc.h> 00037 #include <gwenhywfar/debug.h> 00038 #include <gwenhywfar/gui.h> 00039 #include <gwenhywfar/text.h> 00040 00041 #include <assert.h> 00042 #include <errno.h> 00043 #include <string.h> 00044 #include <ctype.h> 00045 00046 00047 00048 GWEN_INHERIT(GWEN_SYNCIO, GWEN_SYNCIO_HTTP) 00049 00050 00051 00052 GWEN_SYNCIO *GWEN_SyncIo_Http_new(GWEN_SYNCIO *baseIo) { 00053 GWEN_SYNCIO *sio; 00054 GWEN_SYNCIO_HTTP *xio; 00055 00056 sio=GWEN_SyncIo_new(GWEN_SYNCIO_HTTP_TYPE, baseIo); 00057 GWEN_NEW_OBJECT(GWEN_SYNCIO_HTTP, xio); 00058 GWEN_INHERIT_SETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio, xio, GWEN_SyncIo_Http_FreeData); 00059 00060 GWEN_SyncIo_SetConnectFn(sio, GWEN_SyncIo_Http_Connect); 00061 GWEN_SyncIo_SetDisconnectFn(sio, GWEN_SyncIo_Http_Disconnect); 00062 GWEN_SyncIo_SetReadFn(sio, GWEN_SyncIo_Http_Read); 00063 GWEN_SyncIo_SetWriteFn(sio, GWEN_SyncIo_Http_Write); 00064 00065 xio->dbCommandIn=GWEN_DB_Group_new("command"); 00066 xio->dbStatusIn=GWEN_DB_Group_new("status"); 00067 xio->dbHeaderIn=GWEN_DB_Group_new("header"); 00068 00069 xio->dbCommandOut=GWEN_DB_Group_new("command"); 00070 xio->dbStatusOut=GWEN_DB_Group_new("status"); 00071 xio->dbHeaderOut=GWEN_DB_Group_new("header"); 00072 00073 00074 return sio; 00075 } 00076 00077 00078 00079 void GWENHYWFAR_CB GWEN_SyncIo_Http_FreeData(void *bp, void *p) { 00080 GWEN_SYNCIO_HTTP *xio; 00081 00082 xio=(GWEN_SYNCIO_HTTP*) p; 00083 00084 GWEN_DB_Group_free(xio->dbCommandOut); 00085 GWEN_DB_Group_free(xio->dbStatusOut); 00086 GWEN_DB_Group_free(xio->dbHeaderOut); 00087 00088 GWEN_DB_Group_free(xio->dbCommandIn); 00089 GWEN_DB_Group_free(xio->dbStatusIn); 00090 GWEN_DB_Group_free(xio->dbHeaderIn); 00091 00092 GWEN_FREE_OBJECT(xio); 00093 } 00094 00095 00096 00097 int GWENHYWFAR_CB GWEN_SyncIo_Http_Connect(GWEN_SYNCIO *sio) { 00098 GWEN_SYNCIO_HTTP *xio; 00099 GWEN_SYNCIO *baseIo; 00100 int rv; 00101 00102 assert(sio); 00103 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00104 assert(xio); 00105 00106 if (GWEN_SyncIo_GetStatus(sio)==GWEN_SyncIo_Status_Connected) { 00107 DBG_INFO(GWEN_LOGDOMAIN, "Already connected"); 00108 return 0; 00109 } 00110 00111 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00112 assert(baseIo); 00113 00114 rv=GWEN_SyncIo_Connect(baseIo); 00115 if (rv<0) { 00116 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00117 return rv; 00118 } 00119 00120 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Connected); 00121 GWEN_SyncIo_Http_SetReadIdle(sio); 00122 00123 return 0; 00124 } 00125 00126 00127 00128 int GWENHYWFAR_CB GWEN_SyncIo_Http_Disconnect(GWEN_SYNCIO *sio) { 00129 GWEN_SYNCIO_HTTP *xio; 00130 GWEN_SYNCIO *baseIo; 00131 int rv; 00132 00133 assert(sio); 00134 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00135 assert(xio); 00136 00137 if (GWEN_SyncIo_GetStatus(sio)!=GWEN_SyncIo_Status_Connected) { 00138 DBG_INFO(GWEN_LOGDOMAIN, "Not connected"); 00139 return GWEN_ERROR_NOT_CONNECTED; 00140 } 00141 00142 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00143 assert(baseIo); 00144 00145 rv=GWEN_SyncIo_Disconnect(baseIo); 00146 GWEN_SyncIo_SetStatus(sio, GWEN_SyncIo_Status_Disconnected); 00147 if (rv<0) { 00148 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00149 return rv; 00150 } 00151 00152 return 0; 00153 } 00154 00155 00156 00157 void GWEN_SyncIo_Http_SetReadIdle(GWEN_SYNCIO *sio) { 00158 GWEN_SYNCIO_HTTP *xio; 00159 00160 assert(sio); 00161 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00162 assert(xio); 00163 00164 xio->readMode=GWEN_SyncIo_Http_Mode_Idle; 00165 } 00166 00167 00168 00169 int GWENHYWFAR_CB GWEN_SyncIo_Http_Read(GWEN_SYNCIO *sio, 00170 uint8_t *buffer, 00171 uint32_t size) { 00172 GWEN_SYNCIO_HTTP *xio; 00173 int rv; 00174 00175 assert(sio); 00176 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00177 assert(xio); 00178 00179 if (GWEN_SyncIo_GetStatus(sio)!=GWEN_SyncIo_Status_Connected) { 00180 DBG_ERROR(GWEN_LOGDOMAIN, "Not connected"); 00181 return GWEN_ERROR_NOT_CONNECTED; 00182 } 00183 00184 if (xio->readMode==GWEN_SyncIo_Http_Mode_Idle) { 00185 const char *s; 00186 00187 /* reset status and headers */ 00188 GWEN_DB_ClearGroup(xio->dbCommandIn, NULL); 00189 GWEN_DB_ClearGroup(xio->dbStatusIn, NULL); 00190 GWEN_DB_ClearGroup(xio->dbHeaderIn, NULL); 00191 00192 if (GWEN_SyncIo_GetFlags(sio) & GWEN_SYNCIO_FLAGS_PASSIVE) { 00193 /* read command */ 00194 rv=GWEN_SyncIo_Http_ReadCommand(sio); 00195 if (rv<0) { 00196 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00197 xio->readMode=GWEN_SyncIo_Http_Mode_Error; 00198 return rv; 00199 } 00200 00201 /* possibly read header */ 00202 s=GWEN_DB_GetCharValue(xio->dbCommandIn, "protocol", 0, "HTTP/1.0"); 00203 if (!(s && strcasecmp(s, "HTTP/0.9")==0)) { 00204 rv=GWEN_SyncIo_Http_ReadHeader(sio); 00205 if (rv<0) { 00206 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00207 xio->readMode=GWEN_SyncIo_Http_Mode_Error; 00208 return rv; 00209 } 00210 } 00211 } 00212 else { 00213 /* read status */ 00214 rv=GWEN_SyncIo_Http_ReadStatus(sio); 00215 if (rv<0) { 00216 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00217 xio->readMode=GWEN_SyncIo_Http_Mode_Error; 00218 return rv; 00219 } 00220 00221 /* possibly read header */ 00222 s=GWEN_DB_GetCharValue(xio->dbStatusIn, "protocol", 0, "HTTP/1.0"); 00223 if (!(s && strcasecmp(s, "HTTP/0.9")==0)) { 00224 rv=GWEN_SyncIo_Http_ReadHeader(sio); 00225 if (rv<0) { 00226 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00227 xio->readMode=GWEN_SyncIo_Http_Mode_Error; 00228 return rv; 00229 } 00230 } 00231 } 00232 00233 } 00234 00235 if (xio->readMode==GWEN_SyncIo_Http_Mode_ChunkSize) { 00236 rv=GWEN_SyncIo_Http_ReadChunkSize(sio); 00237 if (rv<0) { 00238 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00239 xio->readMode=GWEN_SyncIo_Http_Mode_Error; 00240 return rv; 00241 } 00242 if (xio->currentReadChunkSize==0) { 00243 /* chunksize is 0, body ended */ 00244 GWEN_SyncIo_Http_SetReadIdle(sio); 00245 return 0; 00246 } 00247 else if (xio->currentReadChunkSize==-1) { 00248 DBG_ERROR(GWEN_LOGDOMAIN, "Undetermined chunksize in chunked mode? Aborting."); 00249 xio->readMode=GWEN_SyncIo_Http_Mode_Error; 00250 return GWEN_ERROR_BAD_DATA; 00251 } 00252 00253 /* chunksize known, next will be to read that chunk */ 00254 xio->readMode=GWEN_SyncIo_Http_Mode_Chunk; 00255 } 00256 00257 if (xio->readMode==GWEN_SyncIo_Http_Mode_Chunk) { 00258 /* read chunk */ 00259 rv=GWEN_SyncIo_Http_ReadChunk(sio, buffer, size); 00260 if (rv<0) { 00261 xio->readMode=GWEN_SyncIo_Http_Mode_Error; 00262 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00263 return rv; 00264 } 00265 00266 return rv; 00267 } 00268 00269 if (xio->readMode==GWEN_SyncIo_Http_Mode_Body) { 00270 /* read chunk */ 00271 rv=GWEN_SyncIo_Http_ReadBody(sio, buffer, size); 00272 if (rv<0) { 00273 xio->readMode=GWEN_SyncIo_Http_Mode_Error; 00274 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00275 return rv; 00276 } 00277 00278 return rv; 00279 } 00280 00281 if (xio->readMode==GWEN_SyncIo_Http_Mode_Error) { 00282 DBG_ERROR(GWEN_LOGDOMAIN, "Previous read error"); 00283 return GWEN_ERROR_GENERIC; 00284 } 00285 00286 return 0; 00287 } 00288 00289 00290 00291 int GWENHYWFAR_CB GWEN_SyncIo_Http_Write(GWEN_SYNCIO *sio, 00292 const uint8_t *buffer, 00293 uint32_t size) { 00294 GWEN_SYNCIO_HTTP *xio; 00295 GWEN_SYNCIO *baseIo; 00296 int rv; 00297 00298 assert(sio); 00299 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00300 assert(xio); 00301 00302 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00303 assert(baseIo); 00304 00305 if (GWEN_SyncIo_GetStatus(sio)!=GWEN_SyncIo_Status_Connected) { 00306 DBG_ERROR(GWEN_LOGDOMAIN, "Not connected"); 00307 return GWEN_ERROR_NOT_CONNECTED; 00308 } 00309 00310 if (xio->writeMode==GWEN_SyncIo_Http_Mode_Idle) { 00311 const char *s; 00312 00313 if (GWEN_SyncIo_GetFlags(sio) & GWEN_SYNCIO_FLAGS_PASSIVE) 00314 /* write status */ 00315 rv=GWEN_SyncIo_Http_WriteStatus(sio); 00316 else 00317 /* write command */ 00318 rv=GWEN_SyncIo_Http_WriteCommand(sio); 00319 if (rv<0) { 00320 xio->writeMode=GWEN_SyncIo_Http_Mode_Error; 00321 return rv; 00322 } 00323 00324 /* possibly write header */ 00325 s=GWEN_DB_GetCharValue(xio->dbCommandOut, "protocol", 0, "HTTP/1.0"); 00326 if (!(s && strcasecmp(s, "HTTP/0.9")==0)) { 00327 rv=GWEN_SyncIo_Http_WriteHeader(sio); 00328 if (rv<0) { 00329 xio->writeMode=GWEN_SyncIo_Http_Mode_Error; 00330 return rv; 00331 } 00332 } 00333 } 00334 00335 if (xio->writeMode==GWEN_SyncIo_Http_Mode_ChunkSize) { 00336 rv=GWEN_SyncIo_Http_WriteChunkSize(sio, size); 00337 if (rv<0) { 00338 xio->writeMode=GWEN_SyncIo_Http_Mode_Error; 00339 return rv; 00340 } 00341 if (size==0) { 00342 /* chunksize is 0, body ended */ 00343 GWEN_SyncIo_Http_SetWriteIdle(sio); 00344 return 0; 00345 } 00346 00347 /* chunksize known, next will be to write that chunk */ 00348 xio->writeMode=GWEN_SyncIo_Http_Mode_Chunk; 00349 } 00350 00351 if (xio->writeMode==GWEN_SyncIo_Http_Mode_Chunk) { 00352 /* we want to write binary data transparently */ 00353 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT); 00354 rv=GWEN_SyncIo_WriteForced(baseIo, buffer, size); 00355 if (rv<0) { 00356 xio->writeMode=GWEN_SyncIo_Http_Mode_Error; 00357 return rv; 00358 } 00359 xio->writeMode=GWEN_SyncIo_Http_Mode_ChunkSize; 00360 00361 return rv; 00362 } 00363 00364 if (xio->writeMode==GWEN_SyncIo_Http_Mode_Body) { 00365 if ((xio->currentWriteBodySize!=-1) && 00366 (size>xio->currentWriteBodySize)) { 00367 DBG_ERROR(GWEN_LOGDOMAIN, "Size is beyond total body size (%d)!", size); 00368 xio->writeMode=GWEN_SyncIo_Http_Mode_Error; 00369 return GWEN_ERROR_INVALID; 00370 } 00371 00372 /* we want to write binary data transparently */ 00373 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT); 00374 rv=GWEN_SyncIo_WriteForced(baseIo, buffer, size); 00375 if (rv<0) { 00376 xio->writeMode=GWEN_SyncIo_Http_Mode_Error; 00377 return rv; 00378 } 00379 if (xio->currentWriteBodySize!=-1) { 00380 xio->currentWriteBodySize-=rv; 00381 if (xio->currentWriteBodySize==0) 00382 GWEN_SyncIo_Http_SetWriteIdle(sio); 00383 } 00384 00385 return rv; 00386 } 00387 00388 if (xio->writeMode==GWEN_SyncIo_Http_Mode_Error) { 00389 DBG_ERROR(GWEN_LOGDOMAIN, "Previous write error"); 00390 return GWEN_ERROR_GENERIC; 00391 } 00392 00393 return 0; 00394 } 00395 00396 00397 00398 int GWEN_SyncIo_Http_ReadLine(GWEN_SYNCIO *sio, GWEN_BUFFER *tbuf) { 00399 GWEN_SYNCIO_HTTP *xio; 00400 GWEN_SYNCIO *baseIo; 00401 int rv; 00402 00403 assert(sio); 00404 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00405 assert(xio); 00406 00407 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00408 assert(baseIo); 00409 00410 /* we want to read a text line, so we can't have a transparent mode in the base layer */ 00411 GWEN_SyncIo_SubFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT); 00412 00413 /* read a single line */ 00414 do { 00415 uint8_t *p; 00416 uint32_t l; 00417 00418 GWEN_Buffer_AllocRoom(tbuf, 1024); 00419 p=(uint8_t*) GWEN_Buffer_GetPosPointer(tbuf); 00420 l=GWEN_Buffer_GetMaxUnsegmentedWrite(tbuf); 00421 rv=GWEN_SyncIo_Read(baseIo, p, l); 00422 if (rv<0) { 00423 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00424 return rv; 00425 } 00426 else if (rv>0) { 00427 GWEN_Buffer_IncrementPos(tbuf, rv); 00428 GWEN_Buffer_AdjustUsedBytes(tbuf); 00429 if (p[rv-1]==10) { 00430 p[rv-1]=0; 00431 break; 00432 } 00433 } 00434 else if (rv==0) 00435 break; 00436 } while(rv>0); 00437 00438 if (GWEN_Buffer_GetUsedBytes(tbuf)<1) { 00439 DBG_ERROR(GWEN_LOGDOMAIN, "Nothing received"); 00440 return GWEN_ERROR_EOF; 00441 } 00442 00443 return 0; 00444 } 00445 00446 00447 00448 int GWEN_SyncIo_Http_ParseStatus(GWEN_SYNCIO *sio, char *buffer) { 00449 GWEN_SYNCIO_HTTP *xio; 00450 char *p; 00451 char *s; 00452 int code; 00453 00454 assert(sio); 00455 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00456 assert(xio); 00457 00458 s=buffer; 00459 00460 /* read protocol */ 00461 p=strchr(s, ' '); 00462 if (!p) { 00463 DBG_ERROR(GWEN_LOGDOMAIN, 00464 "Bad format of HTTP status (%s)", buffer); 00465 return GWEN_ERROR_INVALID; 00466 } 00467 *p=0; 00468 p++; 00469 00470 GWEN_DB_SetCharValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", s); 00471 s=p; 00472 00473 /* read status code */ 00474 while(*p && isdigit((int)*p)) 00475 p++; 00476 if (*p) { 00477 *p=0; 00478 p++; 00479 } 00480 if (1!=sscanf(s, "%d", &code)) { 00481 DBG_ERROR(GWEN_LOGDOMAIN, "Bad request (status code \"%s\")", s); 00482 return GWEN_ERROR_INVALID; 00483 } 00484 GWEN_DB_SetIntValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "code", code); 00485 s=p; 00486 00487 /* read text */ 00488 GWEN_DB_SetCharValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "text", s); 00489 00490 return 0; 00491 } 00492 00493 00494 00495 int GWEN_SyncIo_Http_ParseCommand(GWEN_SYNCIO *sio, const char *buffer) { 00496 GWEN_SYNCIO_HTTP *xio; 00497 char *tmp; 00498 char *p; 00499 char *s; 00500 00501 assert(sio); 00502 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00503 assert(xio); 00504 00505 tmp=strdup(buffer); 00506 s=tmp; 00507 00508 /* read command */ 00509 p=strchr(s, ' '); 00510 if (!p) { 00511 DBG_ERROR(GWEN_LOGDOMAIN, 00512 "Bad format of HTTP request (%s)", buffer); 00513 free(tmp); 00514 return GWEN_ERROR_INVALID; 00515 } 00516 *p=0; 00517 p++; 00518 00519 GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "command", s); 00520 s=p; 00521 00522 /* read URL */ 00523 p=strchr(s, ' '); 00524 if (!p) { 00525 DBG_ERROR(GWEN_LOGDOMAIN, 00526 "Bad format of HTTP request (%s)", buffer); 00527 free(tmp); 00528 return GWEN_ERROR_INVALID; 00529 } 00530 *p=0; 00531 p++; 00532 00533 GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "url", s); 00534 s=p; 00535 00536 if (*s==0) { 00537 /* no protocol information follows, so we assume HTTP/0.9 */ 00538 DBG_ERROR(GWEN_LOGDOMAIN, "Bad request (not in HTTP>=1.0)"); 00539 free(tmp); 00540 return GWEN_ERROR_INVALID; 00541 } 00542 else { 00543 GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", s); 00544 } 00545 00546 free(tmp); 00547 return 0; 00548 } 00549 00550 00551 00552 int GWEN_SyncIo_Http_ReadStatus(GWEN_SYNCIO *sio) { 00553 GWEN_SYNCIO_HTTP *xio; 00554 GWEN_SYNCIO *baseIo; 00555 GWEN_BUFFER *tbuf; 00556 int rv; 00557 00558 assert(sio); 00559 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00560 assert(xio); 00561 00562 DBG_INFO(GWEN_LOGDOMAIN, "Reading status"); 00563 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00564 assert(baseIo); 00565 00566 /* read a single line */ 00567 tbuf=GWEN_Buffer_new(0, 256, 0, 1); 00568 rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf); 00569 if (rv<0) { 00570 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00571 GWEN_Buffer_free(tbuf); 00572 return rv; 00573 } 00574 00575 if (*GWEN_Buffer_GetStart(tbuf)==0) { 00576 DBG_INFO(GWEN_LOGDOMAIN, "Empty line received while reading status response, assuming EOF"); 00577 GWEN_Buffer_free(tbuf); 00578 return GWEN_ERROR_EOF; 00579 } 00580 00581 rv=GWEN_SyncIo_Http_ParseStatus(sio, GWEN_Buffer_GetStart(tbuf)); 00582 if (rv<0) { 00583 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00584 GWEN_Buffer_free(tbuf); 00585 return rv; 00586 } 00587 00588 GWEN_Buffer_free(tbuf); 00589 return 0; 00590 } 00591 00592 00593 00594 int GWEN_SyncIo_Http_ReadCommand(GWEN_SYNCIO *sio) { 00595 GWEN_SYNCIO_HTTP *xio; 00596 GWEN_SYNCIO *baseIo; 00597 GWEN_BUFFER *tbuf; 00598 int rv; 00599 00600 assert(sio); 00601 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00602 assert(xio); 00603 00604 DBG_INFO(GWEN_LOGDOMAIN, "Reading command"); 00605 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00606 assert(baseIo); 00607 00608 /* read a single line */ 00609 tbuf=GWEN_Buffer_new(0, 256, 0, 1); 00610 rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf); 00611 if (rv<0) { 00612 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00613 GWEN_Buffer_free(tbuf); 00614 return rv; 00615 } 00616 00617 rv=GWEN_SyncIo_Http_ParseCommand(sio, GWEN_Buffer_GetStart(tbuf)); 00618 if (rv<0) { 00619 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00620 GWEN_Buffer_free(tbuf); 00621 return rv; 00622 } 00623 00624 GWEN_Buffer_free(tbuf); 00625 return 0; 00626 } 00627 00628 00629 00630 int GWEN_SyncIo_Http_ParseHeader(GWEN_SYNCIO *sio, char *buf) { 00631 GWEN_SYNCIO_HTTP *xio; 00632 GWEN_SYNCIO *baseIo; 00633 char *p; 00634 const char *s; 00635 00636 assert(sio); 00637 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00638 assert(xio); 00639 00640 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00641 assert(baseIo); 00642 00643 /* resolve line continuations */ 00644 p=buf; 00645 while(*p) { 00646 p=strchr(p, 10); 00647 if (p) { 00648 if (p[1]==32 || p[1]==9) 00649 /* found a continuation */ 00650 *p=32; 00651 p++; 00652 } 00653 } 00654 00655 /* parse every line */ 00656 p=buf; 00657 while(p && *p) { 00658 char *pNext; 00659 char *pVarBegin; 00660 char *pVarEnd; 00661 00662 /* skip blanks */ 00663 pNext=strchr(p, 10); 00664 if (pNext) { 00665 *pNext=0; 00666 pNext++; 00667 } 00668 while(*p && (*p==32 || *p==9)) 00669 p++; 00670 if (*p) { 00671 pVarBegin=p; 00672 while(*p && *p!=':' && *p>32 && *p<127) 00673 p++; 00674 pVarEnd=p; 00675 if (*p!=':') { 00676 DBG_INFO(GWEN_LOGDOMAIN, "No separator after variable name in received header"); 00677 return GWEN_ERROR_BAD_DATA; 00678 } 00679 *pVarEnd=0; 00680 p++; 00681 00682 while(*p && (*p==32 || *p==9)) 00683 p++; 00684 if (*p) 00685 GWEN_DB_SetCharValue(xio->dbHeaderIn, GWEN_PATH_FLAGS_CREATE_VAR, pVarBegin, p); 00686 } 00687 p=pNext; 00688 } 00689 00690 /* default next mode after reading the header is reading the body 00691 * (if any, but that will be checked later) */ 00692 xio->readMode=GWEN_SyncIo_Http_Mode_Body; 00693 00694 /* header received, now read some settings from it */ 00695 s=GWEN_DB_GetCharValue(xio->dbHeaderIn, "Transfer-Encoding", 0, 0); 00696 if (s && (-1!=GWEN_Text_ComparePattern(s, "*chunked*", 0))) { 00697 /* chunked encoding, this means next we have to read the chunksize */ 00698 xio->currentReadChunkSize=-1; 00699 xio->readMode=GWEN_SyncIo_Http_Mode_ChunkSize; 00700 } 00701 00702 /* get size of body */ 00703 xio->currentReadBodySize=GWEN_DB_GetIntValue(xio->dbHeaderIn, "Content-Length", 0, -1); 00704 if (xio->currentReadBodySize==0) { 00705 /* no body */ 00706 GWEN_SyncIo_Http_SetReadIdle(sio); 00707 } 00708 else if (xio->currentReadBodySize==-1) { 00709 int rcode; 00710 00711 /* no length of body received, assume 0 in case of an error 00712 * This eliminates the bug where this module waits for 00713 * a timeout when receiving an error from a special server 00714 */ 00715 rcode=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, -1); 00716 if (rcode<0 || rcode>=300) { 00717 /* no body */ 00718 GWEN_SyncIo_Http_SetReadIdle(sio); 00719 } 00720 } 00721 00722 return 0; 00723 } 00724 00725 00726 00727 int GWEN_SyncIo_Http_ReadHeader(GWEN_SYNCIO *sio) { 00728 GWEN_SYNCIO_HTTP *xio; 00729 GWEN_SYNCIO *baseIo; 00730 GWEN_BUFFER *tbuf; 00731 int rv; 00732 uint32_t pos; 00733 int lines=0; 00734 00735 assert(sio); 00736 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00737 assert(xio); 00738 00739 DBG_INFO(GWEN_LOGDOMAIN, "Reading header"); 00740 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00741 assert(baseIo); 00742 00743 /* we want to read a text line, so we can't have a transparent mode in the base layer */ 00744 GWEN_SyncIo_SubFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT); 00745 00746 /* read a single line */ 00747 tbuf=GWEN_Buffer_new(0, 256, 0, 1); 00748 pos=0; 00749 do { 00750 uint8_t *p; 00751 00752 GWEN_Buffer_AllocRoom(tbuf, 1024); 00753 p=(uint8_t*) GWEN_Buffer_GetPosPointer(tbuf); 00754 rv=GWEN_SyncIo_Read(baseIo, p, 1024); 00755 if (rv<0) { 00756 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00757 GWEN_Buffer_free(tbuf); 00758 return rv; 00759 } 00760 else if (rv>0) { 00761 GWEN_Buffer_IncrementPos(tbuf, rv); 00762 GWEN_Buffer_AdjustUsedBytes(tbuf); 00763 if (p[rv-1]==10) { 00764 uint32_t npos; 00765 00766 lines++; 00767 npos=GWEN_Buffer_GetPos(tbuf); 00768 if ((npos-pos)==1) { 00769 /* empty line, header finished */ 00770 break; 00771 } 00772 pos=npos; 00773 } 00774 } 00775 else if (rv==0) 00776 break; 00777 } while(rv>0); 00778 00779 if (lines<1) { 00780 DBG_ERROR(GWEN_LOGDOMAIN, "No header line received"); 00781 GWEN_Buffer_free(tbuf); 00782 return GWEN_ERROR_EOF; 00783 } 00784 00785 rv=GWEN_SyncIo_Http_ParseHeader(sio, GWEN_Buffer_GetStart(tbuf)); 00786 if (rv<0) { 00787 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00788 GWEN_Buffer_free(tbuf); 00789 return rv; 00790 } 00791 00792 GWEN_Buffer_free(tbuf); 00793 return 0; 00794 } 00795 00796 00797 00798 int GWEN_SyncIo_Http_ReadChunkSize(GWEN_SYNCIO *sio) { 00799 GWEN_SYNCIO_HTTP *xio; 00800 GWEN_SYNCIO *baseIo; 00801 GWEN_BUFFER *tbuf; 00802 int rv; 00803 int csize; 00804 00805 assert(sio); 00806 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00807 assert(xio); 00808 00809 DBG_INFO(GWEN_LOGDOMAIN, "Reading chunksize"); 00810 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00811 assert(baseIo); 00812 00813 /* read a single line */ 00814 tbuf=GWEN_Buffer_new(0, 256, 0, 1); 00815 rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf); 00816 if (rv<0) { 00817 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00818 GWEN_Buffer_free(tbuf); 00819 return rv; 00820 } 00821 00822 if (*GWEN_Buffer_GetStart(tbuf)==0) { 00823 GWEN_Buffer_Reset(tbuf); 00824 rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf); 00825 if (rv<0) { 00826 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00827 GWEN_Buffer_free(tbuf); 00828 return rv; 00829 } 00830 } 00831 00832 if (1!=sscanf(GWEN_Buffer_GetStart(tbuf), "%x", &csize)) { 00833 DBG_ERROR(GWEN_LOGDOMAIN, "Bad data received (invalid chunksize specifier: [%s])", 00834 GWEN_Buffer_GetStart(tbuf)); 00835 GWEN_Buffer_free(tbuf); 00836 return GWEN_ERROR_BAD_DATA; 00837 } 00838 00839 xio->currentReadChunkSize=csize; 00840 00841 GWEN_Buffer_free(tbuf); 00842 return 0; 00843 } 00844 00845 00846 00847 int GWEN_SyncIo_Http_ReadChunk(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size) { 00848 GWEN_SYNCIO_HTTP *xio; 00849 GWEN_SYNCIO *baseIo; 00850 int rv; 00851 00852 assert(sio); 00853 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00854 assert(xio); 00855 00856 DBG_DEBUG(GWEN_LOGDOMAIN, "Reading chunk (%d bytes)", (int) size); 00857 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00858 assert(baseIo); 00859 00860 /* we want to read binary data transparently */ 00861 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT); 00862 00863 if (size>xio->currentReadChunkSize) 00864 size=xio->currentReadChunkSize; 00865 00866 rv=GWEN_SyncIo_Read(baseIo, buffer, size); 00867 if (rv<0) { 00868 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00869 return rv; 00870 } 00871 00872 xio->currentReadChunkSize-=rv; 00873 if (xio->currentReadBodySize>0) 00874 xio->currentReadBodySize-=rv; 00875 00876 if (xio->currentReadChunkSize==0) 00877 /* chunk finished, change read mode */ 00878 xio->readMode=GWEN_SyncIo_Http_Mode_ChunkSize; 00879 00880 return rv; 00881 } 00882 00883 00884 00885 int GWEN_SyncIo_Http_ReadBody(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size) { 00886 GWEN_SYNCIO_HTTP *xio; 00887 GWEN_SYNCIO *baseIo; 00888 int rv; 00889 00890 assert(size); 00891 00892 assert(sio); 00893 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00894 assert(xio); 00895 00896 DBG_INFO(GWEN_LOGDOMAIN, "Reading body"); 00897 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00898 assert(baseIo); 00899 00900 /* we want to read binary data transparently */ 00901 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT); 00902 00903 if ((xio->currentReadBodySize>=0) && 00904 (size>xio->currentReadBodySize)) { 00905 DBG_INFO(GWEN_LOGDOMAIN, "Adjusting read body size from %d to %d", 00906 size, xio->currentReadBodySize); 00907 size=xio->currentReadBodySize; 00908 } 00909 00910 rv=GWEN_SyncIo_Read(baseIo, buffer, size); 00911 if (rv<0) { 00912 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00913 return rv; 00914 } 00915 00916 if (xio->currentReadBodySize>=0) 00917 xio->currentReadBodySize-=rv; 00918 00919 if (xio->currentReadBodySize==0) 00920 /* body finished, change read mode */ 00921 GWEN_SyncIo_Http_SetReadIdle(sio); 00922 00923 return rv; 00924 } 00925 00926 00927 00928 int GWEN_SyncIo_Http_WriteCommand(GWEN_SYNCIO *sio) { 00929 GWEN_SYNCIO_HTTP *xio; 00930 GWEN_SYNCIO *baseIo; 00931 int rv; 00932 const char *s; 00933 GWEN_BUFFER *tbuf; 00934 00935 assert(sio); 00936 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00937 assert(xio); 00938 00939 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00940 assert(baseIo); 00941 00942 /* we will construct the line including CR/LF ourselves */ 00943 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT); 00944 00945 tbuf=GWEN_Buffer_new(0, 256, 0, 1); 00946 00947 s=GWEN_DB_GetCharValue(xio->dbCommandOut, "command", 0, "GET"); 00948 GWEN_Buffer_AppendString(tbuf, s); 00949 GWEN_Buffer_AppendString(tbuf, " "); 00950 00951 s=GWEN_DB_GetCharValue(xio->dbCommandOut, "url", 0, "/"); 00952 GWEN_Buffer_AppendString(tbuf, s); 00953 GWEN_Buffer_AppendString(tbuf, " "); 00954 00955 s=GWEN_DB_GetCharValue(xio->dbCommandOut, "protocol", 0, "HTTP/1.0"); 00956 GWEN_Buffer_AppendString(tbuf, s); 00957 GWEN_Buffer_AppendString(tbuf, "\r\n"); 00958 00959 /* write */ 00960 rv=GWEN_SyncIo_WriteForced(baseIo, 00961 (const uint8_t*) GWEN_Buffer_GetStart(tbuf), 00962 GWEN_Buffer_GetUsedBytes(tbuf)); 00963 if (rv<0) { 00964 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 00965 GWEN_Buffer_free(tbuf); 00966 return rv; 00967 } 00968 00969 GWEN_Buffer_free(tbuf); 00970 return 0; 00971 } 00972 00973 00974 00975 int GWEN_SyncIo_Http_WriteStatus(GWEN_SYNCIO *sio) { 00976 GWEN_SYNCIO_HTTP *xio; 00977 GWEN_SYNCIO *baseIo; 00978 int rv; 00979 const char *s; 00980 GWEN_BUFFER *tbuf; 00981 char numbuf[32]; 00982 int i; 00983 00984 assert(sio); 00985 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 00986 assert(xio); 00987 00988 baseIo=GWEN_SyncIo_GetBaseIo(sio); 00989 assert(baseIo); 00990 00991 /* we will construct the line including CR/LF ourselves */ 00992 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT); 00993 00994 tbuf=GWEN_Buffer_new(0, 256, 0, 1); 00995 00996 s=GWEN_DB_GetCharValue(xio->dbStatusOut, "protocol", 0, "HTTP/1.0"); 00997 GWEN_Buffer_AppendString(tbuf, s); 00998 GWEN_Buffer_AppendString(tbuf, " "); 00999 01000 i=GWEN_DB_GetIntValue(xio->dbStatusOut, "code", 0, -1); 01001 if (i==-1) { 01002 DBG_INFO(GWEN_LOGDOMAIN, "Missing status code"); 01003 GWEN_Buffer_free(tbuf); 01004 return GWEN_ERROR_NO_DATA; 01005 } 01006 snprintf(numbuf, sizeof(numbuf), "%d ", i); 01007 GWEN_Buffer_AppendString(tbuf, numbuf); 01008 01009 s=GWEN_DB_GetCharValue(xio->dbStatusOut, "text", 0, "No text."); 01010 GWEN_Buffer_AppendString(tbuf, s); 01011 GWEN_Buffer_AppendString(tbuf, "\r\n"); 01012 01013 /* write */ 01014 rv=GWEN_SyncIo_WriteForced(baseIo, 01015 (const uint8_t*) GWEN_Buffer_GetStart(tbuf), 01016 GWEN_Buffer_GetUsedBytes(tbuf)); 01017 if (rv<0) { 01018 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 01019 GWEN_Buffer_free(tbuf); 01020 return rv; 01021 } 01022 01023 GWEN_Buffer_free(tbuf); 01024 return 0; 01025 } 01026 01027 01028 01029 int GWEN_SyncIo_Http_WriteHeader(GWEN_SYNCIO *sio) { 01030 GWEN_SYNCIO_HTTP *xio; 01031 GWEN_SYNCIO *baseIo; 01032 int i; 01033 GWEN_DB_NODE *dbVar; 01034 GWEN_BUFFER *tbuf; 01035 int rv; 01036 01037 assert(sio); 01038 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 01039 assert(xio); 01040 01041 baseIo=GWEN_SyncIo_GetBaseIo(sio); 01042 assert(baseIo); 01043 01044 /* we will construct the line including CR/LF ourselves */ 01045 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT); 01046 01047 /* default next mode after writing the header is writing the body 01048 * (if any, but that will be checked later) */ 01049 xio->writeMode=GWEN_SyncIo_Http_Mode_Body; 01050 01051 tbuf=GWEN_Buffer_new(0, 256, 0, 1); 01052 01053 i=GWEN_DB_GetIntValue(xio->dbHeaderOut, "Content-Length", 0, -1); 01054 xio->currentWriteBodySize=i; 01055 01056 dbVar=GWEN_DB_GetFirstVar(xio->dbHeaderOut); 01057 while (dbVar) { 01058 GWEN_DB_NODE *dbVal; 01059 01060 /* only handle first value */ 01061 dbVal=GWEN_DB_GetFirstValue(dbVar); 01062 if (dbVal) { 01063 GWEN_DB_NODE_TYPE vtype; 01064 01065 vtype=GWEN_DB_GetValueType(dbVal); 01066 if (vtype==GWEN_DB_NodeType_ValueChar) { 01067 const char *s; 01068 01069 GWEN_Buffer_AppendString(tbuf, GWEN_DB_VariableName(dbVar)); 01070 GWEN_Buffer_AppendString(tbuf, ":"); 01071 s=GWEN_DB_GetCharValueFromNode(dbVal); 01072 if (s) 01073 GWEN_Buffer_AppendString(tbuf, s); 01074 GWEN_Buffer_AppendString(tbuf, "\r\n"); 01075 01076 if (strcasecmp(GWEN_DB_VariableName(dbVar), "Transfer-Encoding")==0) { 01077 if (s && (-1!=GWEN_Text_ComparePattern(s, "*chunked*", 0))) { 01078 /* chunked encoding, this means next we have to write the chunksize */ 01079 xio->writeMode=GWEN_SyncIo_Http_Mode_ChunkSize; 01080 } 01081 } 01082 } 01083 else if (vtype==GWEN_DB_NodeType_ValueInt) { 01084 i=GWEN_DB_GetIntValueFromNode(dbVal); 01085 if (i!=-1 || strcasecmp(GWEN_DB_VariableName(dbVar), "Content-Length")==0) { 01086 char numbuf[32]; 01087 01088 /* don't write body size of -1 */ 01089 GWEN_Buffer_AppendString(tbuf, GWEN_DB_VariableName(dbVar)); 01090 GWEN_Buffer_AppendString(tbuf, ":"); 01091 snprintf(numbuf, sizeof(numbuf), "%d", i); 01092 GWEN_Buffer_AppendString(tbuf, numbuf); 01093 GWEN_Buffer_AppendString(tbuf, "\r\n"); 01094 } 01095 } 01096 else { 01097 DBG_INFO(GWEN_LOGDOMAIN, "Variable type %d of var [%s] not supported", 01098 vtype, GWEN_DB_VariableName(dbVar)); 01099 return GWEN_ERROR_BAD_DATA; 01100 } 01101 } 01102 dbVar=GWEN_DB_GetNextVar(dbVar); 01103 } 01104 01105 /* finalize header */ 01106 GWEN_Buffer_AppendString(tbuf, "\r\n"); 01107 01108 /* write */ 01109 rv=GWEN_SyncIo_WriteForced(baseIo, 01110 (const uint8_t*) GWEN_Buffer_GetStart(tbuf), 01111 GWEN_Buffer_GetUsedBytes(tbuf)); 01112 if (rv<0) { 01113 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 01114 GWEN_Buffer_free(tbuf); 01115 return rv; 01116 } 01117 GWEN_Buffer_free(tbuf); 01118 01119 if (xio->currentWriteBodySize==0) 01120 GWEN_SyncIo_Http_SetWriteIdle(sio); 01121 01122 return 0; 01123 } 01124 01125 01126 01127 int GWEN_SyncIo_Http_WriteChunkSize(GWEN_SYNCIO *sio, uint32_t size) { 01128 GWEN_SYNCIO_HTTP *xio; 01129 GWEN_SYNCIO *baseIo; 01130 int rv; 01131 char numbuf[32]; 01132 01133 assert(sio); 01134 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 01135 assert(xio); 01136 01137 baseIo=GWEN_SyncIo_GetBaseIo(sio); 01138 assert(baseIo); 01139 01140 /* we will construct the line including CR/LF ourselves */ 01141 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT); 01142 01143 snprintf(numbuf, sizeof(numbuf)-1, "%x\r\n", size); 01144 numbuf[sizeof(numbuf)-1]=0; 01145 01146 rv=GWEN_SyncIo_WriteForced(baseIo, (const uint8_t*) numbuf, strlen(numbuf)); 01147 if (rv<0) { 01148 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 01149 return rv; 01150 } 01151 01152 return 0; 01153 } 01154 01155 01156 01157 void GWEN_SyncIo_Http_SetWriteIdle(GWEN_SYNCIO *sio) { 01158 GWEN_SYNCIO_HTTP *xio; 01159 01160 assert(sio); 01161 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 01162 assert(xio); 01163 01164 xio->writeMode=GWEN_SyncIo_Http_Mode_Idle; 01165 GWEN_DB_ClearGroup(xio->dbStatusOut, NULL); 01166 } 01167 01168 01169 01170 01171 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbCommandIn(const GWEN_SYNCIO *sio) { 01172 GWEN_SYNCIO_HTTP *xio; 01173 01174 assert(sio); 01175 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 01176 assert(xio); 01177 01178 return xio->dbCommandIn; 01179 } 01180 01181 01182 01183 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbStatusIn(const GWEN_SYNCIO *sio) { 01184 GWEN_SYNCIO_HTTP *xio; 01185 01186 assert(sio); 01187 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 01188 assert(xio); 01189 01190 return xio->dbStatusIn; 01191 } 01192 01193 01194 01195 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbHeaderIn(const GWEN_SYNCIO *sio) { 01196 GWEN_SYNCIO_HTTP *xio; 01197 01198 assert(sio); 01199 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 01200 assert(xio); 01201 01202 return xio->dbHeaderIn; 01203 } 01204 01205 01206 01207 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbCommandOut(const GWEN_SYNCIO *sio) { 01208 GWEN_SYNCIO_HTTP *xio; 01209 01210 assert(sio); 01211 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 01212 assert(xio); 01213 01214 return xio->dbCommandOut; 01215 } 01216 01217 01218 01219 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbStatusOut(const GWEN_SYNCIO *sio) { 01220 GWEN_SYNCIO_HTTP *xio; 01221 01222 assert(sio); 01223 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 01224 assert(xio); 01225 01226 return xio->dbStatusOut; 01227 } 01228 01229 01230 01231 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbHeaderOut(const GWEN_SYNCIO *sio) { 01232 GWEN_SYNCIO_HTTP *xio; 01233 01234 assert(sio); 01235 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 01236 assert(xio); 01237 01238 return xio->dbHeaderOut; 01239 } 01240 01241 01242 01243 01244 int GWEN_SyncIo_Http_RecvBody(GWEN_SYNCIO *sio, GWEN_BUFFER *buf) { 01245 GWEN_SYNCIO_HTTP *xio; 01246 int rv; 01247 int code=0; 01248 int firstRead=1; 01249 int bodySize=-1; 01250 int bytesRead=0; 01251 01252 assert(sio); 01253 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio); 01254 assert(xio); 01255 01256 /* recv packet (this reads the HTTP body) */ 01257 for (;;) { 01258 uint8_t *p; 01259 uint32_t l; 01260 01261 rv=GWEN_Buffer_AllocRoom(buf, 1024); 01262 if (rv<0) { 01263 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 01264 return rv; 01265 } 01266 01267 p=(uint8_t*) GWEN_Buffer_GetPosPointer(buf); 01268 l=GWEN_Buffer_GetMaxUnsegmentedWrite(buf); 01269 do { 01270 rv=GWEN_SyncIo_Read(sio, p, l-1); 01271 } while(rv==GWEN_ERROR_INTERRUPTED); 01272 01273 if (rv==0) 01274 break; 01275 else if (rv<0) { 01276 if (rv==GWEN_ERROR_EOF) { 01277 if (bodySize!=-1 && bytesRead<bodySize) { 01278 DBG_ERROR(GWEN_LOGDOMAIN, 01279 "EOF met prematurely (%d < %d)", 01280 bytesRead, bodySize); 01281 return GWEN_ERROR_EOF; 01282 } 01283 } 01284 else { 01285 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv); 01286 /*return rv;*/ 01287 break; 01288 } 01289 } 01290 else { 01291 GWEN_Buffer_IncrementPos(buf, rv); 01292 GWEN_Buffer_AdjustUsedBytes(buf); 01293 if (firstRead) { 01294 GWEN_DB_NODE *db; 01295 01296 db=GWEN_SyncIo_Http_GetDbHeaderIn(sio); 01297 bodySize=GWEN_DB_GetIntValue(db, "Content-length", 0, -1); 01298 } 01299 bytesRead+=rv; 01300 } 01301 01302 if (bodySize!=-1 && bytesRead>=bodySize) { 01303 break; 01304 } 01305 firstRead=0; 01306 } 01307 01308 if (rv<0) { 01309 if (GWEN_Buffer_GetUsedBytes(buf)) { 01310 /* data received, check for common error codes */ 01311 if (rv==GWEN_ERROR_EOF || rv==GWEN_ERROR_IO || rv==GWEN_ERROR_SSL) { 01312 DBG_INFO(GWEN_LOGDOMAIN, 01313 "We received an error, but we still got data, " 01314 "so we ignore the error here"); 01315 } 01316 else { 01317 DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv); 01318 GWEN_Gui_ProgressLog(0, 01319 GWEN_LoggerLevel_Error, 01320 I18N("No message received")); 01321 return rv; 01322 } 01323 } 01324 else { 01325 DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv); 01326 GWEN_Gui_ProgressLog(0, 01327 GWEN_LoggerLevel_Error, 01328 I18N("No message received")); 01329 return rv; 01330 } 01331 } 01332 01333 if (GWEN_SyncIo_GetFlags(sio) & GWEN_SYNCIO_FLAGS_PASSIVE) 01334 code=0; 01335 else { 01336 code=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, 0); 01337 if (code) { 01338 const char *s; 01339 01340 s=GWEN_DB_GetCharValue(xio->dbStatusIn, "text", 0, NULL); 01341 DBG_DEBUG(GWEN_LOGDOMAIN, "HTTP-Status: %d (%s)", 01342 code, s?s:"- no text -"); 01343 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Info, 01344 I18N("HTTP-Status: %d (%s)"), 01345 code, s?s:I18N("- no details -)")); 01346 } 01347 else { 01348 DBG_ERROR(GWEN_LOGDOMAIN, "No HTTP status code received"); 01349 GWEN_Gui_ProgressLog(0, 01350 GWEN_LoggerLevel_Error, 01351 I18N("No HTTP status code received")); 01352 code=GWEN_ERROR_BAD_DATA; 01353 } 01354 } 01355 01356 return code; 01357 } 01358 01359 01360 01361