gwenhywfar  4.3.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       int rv2;
00244       GWEN_BUFFER *tbuf;
00245 
00246       /* all chunks finished, read trailing CR/LF */
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       /* chunksize is 0, body ended */
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     /* chunksize known, next will be to read that chunk */
00269     xio->readMode=GWEN_SyncIo_Http_Mode_Chunk;
00270   }
00271 
00272   if (xio->readMode==GWEN_SyncIo_Http_Mode_Chunk) {
00273     /* read chunk */
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     /* read chunk */
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       /* write status */
00330       rv=GWEN_SyncIo_Http_WriteStatus(sio);
00331     else
00332       /* write command */
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     /* possibly write header */
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       /* chunksize is 0, body ended */
00358       GWEN_SyncIo_Http_SetWriteIdle(sio);
00359       return 0;
00360     }
00361 
00362     /* chunksize known, next will be to write that chunk */
00363     xio->writeMode=GWEN_SyncIo_Http_Mode_Chunk;
00364   }
00365 
00366   if (xio->writeMode==GWEN_SyncIo_Http_Mode_Chunk) {
00367     /* we want to write binary data transparently */
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     /* we want to write binary data transparently */
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   /* we want to read a text line, so we can't have a transparent mode in the base layer */
00426   GWEN_SyncIo_SubFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
00427 
00428   /* read a single line */
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   /* read protocol */
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   /* read status code */
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   /* read text */
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   /* read command */
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   /* read URL */
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     /* no protocol information follows, so we assume HTTP/0.9 */
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   /* read a single line */
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   /* read a single line */
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   /* resolve line continuations */
00659   p=buf;
00660   while(*p) {
00661     p=strchr(p, 10);
00662     if (p) {
00663       if (p[1]==32 || p[1]==9)
00664         /* found a continuation */
00665         *p=32;
00666       p++;
00667     }
00668   }
00669 
00670   /* parse every line */
00671   p=buf;
00672   while(p && *p) {
00673     char *pNext;
00674     char *pVarBegin;
00675     char *pVarEnd;
00676 
00677     /* skip blanks */
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   /* default next mode after reading the header is reading the body
00706    * (if any, but that will be checked later) */
00707   xio->readMode=GWEN_SyncIo_Http_Mode_Body;
00708 
00709   /* header received, now read some settings from it */
00710   s=GWEN_DB_GetCharValue(xio->dbHeaderIn, "Transfer-Encoding", 0, 0);
00711   if (s && (-1!=GWEN_Text_ComparePattern(s, "*chunked*", 0))) {
00712     /* chunked encoding, this means next we have to read the chunksize */
00713     DBG_DEBUG(GWEN_LOGDOMAIN, "Body is \"chunked\"");
00714     xio->currentReadChunkSize=-1;
00715     xio->readMode=GWEN_SyncIo_Http_Mode_ChunkSize;
00716   }
00717 
00718   /* get size of body */
00719   xio->currentReadBodySize=GWEN_DB_GetIntValue(xio->dbHeaderIn, "Content-Length", 0, -1);
00720   if (xio->currentReadBodySize==0) {
00721     /* no body */
00722     GWEN_SyncIo_Http_SetReadIdle(sio);
00723   }
00724   else if (xio->currentReadBodySize==-1) {
00725     int rcode;
00726 
00727     /* no length of body received, assume 0 in case of an error
00728      * This eliminates the bug where this module waits for
00729      * a timeout when receiving an error from a special server
00730      */
00731     rcode=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, -1);
00732     if (rcode<0 || rcode>=300) {
00733       /* no body */
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   /* we want to read a text line, so we can't have a transparent mode in the base layer */
00760   GWEN_SyncIo_SubFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
00761 
00762   /* read a single line */
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           /* empty line, header finished */
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   /* read a single line */
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   /* we want to read binary data transparently */
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     /* chunk finished, read trailing CR/LF */
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     /* change read mode */
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   /* we want to read binary data transparently */
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     /* body finished, change read mode */
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   /* we will construct the line including CR/LF ourselves */
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   /* write */
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   /* we will construct the line including CR/LF ourselves */
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   /* write */
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   /* we will construct the line including CR/LF ourselves */
01077   GWEN_SyncIo_AddFlags(baseIo, GWEN_SYNCIO_FLAGS_TRANSPARENT);
01078 
01079   /* default next mode after writing the header is writing the body
01080    * (if any, but that will be checked later) */
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     /* only handle first value */
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             /* chunked encoding, this means next we have to write the chunksize */
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           /* don't write body size of -1 */
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   /* finalize header */
01138   GWEN_Buffer_AppendString(tbuf, "\r\n");
01139 
01140   /* write */
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   /* we will construct the line including CR/LF ourselves */
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   /* recv packet (this reads the HTTP body) */
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         /*return rv;*/
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       /* advance progress bar */
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       /* data received, check for common error codes */
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   /* recv packet (this reads the HTTP body) */
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         /*return rv;*/
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       /* advance progress bar */
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       /* data received, check for common error codes */
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