gwenhywfar 4.0.3

syncio_http.c

Go to the documentation of this file.
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