00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
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
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
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
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
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 int rv2;
00244 GWEN_BUFFER *tbuf;
00245
00246
00247 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
00248 rv2=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
00249 if (rv2<0) {
00250 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
00251 GWEN_Buffer_free(tbuf);
00252 return rv2;
00253 }
00254 GWEN_Buffer_free(tbuf);
00255
00256 DBG_DEBUG(GWEN_LOGDOMAIN, "Chunks finished.");
00257
00258
00259 GWEN_SyncIo_Http_SetReadIdle(sio);
00260 return 0;
00261 }
00262 else if (xio->currentReadChunkSize==-1) {
00263 DBG_ERROR(GWEN_LOGDOMAIN, "Undetermined chunksize in chunked mode? Aborting.");
00264 xio->readMode=GWEN_SyncIo_Http_Mode_Error;
00265 return GWEN_ERROR_BAD_DATA;
00266 }
00267
00268
00269 xio->readMode=GWEN_SyncIo_Http_Mode_Chunk;
00270 }
00271
00272 if (xio->readMode==GWEN_SyncIo_Http_Mode_Chunk) {
00273
00274 rv=GWEN_SyncIo_Http_ReadChunk(sio, buffer, size);
00275 if (rv<0) {
00276 xio->readMode=GWEN_SyncIo_Http_Mode_Error;
00277 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00278 return rv;
00279 }
00280
00281 return rv;
00282 }
00283
00284 if (xio->readMode==GWEN_SyncIo_Http_Mode_Body) {
00285
00286 rv=GWEN_SyncIo_Http_ReadBody(sio, buffer, size);
00287 if (rv<0) {
00288 xio->readMode=GWEN_SyncIo_Http_Mode_Error;
00289 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00290 return rv;
00291 }
00292
00293 return rv;
00294 }
00295
00296 if (xio->readMode==GWEN_SyncIo_Http_Mode_Error) {
00297 DBG_ERROR(GWEN_LOGDOMAIN, "Previous read error");
00298 return GWEN_ERROR_GENERIC;
00299 }
00300
00301 return 0;
00302 }
00303
00304
00305
00306 int GWENHYWFAR_CB GWEN_SyncIo_Http_Write(GWEN_SYNCIO *sio,
00307 const uint8_t *buffer,
00308 uint32_t size) {
00309 GWEN_SYNCIO_HTTP *xio;
00310 GWEN_SYNCIO *baseIo;
00311 int rv;
00312
00313 assert(sio);
00314 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00315 assert(xio);
00316
00317 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00318 assert(baseIo);
00319
00320 if (GWEN_SyncIo_GetStatus(sio)!=GWEN_SyncIo_Status_Connected) {
00321 DBG_ERROR(GWEN_LOGDOMAIN, "Not connected");
00322 return GWEN_ERROR_NOT_CONNECTED;
00323 }
00324
00325 if (xio->writeMode==GWEN_SyncIo_Http_Mode_Idle) {
00326 const char *s;
00327
00328 if (GWEN_SyncIo_GetFlags(sio) & GWEN_SYNCIO_FLAGS_PASSIVE)
00329
00330 rv=GWEN_SyncIo_Http_WriteStatus(sio);
00331 else
00332
00333 rv=GWEN_SyncIo_Http_WriteCommand(sio);
00334 if (rv<0) {
00335 xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
00336 return rv;
00337 }
00338
00339
00340 s=GWEN_DB_GetCharValue(xio->dbCommandOut, "protocol", 0, "HTTP/1.0");
00341 if (!(s && strcasecmp(s, "HTTP/0.9")==0)) {
00342 rv=GWEN_SyncIo_Http_WriteHeader(sio);
00343 if (rv<0) {
00344 xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
00345 return rv;
00346 }
00347 }
00348 }
00349
00350 if (xio->writeMode==GWEN_SyncIo_Http_Mode_ChunkSize) {
00351 rv=GWEN_SyncIo_Http_WriteChunkSize(sio, size);
00352 if (rv<0) {
00353 xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
00354 return rv;
00355 }
00356 if (size==0) {
00357
00358 GWEN_SyncIo_Http_SetWriteIdle(sio);
00359 return 0;
00360 }
00361
00362
00363 xio->writeMode=GWEN_SyncIo_Http_Mode_Chunk;
00364 }
00365
00366 if (xio->writeMode==GWEN_SyncIo_Http_Mode_Chunk) {
00367
00368 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
00369 rv=GWEN_SyncIo_WriteForced(baseIo, buffer, size);
00370 if (rv<0) {
00371 xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
00372 return rv;
00373 }
00374 xio->writeMode=GWEN_SyncIo_Http_Mode_ChunkSize;
00375
00376 return rv;
00377 }
00378
00379 if (xio->writeMode==GWEN_SyncIo_Http_Mode_Body) {
00380 if ((xio->currentWriteBodySize!=-1) &&
00381 (size>xio->currentWriteBodySize)) {
00382 DBG_ERROR(GWEN_LOGDOMAIN, "Size is beyond total body size (%d)!", size);
00383 xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
00384 return GWEN_ERROR_INVALID;
00385 }
00386
00387
00388 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
00389 rv=GWEN_SyncIo_WriteForced(baseIo, buffer, size);
00390 if (rv<0) {
00391 xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
00392 return rv;
00393 }
00394 if (xio->currentWriteBodySize!=-1) {
00395 xio->currentWriteBodySize-=rv;
00396 if (xio->currentWriteBodySize==0)
00397 GWEN_SyncIo_Http_SetWriteIdle(sio);
00398 }
00399
00400 return rv;
00401 }
00402
00403 if (xio->writeMode==GWEN_SyncIo_Http_Mode_Error) {
00404 DBG_ERROR(GWEN_LOGDOMAIN, "Previous write error");
00405 return GWEN_ERROR_GENERIC;
00406 }
00407
00408 return 0;
00409 }
00410
00411
00412
00413 int GWEN_SyncIo_Http_ReadLine(GWEN_SYNCIO *sio, GWEN_BUFFER *tbuf) {
00414 GWEN_SYNCIO_HTTP *xio;
00415 GWEN_SYNCIO *baseIo;
00416 int rv;
00417
00418 assert(sio);
00419 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00420 assert(xio);
00421
00422 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00423 assert(baseIo);
00424
00425
00426 GWEN_SyncIo_SubFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
00427
00428
00429 do {
00430 uint8_t *p;
00431 uint32_t l;
00432
00433 GWEN_Buffer_AllocRoom(tbuf, 1024);
00434 p=(uint8_t*) GWEN_Buffer_GetPosPointer(tbuf);
00435 l=GWEN_Buffer_GetMaxUnsegmentedWrite(tbuf);
00436 rv=GWEN_SyncIo_Read(baseIo, p, l);
00437 if (rv<0) {
00438 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00439 return rv;
00440 }
00441 else if (rv>0) {
00442 GWEN_Buffer_IncrementPos(tbuf, rv);
00443 GWEN_Buffer_AdjustUsedBytes(tbuf);
00444 if (p[rv-1]==10) {
00445 p[rv-1]=0;
00446 break;
00447 }
00448 }
00449 else if (rv==0)
00450 break;
00451 } while(rv>0);
00452
00453 if (GWEN_Buffer_GetUsedBytes(tbuf)<1) {
00454 DBG_ERROR(GWEN_LOGDOMAIN, "Nothing received");
00455 return GWEN_ERROR_EOF;
00456 }
00457
00458 return 0;
00459 }
00460
00461
00462
00463 int GWEN_SyncIo_Http_ParseStatus(GWEN_SYNCIO *sio, char *buffer) {
00464 GWEN_SYNCIO_HTTP *xio;
00465 char *p;
00466 char *s;
00467 int code;
00468
00469 assert(sio);
00470 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00471 assert(xio);
00472
00473 s=buffer;
00474
00475
00476 p=strchr(s, ' ');
00477 if (!p) {
00478 DBG_ERROR(GWEN_LOGDOMAIN,
00479 "Bad format of HTTP status (%s)", buffer);
00480 return GWEN_ERROR_INVALID;
00481 }
00482 *p=0;
00483 p++;
00484
00485 GWEN_DB_SetCharValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", s);
00486 s=p;
00487
00488
00489 while(*p && isdigit((int)*p))
00490 p++;
00491 if (*p) {
00492 *p=0;
00493 p++;
00494 }
00495 if (1!=sscanf(s, "%d", &code)) {
00496 DBG_ERROR(GWEN_LOGDOMAIN, "Bad request (status code \"%s\")", s);
00497 return GWEN_ERROR_INVALID;
00498 }
00499 GWEN_DB_SetIntValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "code", code);
00500 s=p;
00501
00502
00503 GWEN_DB_SetCharValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "text", s);
00504
00505 return 0;
00506 }
00507
00508
00509
00510 int GWEN_SyncIo_Http_ParseCommand(GWEN_SYNCIO *sio, const char *buffer) {
00511 GWEN_SYNCIO_HTTP *xio;
00512 char *tmp;
00513 char *p;
00514 char *s;
00515
00516 assert(sio);
00517 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00518 assert(xio);
00519
00520 tmp=strdup(buffer);
00521 s=tmp;
00522
00523
00524 p=strchr(s, ' ');
00525 if (!p) {
00526 DBG_ERROR(GWEN_LOGDOMAIN,
00527 "Bad format of HTTP request (%s)", buffer);
00528 free(tmp);
00529 return GWEN_ERROR_INVALID;
00530 }
00531 *p=0;
00532 p++;
00533
00534 GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "command", s);
00535 s=p;
00536
00537
00538 p=strchr(s, ' ');
00539 if (!p) {
00540 DBG_ERROR(GWEN_LOGDOMAIN,
00541 "Bad format of HTTP request (%s)", buffer);
00542 free(tmp);
00543 return GWEN_ERROR_INVALID;
00544 }
00545 *p=0;
00546 p++;
00547
00548 GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "url", s);
00549 s=p;
00550
00551 if (*s==0) {
00552
00553 DBG_ERROR(GWEN_LOGDOMAIN, "Bad request (not in HTTP>=1.0)");
00554 free(tmp);
00555 return GWEN_ERROR_INVALID;
00556 }
00557 else {
00558 GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", s);
00559 }
00560
00561 free(tmp);
00562 return 0;
00563 }
00564
00565
00566
00567 int GWEN_SyncIo_Http_ReadStatus(GWEN_SYNCIO *sio) {
00568 GWEN_SYNCIO_HTTP *xio;
00569 GWEN_SYNCIO *baseIo;
00570 GWEN_BUFFER *tbuf;
00571 int rv;
00572
00573 assert(sio);
00574 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00575 assert(xio);
00576
00577 DBG_INFO(GWEN_LOGDOMAIN, "Reading status");
00578 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00579 assert(baseIo);
00580
00581
00582 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
00583 rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
00584 if (rv<0) {
00585 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00586 GWEN_Buffer_free(tbuf);
00587 return rv;
00588 }
00589
00590 if (*GWEN_Buffer_GetStart(tbuf)==0) {
00591 DBG_INFO(GWEN_LOGDOMAIN, "Empty line received while reading status response, assuming EOF");
00592 GWEN_Buffer_free(tbuf);
00593 return GWEN_ERROR_EOF;
00594 }
00595
00596 rv=GWEN_SyncIo_Http_ParseStatus(sio, GWEN_Buffer_GetStart(tbuf));
00597 if (rv<0) {
00598 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00599 GWEN_Buffer_free(tbuf);
00600 return rv;
00601 }
00602
00603 GWEN_Buffer_free(tbuf);
00604 return 0;
00605 }
00606
00607
00608
00609 int GWEN_SyncIo_Http_ReadCommand(GWEN_SYNCIO *sio) {
00610 GWEN_SYNCIO_HTTP *xio;
00611 GWEN_SYNCIO *baseIo;
00612 GWEN_BUFFER *tbuf;
00613 int rv;
00614
00615 assert(sio);
00616 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00617 assert(xio);
00618
00619 DBG_INFO(GWEN_LOGDOMAIN, "Reading command");
00620 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00621 assert(baseIo);
00622
00623
00624 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
00625 rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
00626 if (rv<0) {
00627 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00628 GWEN_Buffer_free(tbuf);
00629 return rv;
00630 }
00631
00632 rv=GWEN_SyncIo_Http_ParseCommand(sio, GWEN_Buffer_GetStart(tbuf));
00633 if (rv<0) {
00634 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00635 GWEN_Buffer_free(tbuf);
00636 return rv;
00637 }
00638
00639 GWEN_Buffer_free(tbuf);
00640 return 0;
00641 }
00642
00643
00644
00645 int GWEN_SyncIo_Http_ParseHeader(GWEN_SYNCIO *sio, char *buf) {
00646 GWEN_SYNCIO_HTTP *xio;
00647 GWEN_SYNCIO *baseIo;
00648 char *p;
00649 const char *s;
00650
00651 assert(sio);
00652 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00653 assert(xio);
00654
00655 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00656 assert(baseIo);
00657
00658
00659 p=buf;
00660 while(*p) {
00661 p=strchr(p, 10);
00662 if (p) {
00663 if (p[1]==32 || p[1]==9)
00664
00665 *p=32;
00666 p++;
00667 }
00668 }
00669
00670
00671 p=buf;
00672 while(p && *p) {
00673 char *pNext;
00674 char *pVarBegin;
00675 char *pVarEnd;
00676
00677
00678 pNext=strchr(p, 10);
00679 if (pNext) {
00680 *pNext=0;
00681 pNext++;
00682 }
00683 while(*p && (*p==32 || *p==9))
00684 p++;
00685 if (*p) {
00686 pVarBegin=p;
00687 while(*p && *p!=':' && *p>32 && *p<127)
00688 p++;
00689 pVarEnd=p;
00690 if (*p!=':') {
00691 DBG_INFO(GWEN_LOGDOMAIN, "No separator after variable name in received header");
00692 return GWEN_ERROR_BAD_DATA;
00693 }
00694 *pVarEnd=0;
00695 p++;
00696
00697 while(*p && (*p==32 || *p==9))
00698 p++;
00699 if (*p)
00700 GWEN_DB_SetCharValue(xio->dbHeaderIn, GWEN_PATH_FLAGS_CREATE_VAR, pVarBegin, p);
00701 }
00702 p=pNext;
00703 }
00704
00705
00706
00707 xio->readMode=GWEN_SyncIo_Http_Mode_Body;
00708
00709
00710 s=GWEN_DB_GetCharValue(xio->dbHeaderIn, "Transfer-Encoding", 0, 0);
00711 if (s && (-1!=GWEN_Text_ComparePattern(s, "*chunked*", 0))) {
00712
00713 DBG_DEBUG(GWEN_LOGDOMAIN, "Body is \"chunked\"");
00714 xio->currentReadChunkSize=-1;
00715 xio->readMode=GWEN_SyncIo_Http_Mode_ChunkSize;
00716 }
00717
00718
00719 xio->currentReadBodySize=GWEN_DB_GetIntValue(xio->dbHeaderIn, "Content-Length", 0, -1);
00720 if (xio->currentReadBodySize==0) {
00721
00722 GWEN_SyncIo_Http_SetReadIdle(sio);
00723 }
00724 else if (xio->currentReadBodySize==-1) {
00725 int rcode;
00726
00727
00728
00729
00730
00731 rcode=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, -1);
00732 if (rcode<0 || rcode>=300) {
00733
00734 GWEN_SyncIo_Http_SetReadIdle(sio);
00735 }
00736 }
00737
00738 return 0;
00739 }
00740
00741
00742
00743 int GWEN_SyncIo_Http_ReadHeader(GWEN_SYNCIO *sio) {
00744 GWEN_SYNCIO_HTTP *xio;
00745 GWEN_SYNCIO *baseIo;
00746 GWEN_BUFFER *tbuf;
00747 int rv;
00748 uint32_t pos;
00749 int lines=0;
00750
00751 assert(sio);
00752 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00753 assert(xio);
00754
00755 DBG_INFO(GWEN_LOGDOMAIN, "Reading header");
00756 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00757 assert(baseIo);
00758
00759
00760 GWEN_SyncIo_SubFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
00761
00762
00763 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
00764 pos=0;
00765 do {
00766 uint8_t *p;
00767
00768 GWEN_Buffer_AllocRoom(tbuf, 1024);
00769 p=(uint8_t*) GWEN_Buffer_GetPosPointer(tbuf);
00770 rv=GWEN_SyncIo_Read(baseIo, p, 1024);
00771 if (rv<0) {
00772 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00773 GWEN_Buffer_free(tbuf);
00774 return rv;
00775 }
00776 else if (rv>0) {
00777 GWEN_Buffer_IncrementPos(tbuf, rv);
00778 GWEN_Buffer_AdjustUsedBytes(tbuf);
00779 if (p[rv-1]==10) {
00780 uint32_t npos;
00781
00782 lines++;
00783 npos=GWEN_Buffer_GetPos(tbuf);
00784 if ((npos-pos)==1) {
00785
00786 break;
00787 }
00788 pos=npos;
00789 }
00790 }
00791 else if (rv==0)
00792 break;
00793 } while(rv>0);
00794
00795 if (lines<1) {
00796 DBG_ERROR(GWEN_LOGDOMAIN, "No header line received");
00797 GWEN_Buffer_free(tbuf);
00798 return GWEN_ERROR_EOF;
00799 }
00800
00801 rv=GWEN_SyncIo_Http_ParseHeader(sio, GWEN_Buffer_GetStart(tbuf));
00802 if (rv<0) {
00803 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00804 GWEN_Buffer_free(tbuf);
00805 return rv;
00806 }
00807
00808 GWEN_Buffer_free(tbuf);
00809 return 0;
00810 }
00811
00812
00813
00814 int GWEN_SyncIo_Http_ReadChunkSize(GWEN_SYNCIO *sio) {
00815 GWEN_SYNCIO_HTTP *xio;
00816 GWEN_SYNCIO *baseIo;
00817 GWEN_BUFFER *tbuf;
00818 int rv;
00819 int csize;
00820
00821 assert(sio);
00822 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00823 assert(xio);
00824
00825 DBG_INFO(GWEN_LOGDOMAIN, "Reading chunksize");
00826 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00827 assert(baseIo);
00828
00829
00830 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
00831 rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
00832 if (rv<0) {
00833 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00834 GWEN_Buffer_free(tbuf);
00835 return rv;
00836 }
00837
00838 if (*GWEN_Buffer_GetStart(tbuf)==0) {
00839 GWEN_Buffer_Reset(tbuf);
00840 rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
00841 if (rv<0) {
00842 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00843 GWEN_Buffer_free(tbuf);
00844 return rv;
00845 }
00846 }
00847
00848 if (1!=sscanf(GWEN_Buffer_GetStart(tbuf), "%x", &csize)) {
00849 DBG_ERROR(GWEN_LOGDOMAIN, "Bad data received (invalid chunksize specifier: [%s])",
00850 GWEN_Buffer_GetStart(tbuf));
00851 GWEN_Buffer_free(tbuf);
00852 return GWEN_ERROR_BAD_DATA;
00853 }
00854
00855 xio->currentReadChunkSize=csize;
00856
00857 GWEN_Buffer_free(tbuf);
00858 return 0;
00859 }
00860
00861
00862
00863 int GWEN_SyncIo_Http_ReadChunk(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size) {
00864 GWEN_SYNCIO_HTTP *xio;
00865 GWEN_SYNCIO *baseIo;
00866 int rv;
00867
00868 assert(sio);
00869 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00870 assert(xio);
00871
00872 DBG_DEBUG(GWEN_LOGDOMAIN, "Reading chunk (%d bytes)", (int) size);
00873 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00874 assert(baseIo);
00875
00876
00877 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
00878
00879 if (size>xio->currentReadChunkSize)
00880 size=xio->currentReadChunkSize;
00881
00882 rv=GWEN_SyncIo_Read(baseIo, buffer, size);
00883 if (rv<0) {
00884 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00885 return rv;
00886 }
00887
00888 xio->currentReadChunkSize-=rv;
00889 if (xio->currentReadBodySize>0)
00890 xio->currentReadBodySize-=rv;
00891
00892 if (xio->currentReadChunkSize==0) {
00893 int rv2;
00894 GWEN_BUFFER *tbuf;
00895
00896
00897 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
00898 rv2=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
00899 if (rv2<0) {
00900 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
00901 GWEN_Buffer_free(tbuf);
00902 return rv2;
00903 }
00904 GWEN_Buffer_free(tbuf);
00905
00906 DBG_DEBUG(GWEN_LOGDOMAIN, "Chunk finished.");
00907
00908
00909 xio->readMode=GWEN_SyncIo_Http_Mode_ChunkSize;
00910 }
00911
00912 return rv;
00913 }
00914
00915
00916
00917 int GWEN_SyncIo_Http_ReadBody(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size) {
00918 GWEN_SYNCIO_HTTP *xio;
00919 GWEN_SYNCIO *baseIo;
00920 int rv;
00921
00922 assert(size);
00923
00924 assert(sio);
00925 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00926 assert(xio);
00927
00928 DBG_INFO(GWEN_LOGDOMAIN, "Reading body");
00929 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00930 assert(baseIo);
00931
00932
00933 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
00934
00935 if ((xio->currentReadBodySize>=0) &&
00936 (size>xio->currentReadBodySize)) {
00937 DBG_INFO(GWEN_LOGDOMAIN, "Adjusting read body size from %d to %d",
00938 size, xio->currentReadBodySize);
00939 size=xio->currentReadBodySize;
00940 }
00941
00942 rv=GWEN_SyncIo_Read(baseIo, buffer, size);
00943 if (rv<0) {
00944 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00945 return rv;
00946 }
00947
00948 if (xio->currentReadBodySize>=0)
00949 xio->currentReadBodySize-=rv;
00950
00951 if (xio->currentReadBodySize==0)
00952
00953 GWEN_SyncIo_Http_SetReadIdle(sio);
00954
00955 return rv;
00956 }
00957
00958
00959
00960 int GWEN_SyncIo_Http_WriteCommand(GWEN_SYNCIO *sio) {
00961 GWEN_SYNCIO_HTTP *xio;
00962 GWEN_SYNCIO *baseIo;
00963 int rv;
00964 const char *s;
00965 GWEN_BUFFER *tbuf;
00966
00967 assert(sio);
00968 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
00969 assert(xio);
00970
00971 baseIo=GWEN_SyncIo_GetBaseIo(sio);
00972 assert(baseIo);
00973
00974
00975 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
00976
00977 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
00978
00979 s=GWEN_DB_GetCharValue(xio->dbCommandOut, "command", 0, "GET");
00980 GWEN_Buffer_AppendString(tbuf, s);
00981 GWEN_Buffer_AppendString(tbuf, " ");
00982
00983 s=GWEN_DB_GetCharValue(xio->dbCommandOut, "url", 0, "/");
00984 GWEN_Buffer_AppendString(tbuf, s);
00985 GWEN_Buffer_AppendString(tbuf, " ");
00986
00987 s=GWEN_DB_GetCharValue(xio->dbCommandOut, "protocol", 0, "HTTP/1.0");
00988 GWEN_Buffer_AppendString(tbuf, s);
00989 GWEN_Buffer_AppendString(tbuf, "\r\n");
00990
00991
00992 rv=GWEN_SyncIo_WriteForced(baseIo,
00993 (const uint8_t*) GWEN_Buffer_GetStart(tbuf),
00994 GWEN_Buffer_GetUsedBytes(tbuf));
00995 if (rv<0) {
00996 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00997 GWEN_Buffer_free(tbuf);
00998 return rv;
00999 }
01000
01001 GWEN_Buffer_free(tbuf);
01002 return 0;
01003 }
01004
01005
01006
01007 int GWEN_SyncIo_Http_WriteStatus(GWEN_SYNCIO *sio) {
01008 GWEN_SYNCIO_HTTP *xio;
01009 GWEN_SYNCIO *baseIo;
01010 int rv;
01011 const char *s;
01012 GWEN_BUFFER *tbuf;
01013 char numbuf[32];
01014 int i;
01015
01016 assert(sio);
01017 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01018 assert(xio);
01019
01020 baseIo=GWEN_SyncIo_GetBaseIo(sio);
01021 assert(baseIo);
01022
01023
01024 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
01025
01026 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
01027
01028 s=GWEN_DB_GetCharValue(xio->dbStatusOut, "protocol", 0, "HTTP/1.0");
01029 GWEN_Buffer_AppendString(tbuf, s);
01030 GWEN_Buffer_AppendString(tbuf, " ");
01031
01032 i=GWEN_DB_GetIntValue(xio->dbStatusOut, "code", 0, -1);
01033 if (i==-1) {
01034 DBG_INFO(GWEN_LOGDOMAIN, "Missing status code");
01035 GWEN_Buffer_free(tbuf);
01036 return GWEN_ERROR_NO_DATA;
01037 }
01038 snprintf(numbuf, sizeof(numbuf), "%d ", i);
01039 GWEN_Buffer_AppendString(tbuf, numbuf);
01040
01041 s=GWEN_DB_GetCharValue(xio->dbStatusOut, "text", 0, "No text.");
01042 GWEN_Buffer_AppendString(tbuf, s);
01043 GWEN_Buffer_AppendString(tbuf, "\r\n");
01044
01045
01046 rv=GWEN_SyncIo_WriteForced(baseIo,
01047 (const uint8_t*) GWEN_Buffer_GetStart(tbuf),
01048 GWEN_Buffer_GetUsedBytes(tbuf));
01049 if (rv<0) {
01050 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01051 GWEN_Buffer_free(tbuf);
01052 return rv;
01053 }
01054
01055 GWEN_Buffer_free(tbuf);
01056 return 0;
01057 }
01058
01059
01060
01061 int GWEN_SyncIo_Http_WriteHeader(GWEN_SYNCIO *sio) {
01062 GWEN_SYNCIO_HTTP *xio;
01063 GWEN_SYNCIO *baseIo;
01064 int i;
01065 GWEN_DB_NODE *dbVar;
01066 GWEN_BUFFER *tbuf;
01067 int rv;
01068
01069 assert(sio);
01070 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01071 assert(xio);
01072
01073 baseIo=GWEN_SyncIo_GetBaseIo(sio);
01074 assert(baseIo);
01075
01076
01077 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
01078
01079
01080
01081 xio->writeMode=GWEN_SyncIo_Http_Mode_Body;
01082
01083 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
01084
01085 i=GWEN_DB_GetIntValue(xio->dbHeaderOut, "Content-Length", 0, -1);
01086 xio->currentWriteBodySize=i;
01087
01088 dbVar=GWEN_DB_GetFirstVar(xio->dbHeaderOut);
01089 while (dbVar) {
01090 GWEN_DB_NODE *dbVal;
01091
01092
01093 dbVal=GWEN_DB_GetFirstValue(dbVar);
01094 if (dbVal) {
01095 GWEN_DB_NODE_TYPE vtype;
01096
01097 vtype=GWEN_DB_GetValueType(dbVal);
01098 if (vtype==GWEN_DB_NodeType_ValueChar) {
01099 const char *s;
01100
01101 GWEN_Buffer_AppendString(tbuf, GWEN_DB_VariableName(dbVar));
01102 GWEN_Buffer_AppendString(tbuf, ":");
01103 s=GWEN_DB_GetCharValueFromNode(dbVal);
01104 if (s)
01105 GWEN_Buffer_AppendString(tbuf, s);
01106 GWEN_Buffer_AppendString(tbuf, "\r\n");
01107
01108 if (strcasecmp(GWEN_DB_VariableName(dbVar), "Transfer-Encoding")==0) {
01109 if (s && (-1!=GWEN_Text_ComparePattern(s, "*chunked*", 0))) {
01110
01111 xio->writeMode=GWEN_SyncIo_Http_Mode_ChunkSize;
01112 }
01113 }
01114 }
01115 else if (vtype==GWEN_DB_NodeType_ValueInt) {
01116 i=GWEN_DB_GetIntValueFromNode(dbVal);
01117 if (i!=-1 || strcasecmp(GWEN_DB_VariableName(dbVar), "Content-Length")==0) {
01118 char numbuf[32];
01119
01120
01121 GWEN_Buffer_AppendString(tbuf, GWEN_DB_VariableName(dbVar));
01122 GWEN_Buffer_AppendString(tbuf, ":");
01123 snprintf(numbuf, sizeof(numbuf), "%d", i);
01124 GWEN_Buffer_AppendString(tbuf, numbuf);
01125 GWEN_Buffer_AppendString(tbuf, "\r\n");
01126 }
01127 }
01128 else {
01129 DBG_INFO(GWEN_LOGDOMAIN, "Variable type %d of var [%s] not supported",
01130 vtype, GWEN_DB_VariableName(dbVar));
01131 return GWEN_ERROR_BAD_DATA;
01132 }
01133 }
01134 dbVar=GWEN_DB_GetNextVar(dbVar);
01135 }
01136
01137
01138 GWEN_Buffer_AppendString(tbuf, "\r\n");
01139
01140
01141 rv=GWEN_SyncIo_WriteForced(baseIo,
01142 (const uint8_t*) GWEN_Buffer_GetStart(tbuf),
01143 GWEN_Buffer_GetUsedBytes(tbuf));
01144 if (rv<0) {
01145 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01146 GWEN_Buffer_free(tbuf);
01147 return rv;
01148 }
01149 GWEN_Buffer_free(tbuf);
01150
01151 if (xio->currentWriteBodySize==0)
01152 GWEN_SyncIo_Http_SetWriteIdle(sio);
01153
01154 return 0;
01155 }
01156
01157
01158
01159 int GWEN_SyncIo_Http_WriteChunkSize(GWEN_SYNCIO *sio, uint32_t size) {
01160 GWEN_SYNCIO_HTTP *xio;
01161 GWEN_SYNCIO *baseIo;
01162 int rv;
01163 char numbuf[32];
01164
01165 assert(sio);
01166 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01167 assert(xio);
01168
01169 baseIo=GWEN_SyncIo_GetBaseIo(sio);
01170 assert(baseIo);
01171
01172
01173 GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
01174
01175 snprintf(numbuf, sizeof(numbuf)-1, "%x\r\n", size);
01176 numbuf[sizeof(numbuf)-1]=0;
01177
01178 rv=GWEN_SyncIo_WriteForced(baseIo, (const uint8_t*) numbuf, strlen(numbuf));
01179 if (rv<0) {
01180 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01181 return rv;
01182 }
01183
01184 return 0;
01185 }
01186
01187
01188
01189 void GWEN_SyncIo_Http_SetWriteIdle(GWEN_SYNCIO *sio) {
01190 GWEN_SYNCIO_HTTP *xio;
01191
01192 assert(sio);
01193 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01194 assert(xio);
01195
01196 xio->writeMode=GWEN_SyncIo_Http_Mode_Idle;
01197 GWEN_DB_ClearGroup(xio->dbStatusOut, NULL);
01198 }
01199
01200
01201
01202
01203 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbCommandIn(const GWEN_SYNCIO *sio) {
01204 GWEN_SYNCIO_HTTP *xio;
01205
01206 assert(sio);
01207 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01208 assert(xio);
01209
01210 return xio->dbCommandIn;
01211 }
01212
01213
01214
01215 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbStatusIn(const GWEN_SYNCIO *sio) {
01216 GWEN_SYNCIO_HTTP *xio;
01217
01218 assert(sio);
01219 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01220 assert(xio);
01221
01222 return xio->dbStatusIn;
01223 }
01224
01225
01226
01227 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbHeaderIn(const GWEN_SYNCIO *sio) {
01228 GWEN_SYNCIO_HTTP *xio;
01229
01230 assert(sio);
01231 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01232 assert(xio);
01233
01234 return xio->dbHeaderIn;
01235 }
01236
01237
01238
01239 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbCommandOut(const GWEN_SYNCIO *sio) {
01240 GWEN_SYNCIO_HTTP *xio;
01241
01242 assert(sio);
01243 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01244 assert(xio);
01245
01246 return xio->dbCommandOut;
01247 }
01248
01249
01250
01251 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbStatusOut(const GWEN_SYNCIO *sio) {
01252 GWEN_SYNCIO_HTTP *xio;
01253
01254 assert(sio);
01255 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01256 assert(xio);
01257
01258 return xio->dbStatusOut;
01259 }
01260
01261
01262
01263 GWEN_DB_NODE *GWEN_SyncIo_Http_GetDbHeaderOut(const GWEN_SYNCIO *sio) {
01264 GWEN_SYNCIO_HTTP *xio;
01265
01266 assert(sio);
01267 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01268 assert(xio);
01269
01270 return xio->dbHeaderOut;
01271 }
01272
01273
01274
01275
01276 int GWEN_SyncIo_Http_RecvBody(GWEN_SYNCIO *sio, GWEN_BUFFER *buf) {
01277 GWEN_SYNCIO_HTTP *xio;
01278 int rv;
01279 int code=0;
01280 int firstRead=1;
01281 int bodySize=-1;
01282 int bytesRead=0;
01283 uint32_t pid;
01284
01285 assert(sio);
01286 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01287 assert(xio);
01288
01289 pid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
01290 GWEN_GUI_PROGRESS_SHOW_ABORT |
01291 GWEN_GUI_PROGRESS_ALLOW_EMBED |
01292 GWEN_GUI_PROGRESS_SHOW_PROGRESS,
01293 I18N("Network Operation"),
01294 I18N("Receiving data"),
01295 0,
01296 0);
01297
01298
01299
01300 for (;;) {
01301 uint8_t *p;
01302 uint32_t l;
01303
01304 rv=GWEN_Buffer_AllocRoom(buf, 1024);
01305 if (rv<0) {
01306 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01307 GWEN_Gui_ProgressEnd(pid);
01308 return rv;
01309 }
01310
01311 p=(uint8_t*) GWEN_Buffer_GetPosPointer(buf);
01312 l=GWEN_Buffer_GetMaxUnsegmentedWrite(buf);
01313 do {
01314 rv=GWEN_SyncIo_Read(sio, p, l-1);
01315 } while(rv==GWEN_ERROR_INTERRUPTED);
01316
01317 if (rv==0)
01318 break;
01319 else if (rv<0) {
01320 if (rv==GWEN_ERROR_EOF) {
01321 if (bodySize!=-1 && bytesRead<bodySize) {
01322 DBG_ERROR(GWEN_LOGDOMAIN,
01323 "EOF met prematurely (%d < %d)",
01324 bytesRead, bodySize);
01325 GWEN_Gui_ProgressEnd(pid);
01326 return GWEN_ERROR_EOF;
01327 }
01328 }
01329 else {
01330 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01331
01332 break;
01333 }
01334 }
01335 else {
01336 GWEN_Buffer_IncrementPos(buf, rv);
01337 GWEN_Buffer_AdjustUsedBytes(buf);
01338 if (firstRead) {
01339 GWEN_DB_NODE *db;
01340
01341 db=GWEN_SyncIo_Http_GetDbHeaderIn(sio);
01342 bodySize=GWEN_DB_GetIntValue(db, "Content-length", 0, -1);
01343
01344 if (bodySize!=-1)
01345 GWEN_Gui_ProgressSetTotal(pid, bodySize);
01346 }
01347 bytesRead+=rv;
01348
01349
01350 rv=GWEN_Gui_ProgressAdvance(pid, bytesRead);
01351 if (rv==GWEN_ERROR_USER_ABORTED) {
01352 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01353 GWEN_Gui_ProgressEnd(pid);
01354 return rv;
01355 }
01356 }
01357
01358 if (bodySize!=-1 && bytesRead>=bodySize) {
01359 break;
01360 }
01361
01362 firstRead=0;
01363 }
01364 GWEN_Gui_ProgressEnd(pid);
01365
01366 if (rv<0) {
01367 if (GWEN_Buffer_GetUsedBytes(buf)) {
01368
01369 if (rv==GWEN_ERROR_EOF || rv==GWEN_ERROR_IO || rv==GWEN_ERROR_SSL) {
01370 DBG_INFO(GWEN_LOGDOMAIN,
01371 "We received an error, but we still got data, "
01372 "so we ignore the error here");
01373 }
01374 else {
01375 DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
01376 GWEN_Gui_ProgressLog(0,
01377 GWEN_LoggerLevel_Error,
01378 I18N("No message received"));
01379 return rv;
01380 }
01381 }
01382 else {
01383 DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
01384 GWEN_Gui_ProgressLog(0,
01385 GWEN_LoggerLevel_Error,
01386 I18N("No message received"));
01387 return rv;
01388 }
01389 }
01390
01391 if (GWEN_SyncIo_GetFlags(sio) & GWEN_SYNCIO_FLAGS_PASSIVE)
01392 code=0;
01393 else {
01394 code=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, 0);
01395 if (code) {
01396 const char *s;
01397
01398 s=GWEN_DB_GetCharValue(xio->dbStatusIn, "text", 0, NULL);
01399 DBG_DEBUG(GWEN_LOGDOMAIN, "HTTP-Status: %d (%s)",
01400 code, s?s:"- no text -");
01401 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Info,
01402 I18N("HTTP-Status: %d (%s)"),
01403 code, s?s:I18N("- no details -)"));
01404 }
01405 else {
01406 DBG_ERROR(GWEN_LOGDOMAIN, "No HTTP status code received");
01407 GWEN_Gui_ProgressLog(0,
01408 GWEN_LoggerLevel_Error,
01409 I18N("No HTTP status code received"));
01410 code=GWEN_ERROR_BAD_DATA;
01411 }
01412 }
01413
01414 return code;
01415 }
01416
01417
01418
01419 int GWEN_SyncIo_Http_RecvBodyToSio(GWEN_SYNCIO *sio, GWEN_SYNCIO *sout) {
01420 GWEN_SYNCIO_HTTP *xio;
01421 int rv;
01422 int code=0;
01423 int firstRead=1;
01424 int bodySize=-1;
01425 int bytesRead=0;
01426 uint32_t pid;
01427
01428 assert(sio);
01429 xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
01430 assert(xio);
01431
01432 pid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
01433 GWEN_GUI_PROGRESS_SHOW_ABORT |
01434 GWEN_GUI_PROGRESS_ALLOW_EMBED |
01435 GWEN_GUI_PROGRESS_SHOW_PROGRESS,
01436 I18N("Network Operation"),
01437 I18N("Receiving data"),
01438 0,
01439 0);
01440
01441
01442 for (;;) {
01443 uint8_t *p;
01444 uint32_t l;
01445 uint8_t rbuf[1024];
01446
01447 p=rbuf;
01448 l=sizeof(rbuf);
01449
01450 do {
01451 rv=GWEN_SyncIo_Read(sio, p, l-1);
01452 } while(rv==GWEN_ERROR_INTERRUPTED);
01453
01454 if (rv==0)
01455 break;
01456 else if (rv<0) {
01457 if (rv==GWEN_ERROR_EOF) {
01458 if (bodySize!=-1 && bytesRead<bodySize) {
01459 DBG_ERROR(GWEN_LOGDOMAIN,
01460 "EOF met prematurely (%d < %d)",
01461 bytesRead, bodySize);
01462 GWEN_Gui_ProgressEnd(pid);
01463 return GWEN_ERROR_EOF;
01464 }
01465 }
01466 else {
01467 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01468
01469 break;
01470 }
01471 }
01472 else {
01473 int rv2;
01474
01475 rv2=GWEN_SyncIo_WriteForced(sout, rbuf, rv);
01476 if (rv2<0) {
01477 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
01478 GWEN_Gui_ProgressEnd(pid);
01479 return rv2;
01480 }
01481 if (firstRead) {
01482 GWEN_DB_NODE *db;
01483
01484 db=GWEN_SyncIo_Http_GetDbHeaderIn(sio);
01485 bodySize=GWEN_DB_GetIntValue(db, "Content-length", 0, -1);
01486
01487 if (bodySize!=-1)
01488 GWEN_Gui_ProgressSetTotal(pid, bodySize);
01489 }
01490 bytesRead+=rv;
01491
01492
01493 rv=GWEN_Gui_ProgressAdvance(pid, bytesRead);
01494 if (rv==GWEN_ERROR_USER_ABORTED) {
01495 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
01496 GWEN_Gui_ProgressEnd(pid);
01497 return rv;
01498 }
01499 }
01500
01501 if (bodySize!=-1 && bytesRead>=bodySize) {
01502 break;
01503 }
01504 firstRead=0;
01505 }
01506 GWEN_Gui_ProgressEnd(pid);
01507
01508
01509 if (rv<0) {
01510 if (bytesRead) {
01511
01512 if (rv==GWEN_ERROR_EOF || rv==GWEN_ERROR_IO || rv==GWEN_ERROR_SSL) {
01513 DBG_INFO(GWEN_LOGDOMAIN,
01514 "We received an error, but we still got data, "
01515 "so we ignore the error here");
01516 }
01517 else {
01518 DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
01519 GWEN_Gui_ProgressLog(0,
01520 GWEN_LoggerLevel_Error,
01521 I18N("No message received"));
01522 return rv;
01523 }
01524 }
01525 else {
01526 DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
01527 GWEN_Gui_ProgressLog(0,
01528 GWEN_LoggerLevel_Error,
01529 I18N("No message received"));
01530 return rv;
01531 }
01532 }
01533
01534 if (GWEN_SyncIo_GetFlags(sio) & GWEN_SYNCIO_FLAGS_PASSIVE)
01535 code=0;
01536 else {
01537 code=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, 0);
01538 if (code) {
01539 const char *s;
01540
01541 s=GWEN_DB_GetCharValue(xio->dbStatusIn, "text", 0, NULL);
01542 DBG_DEBUG(GWEN_LOGDOMAIN, "HTTP-Status: %d (%s)",
01543 code, s?s:"- no text -");
01544 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Info,
01545 I18N("HTTP-Status: %d (%s)"),
01546 code, s?s:I18N("- no details -)"));
01547 }
01548 else {
01549 DBG_ERROR(GWEN_LOGDOMAIN, "No HTTP status code received");
01550 GWEN_Gui_ProgressLog(0,
01551 GWEN_LoggerLevel_Error,
01552 I18N("No HTTP status code received"));
01553 code=GWEN_ERROR_BAD_DATA;
01554 }
01555 }
01556
01557 return code;
01558 }
01559
01560
01561
01562