gwenhywfar  4.3.3
syncio_http.c
Go to the documentation of this file.
1 /***************************************************************************
2  begin : Wed Apr 28 2010
3  copyright : (C) 2010 by Martin Preuss
4  email : martin@libchipcard.de
5 
6  ***************************************************************************
7  * *
8  * This library is free software; you can redistribute it and/or *
9  * modify it under the terms of the GNU Lesser General Public *
10  * License as published by the Free Software Foundation; either *
11  * version 2.1 of the License, or (at your option) any later version. *
12  * *
13  * This library is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16  * Lesser General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU Lesser General Public *
19  * License along with this library; if not, write to the Free Software *
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21  * MA 02111-1307 USA *
22  * *
23  ***************************************************************************/
24 
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 #define DISABLE_DEBUGLOG
30 
31 
32 
33 #include "syncio_http_p.h"
34 #include "i18n_l.h"
35 
36 #include <gwenhywfar/misc.h>
37 #include <gwenhywfar/debug.h>
38 #include <gwenhywfar/gui.h>
39 #include <gwenhywfar/text.h>
40 
41 #include <assert.h>
42 #include <errno.h>
43 #include <string.h>
44 #include <ctype.h>
45 
46 
47 
48 GWEN_INHERIT(GWEN_SYNCIO, GWEN_SYNCIO_HTTP)
49 
50 
51 
53  GWEN_SYNCIO *sio;
54  GWEN_SYNCIO_HTTP *xio;
55 
57  GWEN_NEW_OBJECT(GWEN_SYNCIO_HTTP, xio);
58  GWEN_INHERIT_SETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio, xio, GWEN_SyncIo_Http_FreeData);
59 
64 
65  xio->dbCommandIn=GWEN_DB_Group_new("command");
66  xio->dbStatusIn=GWEN_DB_Group_new("status");
67  xio->dbHeaderIn=GWEN_DB_Group_new("header");
68 
69  xio->dbCommandOut=GWEN_DB_Group_new("command");
70  xio->dbStatusOut=GWEN_DB_Group_new("status");
71  xio->dbHeaderOut=GWEN_DB_Group_new("header");
72 
73 
74  return sio;
75 }
76 
77 
78 
79 void GWENHYWFAR_CB GWEN_SyncIo_Http_FreeData(void *bp, void *p) {
80  GWEN_SYNCIO_HTTP *xio;
81 
82  xio=(GWEN_SYNCIO_HTTP*) p;
83 
84  GWEN_DB_Group_free(xio->dbCommandOut);
85  GWEN_DB_Group_free(xio->dbStatusOut);
86  GWEN_DB_Group_free(xio->dbHeaderOut);
87 
88  GWEN_DB_Group_free(xio->dbCommandIn);
89  GWEN_DB_Group_free(xio->dbStatusIn);
90  GWEN_DB_Group_free(xio->dbHeaderIn);
91 
92  GWEN_FREE_OBJECT(xio);
93 }
94 
95 
96 
98  GWEN_SYNCIO_HTTP *xio;
99  GWEN_SYNCIO *baseIo;
100  int rv;
101 
102  assert(sio);
103  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
104  assert(xio);
105 
107  DBG_INFO(GWEN_LOGDOMAIN, "Already connected");
108  return 0;
109  }
110 
111  baseIo=GWEN_SyncIo_GetBaseIo(sio);
112  assert(baseIo);
113 
114  rv=GWEN_SyncIo_Connect(baseIo);
115  if (rv<0) {
116  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
117  return rv;
118  }
119 
122 
123  return 0;
124 }
125 
126 
127 
129  GWEN_SYNCIO_HTTP *xio;
130  GWEN_SYNCIO *baseIo;
131  int rv;
132 
133  assert(sio);
134  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
135  assert(xio);
136 
138  DBG_INFO(GWEN_LOGDOMAIN, "Not connected");
140  }
141 
142  baseIo=GWEN_SyncIo_GetBaseIo(sio);
143  assert(baseIo);
144 
145  rv=GWEN_SyncIo_Disconnect(baseIo);
147  if (rv<0) {
148  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
149  return rv;
150  }
151 
152  return 0;
153 }
154 
155 
156 
158  GWEN_SYNCIO_HTTP *xio;
159 
160  assert(sio);
161  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
162  assert(xio);
163 
164  xio->readMode=GWEN_SyncIo_Http_Mode_Idle;
165 }
166 
167 
168 
170  uint8_t *buffer,
171  uint32_t size) {
172  GWEN_SYNCIO_HTTP *xio;
173  int rv;
174 
175  assert(sio);
176  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
177  assert(xio);
178 
180  DBG_ERROR(GWEN_LOGDOMAIN, "Not connected");
182  }
183 
184  if (xio->readMode==GWEN_SyncIo_Http_Mode_Idle) {
185  const char *s;
186 
187  /* reset status and headers */
188  GWEN_DB_ClearGroup(xio->dbCommandIn, NULL);
189  GWEN_DB_ClearGroup(xio->dbStatusIn, NULL);
190  GWEN_DB_ClearGroup(xio->dbHeaderIn, NULL);
191 
193  /* read command */
195  if (rv<0) {
196  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
197  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
198  return rv;
199  }
200 
201  /* possibly read header */
202  s=GWEN_DB_GetCharValue(xio->dbCommandIn, "protocol", 0, "HTTP/1.0");
203  if (!(s && strcasecmp(s, "HTTP/0.9")==0)) {
205  if (rv<0) {
206  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
207  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
208  return rv;
209  }
210  }
211  }
212  else {
213  /* read status */
215  if (rv<0) {
216  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
217  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
218  return rv;
219  }
220 
221  /* possibly read header */
222  s=GWEN_DB_GetCharValue(xio->dbStatusIn, "protocol", 0, "HTTP/1.0");
223  if (!(s && strcasecmp(s, "HTTP/0.9")==0)) {
225  if (rv<0) {
226  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
227  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
228  return rv;
229  }
230  }
231  }
232 
233  }
234 
235  if (xio->readMode==GWEN_SyncIo_Http_Mode_ChunkSize) {
237  if (rv<0) {
238  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
239  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
240  return rv;
241  }
242  if (xio->currentReadChunkSize==0) {
243  int rv2;
244  GWEN_BUFFER *tbuf;
245 
246  /* all chunks finished, read trailing CR/LF */
247  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
248  rv2=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
249  if (rv2<0) {
250  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
251  GWEN_Buffer_free(tbuf);
252  return rv2;
253  }
254  GWEN_Buffer_free(tbuf);
255 
256  DBG_DEBUG(GWEN_LOGDOMAIN, "Chunks finished.");
257 
258  /* chunksize is 0, body ended */
260  return 0;
261  }
262  else if (xio->currentReadChunkSize==-1) {
263  DBG_ERROR(GWEN_LOGDOMAIN, "Undetermined chunksize in chunked mode? Aborting.");
264  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
265  return GWEN_ERROR_BAD_DATA;
266  }
267 
268  /* chunksize known, next will be to read that chunk */
269  xio->readMode=GWEN_SyncIo_Http_Mode_Chunk;
270  }
271 
272  if (xio->readMode==GWEN_SyncIo_Http_Mode_Chunk) {
273  /* read chunk */
274  rv=GWEN_SyncIo_Http_ReadChunk(sio, buffer, size);
275  if (rv<0) {
276  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
277  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
278  return rv;
279  }
280 
281  return rv;
282  }
283 
284  if (xio->readMode==GWEN_SyncIo_Http_Mode_Body) {
285  /* read chunk */
286  rv=GWEN_SyncIo_Http_ReadBody(sio, buffer, size);
287  if (rv<0) {
288  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
289  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
290  return rv;
291  }
292 
293  return rv;
294  }
295 
296  if (xio->readMode==GWEN_SyncIo_Http_Mode_Error) {
297  DBG_ERROR(GWEN_LOGDOMAIN, "Previous read error");
298  return GWEN_ERROR_GENERIC;
299  }
300 
301  return 0;
302 }
303 
304 
305 
307  const uint8_t *buffer,
308  uint32_t size) {
309  GWEN_SYNCIO_HTTP *xio;
310  GWEN_SYNCIO *baseIo;
311  int rv;
312 
313  assert(sio);
314  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
315  assert(xio);
316 
317  baseIo=GWEN_SyncIo_GetBaseIo(sio);
318  assert(baseIo);
319 
321  DBG_ERROR(GWEN_LOGDOMAIN, "Not connected");
323  }
324 
325  if (xio->writeMode==GWEN_SyncIo_Http_Mode_Idle) {
326  const char *s;
327 
329  /* write status */
331  else
332  /* write command */
334  if (rv<0) {
335  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
336  return rv;
337  }
338 
339  /* possibly write header */
340  s=GWEN_DB_GetCharValue(xio->dbCommandOut, "protocol", 0, "HTTP/1.0");
341  if (!(s && strcasecmp(s, "HTTP/0.9")==0)) {
343  if (rv<0) {
344  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
345  return rv;
346  }
347  }
348  }
349 
350  if (xio->writeMode==GWEN_SyncIo_Http_Mode_ChunkSize) {
351  rv=GWEN_SyncIo_Http_WriteChunkSize(sio, size);
352  if (rv<0) {
353  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
354  return rv;
355  }
356  if (size==0) {
357  /* chunksize is 0, body ended */
359  return 0;
360  }
361 
362  /* chunksize known, next will be to write that chunk */
363  xio->writeMode=GWEN_SyncIo_Http_Mode_Chunk;
364  }
365 
366  if (xio->writeMode==GWEN_SyncIo_Http_Mode_Chunk) {
367  /* we want to write binary data transparently */
369  rv=GWEN_SyncIo_WriteForced(baseIo, buffer, size);
370  if (rv<0) {
371  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
372  return rv;
373  }
374  xio->writeMode=GWEN_SyncIo_Http_Mode_ChunkSize;
375 
376  return rv;
377  }
378 
379  if (xio->writeMode==GWEN_SyncIo_Http_Mode_Body) {
380  if ((xio->currentWriteBodySize!=-1) &&
381  (size>xio->currentWriteBodySize)) {
382  DBG_ERROR(GWEN_LOGDOMAIN, "Size is beyond total body size (%d)!", size);
383  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
384  return GWEN_ERROR_INVALID;
385  }
386 
387  /* we want to write binary data transparently */
389  rv=GWEN_SyncIo_WriteForced(baseIo, buffer, size);
390  if (rv<0) {
391  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
392  return rv;
393  }
394  if (xio->currentWriteBodySize!=-1) {
395  xio->currentWriteBodySize-=rv;
396  if (xio->currentWriteBodySize==0)
398  }
399 
400  return rv;
401  }
402 
403  if (xio->writeMode==GWEN_SyncIo_Http_Mode_Error) {
404  DBG_ERROR(GWEN_LOGDOMAIN, "Previous write error");
405  return GWEN_ERROR_GENERIC;
406  }
407 
408  return 0;
409 }
410 
411 
412 
414  GWEN_SYNCIO_HTTP *xio;
415  GWEN_SYNCIO *baseIo;
416  int rv;
417 
418  assert(sio);
419  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
420  assert(xio);
421 
422  baseIo=GWEN_SyncIo_GetBaseIo(sio);
423  assert(baseIo);
424 
425  /* we want to read a text line, so we can't have a transparent mode in the base layer */
427 
428  /* read a single line */
429  do {
430  uint8_t *p;
431  uint32_t l;
432 
433  GWEN_Buffer_AllocRoom(tbuf, 1024);
434  p=(uint8_t*) GWEN_Buffer_GetPosPointer(tbuf);
436  rv=GWEN_SyncIo_Read(baseIo, p, l);
437  if (rv<0) {
438  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
439  return rv;
440  }
441  else if (rv>0) {
442  GWEN_Buffer_IncrementPos(tbuf, rv);
444  if (p[rv-1]==10) {
445  p[rv-1]=0;
446  break;
447  }
448  }
449  else if (rv==0)
450  break;
451  } while(rv>0);
452 
453  if (GWEN_Buffer_GetUsedBytes(tbuf)<1) {
454  DBG_ERROR(GWEN_LOGDOMAIN, "Nothing received");
455  return GWEN_ERROR_EOF;
456  }
457 
458  return 0;
459 }
460 
461 
462 
463 int GWEN_SyncIo_Http_ParseStatus(GWEN_SYNCIO *sio, char *buffer) {
464  GWEN_SYNCIO_HTTP *xio;
465  char *p;
466  char *s;
467  int code;
468 
469  assert(sio);
470  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
471  assert(xio);
472 
473  s=buffer;
474 
475  /* read protocol */
476  p=strchr(s, ' ');
477  if (!p) {
479  "Bad format of HTTP status (%s)", buffer);
480  return GWEN_ERROR_INVALID;
481  }
482  *p=0;
483  p++;
484 
485  GWEN_DB_SetCharValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", s);
486  s=p;
487 
488  /* read status code */
489  while(*p && isdigit((int)*p))
490  p++;
491  if (*p) {
492  *p=0;
493  p++;
494  }
495  if (1!=sscanf(s, "%d", &code)) {
496  DBG_ERROR(GWEN_LOGDOMAIN, "Bad request (status code \"%s\")", s);
497  return GWEN_ERROR_INVALID;
498  }
499  GWEN_DB_SetIntValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "code", code);
500  s=p;
501 
502  /* read text */
503  GWEN_DB_SetCharValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "text", s);
504 
505  return 0;
506 }
507 
508 
509 
510 int GWEN_SyncIo_Http_ParseCommand(GWEN_SYNCIO *sio, const char *buffer) {
511  GWEN_SYNCIO_HTTP *xio;
512  char *tmp;
513  char *p;
514  char *s;
515 
516  assert(sio);
517  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
518  assert(xio);
519 
520  tmp=strdup(buffer);
521  s=tmp;
522 
523  /* read command */
524  p=strchr(s, ' ');
525  if (!p) {
527  "Bad format of HTTP request (%s)", buffer);
528  free(tmp);
529  return GWEN_ERROR_INVALID;
530  }
531  *p=0;
532  p++;
533 
534  GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "command", s);
535  s=p;
536 
537  /* read URL */
538  p=strchr(s, ' ');
539  if (!p) {
541  "Bad format of HTTP request (%s)", buffer);
542  free(tmp);
543  return GWEN_ERROR_INVALID;
544  }
545  *p=0;
546  p++;
547 
548  GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "url", s);
549  s=p;
550 
551  if (*s==0) {
552  /* no protocol information follows, so we assume HTTP/0.9 */
553  DBG_ERROR(GWEN_LOGDOMAIN, "Bad request (not in HTTP>=1.0)");
554  free(tmp);
555  return GWEN_ERROR_INVALID;
556  }
557  else {
558  GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", s);
559  }
560 
561  free(tmp);
562  return 0;
563 }
564 
565 
566 
568  GWEN_SYNCIO_HTTP *xio;
569  GWEN_SYNCIO *baseIo;
570  GWEN_BUFFER *tbuf;
571  int rv;
572 
573  assert(sio);
574  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
575  assert(xio);
576 
577  DBG_INFO(GWEN_LOGDOMAIN, "Reading status");
578  baseIo=GWEN_SyncIo_GetBaseIo(sio);
579  assert(baseIo);
580 
581  /* read a single line */
582  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
583  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
584  if (rv<0) {
585  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
586  GWEN_Buffer_free(tbuf);
587  return rv;
588  }
589 
590  if (*GWEN_Buffer_GetStart(tbuf)==0) {
591  DBG_INFO(GWEN_LOGDOMAIN, "Empty line received while reading status response, assuming EOF");
592  GWEN_Buffer_free(tbuf);
593  return GWEN_ERROR_EOF;
594  }
595 
597  if (rv<0) {
598  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
599  GWEN_Buffer_free(tbuf);
600  return rv;
601  }
602 
603  GWEN_Buffer_free(tbuf);
604  return 0;
605 }
606 
607 
608 
610  GWEN_SYNCIO_HTTP *xio;
611  GWEN_SYNCIO *baseIo;
612  GWEN_BUFFER *tbuf;
613  int rv;
614 
615  assert(sio);
616  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
617  assert(xio);
618 
619  DBG_INFO(GWEN_LOGDOMAIN, "Reading command");
620  baseIo=GWEN_SyncIo_GetBaseIo(sio);
621  assert(baseIo);
622 
623  /* read a single line */
624  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
625  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
626  if (rv<0) {
627  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
628  GWEN_Buffer_free(tbuf);
629  return rv;
630  }
631 
633  if (rv<0) {
634  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
635  GWEN_Buffer_free(tbuf);
636  return rv;
637  }
638 
639  GWEN_Buffer_free(tbuf);
640  return 0;
641 }
642 
643 
644 
646  GWEN_SYNCIO_HTTP *xio;
647  GWEN_SYNCIO *baseIo;
648  char *p;
649  const char *s;
650 
651  assert(sio);
652  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
653  assert(xio);
654 
655  baseIo=GWEN_SyncIo_GetBaseIo(sio);
656  assert(baseIo);
657 
658  /* resolve line continuations */
659  p=buf;
660  while(*p) {
661  p=strchr(p, 10);
662  if (p) {
663  if (p[1]==32 || p[1]==9)
664  /* found a continuation */
665  *p=32;
666  p++;
667  }
668  }
669 
670  /* parse every line */
671  p=buf;
672  while(p && *p) {
673  char *pNext;
674  char *pVarBegin;
675  char *pVarEnd;
676 
677  /* skip blanks */
678  pNext=strchr(p, 10);
679  if (pNext) {
680  *pNext=0;
681  pNext++;
682  }
683  while(*p && (*p==32 || *p==9))
684  p++;
685  if (*p) {
686  pVarBegin=p;
687  while(*p && *p!=':' && *p>32 && *p<127)
688  p++;
689  pVarEnd=p;
690  if (*p!=':') {
691  DBG_INFO(GWEN_LOGDOMAIN, "No separator after variable name in received header");
692  return GWEN_ERROR_BAD_DATA;
693  }
694  *pVarEnd=0;
695  p++;
696 
697  while(*p && (*p==32 || *p==9))
698  p++;
699  if (*p)
700  GWEN_DB_SetCharValue(xio->dbHeaderIn, GWEN_PATH_FLAGS_CREATE_VAR, pVarBegin, p);
701  }
702  p=pNext;
703  }
704 
705  /* default next mode after reading the header is reading the body
706  * (if any, but that will be checked later) */
707  xio->readMode=GWEN_SyncIo_Http_Mode_Body;
708 
709  /* header received, now read some settings from it */
710  s=GWEN_DB_GetCharValue(xio->dbHeaderIn, "Transfer-Encoding", 0, 0);
711  if (s && (-1!=GWEN_Text_ComparePattern(s, "*chunked*", 0))) {
712  /* chunked encoding, this means next we have to read the chunksize */
713  DBG_DEBUG(GWEN_LOGDOMAIN, "Body is \"chunked\"");
714  xio->currentReadChunkSize=-1;
715  xio->readMode=GWEN_SyncIo_Http_Mode_ChunkSize;
716  }
717 
718  /* get size of body */
719  xio->currentReadBodySize=GWEN_DB_GetIntValue(xio->dbHeaderIn, "Content-Length", 0, -1);
720  if (xio->currentReadBodySize==0) {
721  /* no body */
723  }
724  else if (xio->currentReadBodySize==-1) {
725  int rcode;
726 
727  /* no length of body received, assume 0 in case of an error
728  * This eliminates the bug where this module waits for
729  * a timeout when receiving an error from a special server
730  */
731  rcode=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, -1);
732  if (rcode<0 || rcode>=300) {
733  /* no body */
735  }
736  }
737 
738  return 0;
739 }
740 
741 
742 
744  GWEN_SYNCIO_HTTP *xio;
745  GWEN_SYNCIO *baseIo;
746  GWEN_BUFFER *tbuf;
747  int rv;
748  uint32_t pos;
749  int lines=0;
750 
751  assert(sio);
752  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
753  assert(xio);
754 
755  DBG_INFO(GWEN_LOGDOMAIN, "Reading header");
756  baseIo=GWEN_SyncIo_GetBaseIo(sio);
757  assert(baseIo);
758 
759  /* we want to read a text line, so we can't have a transparent mode in the base layer */
761 
762  /* read a single line */
763  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
764  pos=0;
765  do {
766  uint8_t *p;
767 
768  GWEN_Buffer_AllocRoom(tbuf, 1024);
769  p=(uint8_t*) GWEN_Buffer_GetPosPointer(tbuf);
770  rv=GWEN_SyncIo_Read(baseIo, p, 1024);
771  if (rv<0) {
772  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
773  GWEN_Buffer_free(tbuf);
774  return rv;
775  }
776  else if (rv>0) {
777  GWEN_Buffer_IncrementPos(tbuf, rv);
779  if (p[rv-1]==10) {
780  uint32_t npos;
781 
782  lines++;
783  npos=GWEN_Buffer_GetPos(tbuf);
784  if ((npos-pos)==1) {
785  /* empty line, header finished */
786  break;
787  }
788  pos=npos;
789  }
790  }
791  else if (rv==0)
792  break;
793  } while(rv>0);
794 
795  if (lines<1) {
796  DBG_ERROR(GWEN_LOGDOMAIN, "No header line received");
797  GWEN_Buffer_free(tbuf);
798  return GWEN_ERROR_EOF;
799  }
800 
802  if (rv<0) {
803  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
804  GWEN_Buffer_free(tbuf);
805  return rv;
806  }
807 
808  GWEN_Buffer_free(tbuf);
809  return 0;
810 }
811 
812 
813 
815  GWEN_SYNCIO_HTTP *xio;
816  GWEN_SYNCIO *baseIo;
817  GWEN_BUFFER *tbuf;
818  int rv;
819  int csize;
820 
821  assert(sio);
822  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
823  assert(xio);
824 
825  DBG_INFO(GWEN_LOGDOMAIN, "Reading chunksize");
826  baseIo=GWEN_SyncIo_GetBaseIo(sio);
827  assert(baseIo);
828 
829  /* read a single line */
830  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
831  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
832  if (rv<0) {
833  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
834  GWEN_Buffer_free(tbuf);
835  return rv;
836  }
837 
838  if (*GWEN_Buffer_GetStart(tbuf)==0) {
839  GWEN_Buffer_Reset(tbuf);
840  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
841  if (rv<0) {
842  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
843  GWEN_Buffer_free(tbuf);
844  return rv;
845  }
846  }
847 
848  if (1!=sscanf(GWEN_Buffer_GetStart(tbuf), "%x", &csize)) {
849  DBG_ERROR(GWEN_LOGDOMAIN, "Bad data received (invalid chunksize specifier: [%s])",
850  GWEN_Buffer_GetStart(tbuf));
851  GWEN_Buffer_free(tbuf);
852  return GWEN_ERROR_BAD_DATA;
853  }
854 
855  xio->currentReadChunkSize=csize;
856 
857  GWEN_Buffer_free(tbuf);
858  return 0;
859 }
860 
861 
862 
863 int GWEN_SyncIo_Http_ReadChunk(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size) {
864  GWEN_SYNCIO_HTTP *xio;
865  GWEN_SYNCIO *baseIo;
866  int rv;
867 
868  assert(sio);
869  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
870  assert(xio);
871 
872  DBG_DEBUG(GWEN_LOGDOMAIN, "Reading chunk (%d bytes)", (int) size);
873  baseIo=GWEN_SyncIo_GetBaseIo(sio);
874  assert(baseIo);
875 
876  /* we want to read binary data transparently */
878 
879  if (size>xio->currentReadChunkSize)
880  size=xio->currentReadChunkSize;
881 
882  rv=GWEN_SyncIo_Read(baseIo, buffer, size);
883  if (rv<0) {
884  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
885  return rv;
886  }
887 
888  xio->currentReadChunkSize-=rv;
889  if (xio->currentReadBodySize>0)
890  xio->currentReadBodySize-=rv;
891 
892  if (xio->currentReadChunkSize==0) {
893  int rv2;
894  GWEN_BUFFER *tbuf;
895 
896  /* chunk finished, read trailing CR/LF */
897  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
898  rv2=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
899  if (rv2<0) {
900  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
901  GWEN_Buffer_free(tbuf);
902  return rv2;
903  }
904  GWEN_Buffer_free(tbuf);
905 
906  DBG_DEBUG(GWEN_LOGDOMAIN, "Chunk finished.");
907 
908  /* change read mode */
909  xio->readMode=GWEN_SyncIo_Http_Mode_ChunkSize;
910  }
911 
912  return rv;
913 }
914 
915 
916 
917 int GWEN_SyncIo_Http_ReadBody(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size) {
918  GWEN_SYNCIO_HTTP *xio;
919  GWEN_SYNCIO *baseIo;
920  int rv;
921 
922  assert(size);
923 
924  assert(sio);
925  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
926  assert(xio);
927 
928  DBG_INFO(GWEN_LOGDOMAIN, "Reading body");
929  baseIo=GWEN_SyncIo_GetBaseIo(sio);
930  assert(baseIo);
931 
932  /* we want to read binary data transparently */
934 
935  if ((xio->currentReadBodySize>=0) &&
936  (size>xio->currentReadBodySize)) {
937  DBG_INFO(GWEN_LOGDOMAIN, "Adjusting read body size from %d to %d",
938  size, xio->currentReadBodySize);
939  size=xio->currentReadBodySize;
940  }
941 
942  rv=GWEN_SyncIo_Read(baseIo, buffer, size);
943  if (rv<0) {
944  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
945  return rv;
946  }
947 
948  if (xio->currentReadBodySize>=0)
949  xio->currentReadBodySize-=rv;
950 
951  if (xio->currentReadBodySize==0)
952  /* body finished, change read mode */
954 
955  return rv;
956 }
957 
958 
959 
961  GWEN_SYNCIO_HTTP *xio;
962  GWEN_SYNCIO *baseIo;
963  int rv;
964  const char *s;
965  GWEN_BUFFER *tbuf;
966 
967  assert(sio);
968  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
969  assert(xio);
970 
971  baseIo=GWEN_SyncIo_GetBaseIo(sio);
972  assert(baseIo);
973 
974  /* we will construct the line including CR/LF ourselves */
976 
977  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
978 
979  s=GWEN_DB_GetCharValue(xio->dbCommandOut, "command", 0, "GET");
980  GWEN_Buffer_AppendString(tbuf, s);
981  GWEN_Buffer_AppendString(tbuf, " ");
982 
983  s=GWEN_DB_GetCharValue(xio->dbCommandOut, "url", 0, "/");
984  GWEN_Buffer_AppendString(tbuf, s);
985  GWEN_Buffer_AppendString(tbuf, " ");
986 
987  s=GWEN_DB_GetCharValue(xio->dbCommandOut, "protocol", 0, "HTTP/1.0");
988  GWEN_Buffer_AppendString(tbuf, s);
989  GWEN_Buffer_AppendString(tbuf, "\r\n");
990 
991  /* write */
992  rv=GWEN_SyncIo_WriteForced(baseIo,
993  (const uint8_t*) GWEN_Buffer_GetStart(tbuf),
995  if (rv<0) {
996  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
997  GWEN_Buffer_free(tbuf);
998  return rv;
999  }
1000 
1001  GWEN_Buffer_free(tbuf);
1002  return 0;
1003 }
1004 
1005 
1006 
1008  GWEN_SYNCIO_HTTP *xio;
1009  GWEN_SYNCIO *baseIo;
1010  int rv;
1011  const char *s;
1012  GWEN_BUFFER *tbuf;
1013  char numbuf[32];
1014  int i;
1015 
1016  assert(sio);
1017  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1018  assert(xio);
1019 
1020  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1021  assert(baseIo);
1022 
1023  /* we will construct the line including CR/LF ourselves */
1025 
1026  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
1027 
1028  s=GWEN_DB_GetCharValue(xio->dbStatusOut, "protocol", 0, "HTTP/1.0");
1029  GWEN_Buffer_AppendString(tbuf, s);
1030  GWEN_Buffer_AppendString(tbuf, " ");
1031 
1032  i=GWEN_DB_GetIntValue(xio->dbStatusOut, "code", 0, -1);
1033  if (i==-1) {
1034  DBG_INFO(GWEN_LOGDOMAIN, "Missing status code");
1035  GWEN_Buffer_free(tbuf);
1036  return GWEN_ERROR_NO_DATA;
1037  }
1038  snprintf(numbuf, sizeof(numbuf), "%d ", i);
1039  GWEN_Buffer_AppendString(tbuf, numbuf);
1040 
1041  s=GWEN_DB_GetCharValue(xio->dbStatusOut, "text", 0, "No text.");
1042  GWEN_Buffer_AppendString(tbuf, s);
1043  GWEN_Buffer_AppendString(tbuf, "\r\n");
1044 
1045  /* write */
1046  rv=GWEN_SyncIo_WriteForced(baseIo,
1047  (const uint8_t*) GWEN_Buffer_GetStart(tbuf),
1048  GWEN_Buffer_GetUsedBytes(tbuf));
1049  if (rv<0) {
1050  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1051  GWEN_Buffer_free(tbuf);
1052  return rv;
1053  }
1054 
1055  GWEN_Buffer_free(tbuf);
1056  return 0;
1057 }
1058 
1059 
1060 
1062  GWEN_SYNCIO_HTTP *xio;
1063  GWEN_SYNCIO *baseIo;
1064  int i;
1065  GWEN_DB_NODE *dbVar;
1066  GWEN_BUFFER *tbuf;
1067  int rv;
1068 
1069  assert(sio);
1070  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1071  assert(xio);
1072 
1073  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1074  assert(baseIo);
1075 
1076  /* we will construct the line including CR/LF ourselves */
1078 
1079  /* default next mode after writing the header is writing the body
1080  * (if any, but that will be checked later) */
1081  xio->writeMode=GWEN_SyncIo_Http_Mode_Body;
1082 
1083  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
1084 
1085  i=GWEN_DB_GetIntValue(xio->dbHeaderOut, "Content-Length", 0, -1);
1086  xio->currentWriteBodySize=i;
1087 
1088  dbVar=GWEN_DB_GetFirstVar(xio->dbHeaderOut);
1089  while (dbVar) {
1090  GWEN_DB_NODE *dbVal;
1091 
1092  /* only handle first value */
1093  dbVal=GWEN_DB_GetFirstValue(dbVar);
1094  if (dbVal) {
1095  GWEN_DB_NODE_TYPE vtype;
1096 
1097  vtype=GWEN_DB_GetValueType(dbVal);
1098  if (vtype==GWEN_DB_NodeType_ValueChar) {
1099  const char *s;
1100 
1102  GWEN_Buffer_AppendString(tbuf, ":");
1104  if (s)
1105  GWEN_Buffer_AppendString(tbuf, s);
1106  GWEN_Buffer_AppendString(tbuf, "\r\n");
1107 
1108  if (strcasecmp(GWEN_DB_VariableName(dbVar), "Transfer-Encoding")==0) {
1109  if (s && (-1!=GWEN_Text_ComparePattern(s, "*chunked*", 0))) {
1110  /* chunked encoding, this means next we have to write the chunksize */
1111  xio->writeMode=GWEN_SyncIo_Http_Mode_ChunkSize;
1112  }
1113  }
1114  }
1115  else if (vtype==GWEN_DB_NodeType_ValueInt) {
1116  i=GWEN_DB_GetIntValueFromNode(dbVal);
1117  if (i!=-1 || strcasecmp(GWEN_DB_VariableName(dbVar), "Content-Length")==0) {
1118  char numbuf[32];
1119 
1120  /* don't write body size of -1 */
1122  GWEN_Buffer_AppendString(tbuf, ":");
1123  snprintf(numbuf, sizeof(numbuf), "%d", i);
1124  GWEN_Buffer_AppendString(tbuf, numbuf);
1125  GWEN_Buffer_AppendString(tbuf, "\r\n");
1126  }
1127  }
1128  else {
1129  DBG_INFO(GWEN_LOGDOMAIN, "Variable type %d of var [%s] not supported",
1130  vtype, GWEN_DB_VariableName(dbVar));
1131  return GWEN_ERROR_BAD_DATA;
1132  }
1133  }
1134  dbVar=GWEN_DB_GetNextVar(dbVar);
1135  }
1136 
1137  /* finalize header */
1138  GWEN_Buffer_AppendString(tbuf, "\r\n");
1139 
1140  /* write */
1141  rv=GWEN_SyncIo_WriteForced(baseIo,
1142  (const uint8_t*) GWEN_Buffer_GetStart(tbuf),
1143  GWEN_Buffer_GetUsedBytes(tbuf));
1144  if (rv<0) {
1145  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1146  GWEN_Buffer_free(tbuf);
1147  return rv;
1148  }
1149  GWEN_Buffer_free(tbuf);
1150 
1151  if (xio->currentWriteBodySize==0)
1153 
1154  return 0;
1155 }
1156 
1157 
1158 
1160  GWEN_SYNCIO_HTTP *xio;
1161  GWEN_SYNCIO *baseIo;
1162  int rv;
1163  char numbuf[32];
1164 
1165  assert(sio);
1166  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1167  assert(xio);
1168 
1169  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1170  assert(baseIo);
1171 
1172  /* we will construct the line including CR/LF ourselves */
1174 
1175  snprintf(numbuf, sizeof(numbuf)-1, "%x\r\n", size);
1176  numbuf[sizeof(numbuf)-1]=0;
1177 
1178  rv=GWEN_SyncIo_WriteForced(baseIo, (const uint8_t*) numbuf, strlen(numbuf));
1179  if (rv<0) {
1180  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1181  return rv;
1182  }
1183 
1184  return 0;
1185 }
1186 
1187 
1188 
1190  GWEN_SYNCIO_HTTP *xio;
1191 
1192  assert(sio);
1193  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1194  assert(xio);
1195 
1196  xio->writeMode=GWEN_SyncIo_Http_Mode_Idle;
1197  GWEN_DB_ClearGroup(xio->dbStatusOut, NULL);
1198 }
1199 
1200 
1201 
1202 
1204  GWEN_SYNCIO_HTTP *xio;
1205 
1206  assert(sio);
1207  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1208  assert(xio);
1209 
1210  return xio->dbCommandIn;
1211 }
1212 
1213 
1214 
1216  GWEN_SYNCIO_HTTP *xio;
1217 
1218  assert(sio);
1219  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1220  assert(xio);
1221 
1222  return xio->dbStatusIn;
1223 }
1224 
1225 
1226 
1228  GWEN_SYNCIO_HTTP *xio;
1229 
1230  assert(sio);
1231  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1232  assert(xio);
1233 
1234  return xio->dbHeaderIn;
1235 }
1236 
1237 
1238 
1240  GWEN_SYNCIO_HTTP *xio;
1241 
1242  assert(sio);
1243  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1244  assert(xio);
1245 
1246  return xio->dbCommandOut;
1247 }
1248 
1249 
1250 
1252  GWEN_SYNCIO_HTTP *xio;
1253 
1254  assert(sio);
1255  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1256  assert(xio);
1257 
1258  return xio->dbStatusOut;
1259 }
1260 
1261 
1262 
1264  GWEN_SYNCIO_HTTP *xio;
1265 
1266  assert(sio);
1267  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1268  assert(xio);
1269 
1270  return xio->dbHeaderOut;
1271 }
1272 
1273 
1274 
1275 
1277  GWEN_SYNCIO_HTTP *xio;
1278  int rv;
1279  int code=0;
1280  int firstRead=1;
1281  int bodySize=-1;
1282  int bytesRead=0;
1283  uint32_t pid;
1284 
1285  assert(sio);
1286  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1287  assert(xio);
1288 
1293  I18N("Network Operation"),
1294  I18N("Receiving data"),
1295  0,
1296  0);
1297 
1298 
1299  /* recv packet (this reads the HTTP body) */
1300  for (;;) {
1301  uint8_t *p;
1302  uint32_t l;
1303 
1304  rv=GWEN_Buffer_AllocRoom(buf, 1024);
1305  if (rv<0) {
1306  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1307  GWEN_Gui_ProgressEnd(pid);
1308  return rv;
1309  }
1310 
1311  p=(uint8_t*) GWEN_Buffer_GetPosPointer(buf);
1313  do {
1314  rv=GWEN_SyncIo_Read(sio, p, l-1);
1315  } while(rv==GWEN_ERROR_INTERRUPTED);
1316 
1317  if (rv==0)
1318  break;
1319  else if (rv<0) {
1320  if (rv==GWEN_ERROR_EOF) {
1321  if (bodySize!=-1 && bytesRead<bodySize) {
1323  "EOF met prematurely (%d < %d)",
1324  bytesRead, bodySize);
1325  GWEN_Gui_ProgressEnd(pid);
1326  return GWEN_ERROR_EOF;
1327  }
1328  }
1329  else {
1330  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1331  /*return rv;*/
1332  break;
1333  }
1334  }
1335  else {
1336  GWEN_Buffer_IncrementPos(buf, rv);
1338  if (firstRead) {
1339  GWEN_DB_NODE *db;
1340 
1342  bodySize=GWEN_DB_GetIntValue(db, "Content-length", 0, -1);
1343 
1344  if (bodySize!=-1)
1345  GWEN_Gui_ProgressSetTotal(pid, bodySize);
1346  }
1347  bytesRead+=rv;
1348 
1349  /* advance progress bar */
1350  rv=GWEN_Gui_ProgressAdvance(pid, bytesRead);
1351  if (rv==GWEN_ERROR_USER_ABORTED) {
1352  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1353  GWEN_Gui_ProgressEnd(pid);
1354  return rv;
1355  }
1356  }
1357 
1358  if (bodySize!=-1 && bytesRead>=bodySize) {
1359  break;
1360  }
1361 
1362  firstRead=0;
1363  }
1364  GWEN_Gui_ProgressEnd(pid);
1365 
1366  if (rv<0) {
1367  if (GWEN_Buffer_GetUsedBytes(buf)) {
1368  /* data received, check for common error codes */
1369  if (rv==GWEN_ERROR_EOF || rv==GWEN_ERROR_IO || rv==GWEN_ERROR_SSL) {
1371  "We received an error, but we still got data, "
1372  "so we ignore the error here");
1373  }
1374  else {
1375  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1378  I18N("No message received"));
1379  return rv;
1380  }
1381  }
1382  else {
1383  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1386  I18N("No message received"));
1387  return rv;
1388  }
1389  }
1390 
1392  code=0;
1393  else {
1394  code=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, 0);
1395  if (code) {
1396  const char *s;
1397 
1398  s=GWEN_DB_GetCharValue(xio->dbStatusIn, "text", 0, NULL);
1399  DBG_DEBUG(GWEN_LOGDOMAIN, "HTTP-Status: %d (%s)",
1400  code, s?s:"- no text -");
1402  I18N("HTTP-Status: %d (%s)"),
1403  code, s?s:I18N("- no details -)"));
1404  }
1405  else {
1406  DBG_ERROR(GWEN_LOGDOMAIN, "No HTTP status code received");
1409  I18N("No HTTP status code received"));
1410  code=GWEN_ERROR_BAD_DATA;
1411  }
1412  }
1413 
1414  return code;
1415 }
1416 
1417 
1418 
1420  GWEN_SYNCIO_HTTP *xio;
1421  int rv;
1422  int code=0;
1423  int firstRead=1;
1424  int bodySize=-1;
1425  int bytesRead=0;
1426  uint32_t pid;
1427 
1428  assert(sio);
1429  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1430  assert(xio);
1431 
1436  I18N("Network Operation"),
1437  I18N("Receiving data"),
1438  0,
1439  0);
1440 
1441  /* recv packet (this reads the HTTP body) */
1442  for (;;) {
1443  uint8_t *p;
1444  uint32_t l;
1445  uint8_t rbuf[1024];
1446 
1447  p=rbuf;
1448  l=sizeof(rbuf);
1449 
1450  do {
1451  rv=GWEN_SyncIo_Read(sio, p, l-1);
1452  } while(rv==GWEN_ERROR_INTERRUPTED);
1453 
1454  if (rv==0)
1455  break;
1456  else if (rv<0) {
1457  if (rv==GWEN_ERROR_EOF) {
1458  if (bodySize!=-1 && bytesRead<bodySize) {
1460  "EOF met prematurely (%d < %d)",
1461  bytesRead, bodySize);
1462  GWEN_Gui_ProgressEnd(pid);
1463  return GWEN_ERROR_EOF;
1464  }
1465  }
1466  else {
1467  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1468  /*return rv;*/
1469  break;
1470  }
1471  }
1472  else {
1473  int rv2;
1474 
1475  rv2=GWEN_SyncIo_WriteForced(sout, rbuf, rv);
1476  if (rv2<0) {
1477  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
1478  GWEN_Gui_ProgressEnd(pid);
1479  return rv2;
1480  }
1481  if (firstRead) {
1482  GWEN_DB_NODE *db;
1483 
1485  bodySize=GWEN_DB_GetIntValue(db, "Content-length", 0, -1);
1486 
1487  if (bodySize!=-1)
1488  GWEN_Gui_ProgressSetTotal(pid, bodySize);
1489  }
1490  bytesRead+=rv;
1491 
1492  /* advance progress bar */
1493  rv=GWEN_Gui_ProgressAdvance(pid, bytesRead);
1494  if (rv==GWEN_ERROR_USER_ABORTED) {
1495  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1496  GWEN_Gui_ProgressEnd(pid);
1497  return rv;
1498  }
1499  }
1500 
1501  if (bodySize!=-1 && bytesRead>=bodySize) {
1502  break;
1503  }
1504  firstRead=0;
1505  }
1506  GWEN_Gui_ProgressEnd(pid);
1507 
1508 
1509  if (rv<0) {
1510  if (bytesRead) {
1511  /* data received, check for common error codes */
1512  if (rv==GWEN_ERROR_EOF || rv==GWEN_ERROR_IO || rv==GWEN_ERROR_SSL) {
1514  "We received an error, but we still got data, "
1515  "so we ignore the error here");
1516  }
1517  else {
1518  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1521  I18N("No message received"));
1522  return rv;
1523  }
1524  }
1525  else {
1526  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1529  I18N("No message received"));
1530  return rv;
1531  }
1532  }
1533 
1535  code=0;
1536  else {
1537  code=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, 0);
1538  if (code) {
1539  const char *s;
1540 
1541  s=GWEN_DB_GetCharValue(xio->dbStatusIn, "text", 0, NULL);
1542  DBG_DEBUG(GWEN_LOGDOMAIN, "HTTP-Status: %d (%s)",
1543  code, s?s:"- no text -");
1545  I18N("HTTP-Status: %d (%s)"),
1546  code, s?s:I18N("- no details -)"));
1547  }
1548  else {
1549  DBG_ERROR(GWEN_LOGDOMAIN, "No HTTP status code received");
1552  I18N("No HTTP status code received"));
1553  code=GWEN_ERROR_BAD_DATA;
1554  }
1555  }
1556 
1557  return code;
1558 }
1559 
1560 
1561 
1562