gwenhywfar  5.10.1
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 {
54  GWEN_SYNCIO *sio;
55  GWEN_SYNCIO_HTTP *xio;
56 
58  GWEN_NEW_OBJECT(GWEN_SYNCIO_HTTP, xio);
59  GWEN_INHERIT_SETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio, xio, GWEN_SyncIo_Http_FreeData);
60 
65 
66  xio->dbCommandIn=GWEN_DB_Group_new("command");
67  xio->dbStatusIn=GWEN_DB_Group_new("status");
68  xio->dbHeaderIn=GWEN_DB_Group_new("header");
69 
70  xio->dbCommandOut=GWEN_DB_Group_new("command");
71  xio->dbStatusOut=GWEN_DB_Group_new("status");
72  xio->dbHeaderOut=GWEN_DB_Group_new("header");
73 
74 
75  return sio;
76 }
77 
78 
79 
81 {
82  GWEN_SYNCIO_HTTP *xio;
83 
84  xio=(GWEN_SYNCIO_HTTP *) p;
85 
86  GWEN_DB_Group_free(xio->dbCommandOut);
87  GWEN_DB_Group_free(xio->dbStatusOut);
88  GWEN_DB_Group_free(xio->dbHeaderOut);
89 
90  GWEN_DB_Group_free(xio->dbCommandIn);
91  GWEN_DB_Group_free(xio->dbStatusIn);
92  GWEN_DB_Group_free(xio->dbHeaderIn);
93 
94  GWEN_FREE_OBJECT(xio);
95 }
96 
97 
98 
100 {
101  GWEN_SYNCIO_HTTP *xio;
102  GWEN_SYNCIO *baseIo;
103  int rv;
104 
105  assert(sio);
106  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
107  assert(xio);
108 
110  DBG_INFO(GWEN_LOGDOMAIN, "Already connected");
111  return 0;
112  }
113 
114  baseIo=GWEN_SyncIo_GetBaseIo(sio);
115  assert(baseIo);
116 
117  rv=GWEN_SyncIo_Connect(baseIo);
118  if (rv<0) {
119  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
120  return rv;
121  }
122 
125 
126  return 0;
127 }
128 
129 
130 
132 {
133  GWEN_SYNCIO_HTTP *xio;
134  GWEN_SYNCIO *baseIo;
135  int rv;
136 
137  assert(sio);
138  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
139  assert(xio);
140 
142  DBG_INFO(GWEN_LOGDOMAIN, "Not connected");
144  }
145 
146  baseIo=GWEN_SyncIo_GetBaseIo(sio);
147  assert(baseIo);
148 
149  rv=GWEN_SyncIo_Disconnect(baseIo);
151  if (rv<0) {
152  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
153  return rv;
154  }
155 
156  return 0;
157 }
158 
159 
160 
162 {
163  GWEN_SYNCIO_HTTP *xio;
164 
165  assert(sio);
166  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
167  assert(xio);
168 
169  xio->readMode=GWEN_SyncIo_Http_Mode_Idle;
170 }
171 
172 
173 
175  uint8_t *buffer,
176  uint32_t size)
177 {
178  GWEN_SYNCIO_HTTP *xio;
179  int rv;
180 
181  assert(sio);
182  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
183  assert(xio);
184 
186  DBG_ERROR(GWEN_LOGDOMAIN, "Not connected");
188  }
189 
190  if (xio->readMode==GWEN_SyncIo_Http_Mode_Idle) {
191  const char *s;
192 
193  /* reset status and headers */
194  GWEN_DB_ClearGroup(xio->dbCommandIn, NULL);
195  GWEN_DB_ClearGroup(xio->dbStatusIn, NULL);
196  GWEN_DB_ClearGroup(xio->dbHeaderIn, NULL);
197 
199  /* read command */
201  if (rv<0) {
202  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
203  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
204  return rv;
205  }
206 
207  /* possibly read header */
208  s=GWEN_DB_GetCharValue(xio->dbCommandIn, "protocol", 0, "HTTP/1.0");
209  if (!(s && strcasecmp(s, "HTTP/0.9")==0)) {
211  if (rv<0) {
212  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
213  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
214  return rv;
215  }
216  }
217  }
218  else {
219  /* read status */
221  if (rv<0) {
222  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
223  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
224  return rv;
225  }
226 
227  /* possibly read header */
228  s=GWEN_DB_GetCharValue(xio->dbStatusIn, "protocol", 0, "HTTP/1.0");
229  if (!(s && strcasecmp(s, "HTTP/0.9")==0)) {
231  if (rv<0) {
232  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
233  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
234  return rv;
235  }
236  }
237  }
238 
239  }
240 
241  if (xio->readMode==GWEN_SyncIo_Http_Mode_ChunkSize) {
243  if (rv<0) {
244  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
245  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
246  return rv;
247  }
248  if (xio->currentReadChunkSize==0) {
249  int rv2;
250  GWEN_BUFFER *tbuf;
251 
252  /* all chunks finished, read trailing CR/LF */
253  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
254  rv2=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
255  if (rv2<0) {
256  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
257  GWEN_Buffer_free(tbuf);
258  return rv2;
259  }
260  GWEN_Buffer_free(tbuf);
261 
262  DBG_DEBUG(GWEN_LOGDOMAIN, "Chunks finished.");
263 
264  /* chunksize is 0, body ended */
266  return 0;
267  }
268  else if (xio->currentReadChunkSize==-1) {
269  DBG_ERROR(GWEN_LOGDOMAIN, "Undetermined chunksize in chunked mode? Aborting.");
270  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
271  return GWEN_ERROR_BAD_DATA;
272  }
273 
274  /* chunksize known, next will be to read that chunk */
275  xio->readMode=GWEN_SyncIo_Http_Mode_Chunk;
276  }
277 
278  if (xio->readMode==GWEN_SyncIo_Http_Mode_Chunk) {
279  /* read chunk */
280  rv=GWEN_SyncIo_Http_ReadChunk(sio, buffer, size);
281  if (rv<0) {
282  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
283  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
284  return rv;
285  }
286 
287  return rv;
288  }
289 
290  if (xio->readMode==GWEN_SyncIo_Http_Mode_Body) {
291  /* read chunk */
292  rv=GWEN_SyncIo_Http_ReadBody(sio, buffer, size);
293  if (rv<0) {
294  xio->readMode=GWEN_SyncIo_Http_Mode_Error;
295  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
296  return rv;
297  }
298 
299  return rv;
300  }
301 
302  if (xio->readMode==GWEN_SyncIo_Http_Mode_Error) {
303  DBG_ERROR(GWEN_LOGDOMAIN, "Previous read error");
304  return GWEN_ERROR_GENERIC;
305  }
306 
307  return 0;
308 }
309 
310 
311 
313  const uint8_t *buffer,
314  uint32_t size)
315 {
316  GWEN_SYNCIO_HTTP *xio;
317  GWEN_SYNCIO *baseIo;
318  int rv;
319 
320  assert(sio);
321  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
322  assert(xio);
323 
324  baseIo=GWEN_SyncIo_GetBaseIo(sio);
325  assert(baseIo);
326 
328  DBG_ERROR(GWEN_LOGDOMAIN, "Not connected");
330  }
331 
332  if (xio->writeMode==GWEN_SyncIo_Http_Mode_Idle) {
333  const char *s;
334 
336  /* write status */
338  else
339  /* write command */
341  if (rv<0) {
342  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
343  return rv;
344  }
345 
346  /* possibly write header */
347  s=GWEN_DB_GetCharValue(xio->dbCommandOut, "protocol", 0, "HTTP/1.0");
348  if (!(s && strcasecmp(s, "HTTP/0.9")==0)) {
350  if (rv<0) {
351  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
352  return rv;
353  }
354  }
355  }
356 
357  if (xio->writeMode==GWEN_SyncIo_Http_Mode_ChunkSize) {
358  rv=GWEN_SyncIo_Http_WriteChunkSize(sio, size);
359  if (rv<0) {
360  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
361  return rv;
362  }
363  if (size==0) {
364  /* chunksize is 0, body ended */
366  return 0;
367  }
368 
369  /* chunksize known, next will be to write that chunk */
370  xio->writeMode=GWEN_SyncIo_Http_Mode_Chunk;
371  }
372 
373  if (xio->writeMode==GWEN_SyncIo_Http_Mode_Chunk) {
374  /* we want to write binary data transparently */
376  rv=GWEN_SyncIo_WriteForced(baseIo, buffer, size);
377  if (rv<0) {
378  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
379  return rv;
380  }
381  xio->writeMode=GWEN_SyncIo_Http_Mode_ChunkSize;
382 
383  return rv;
384  }
385 
386  if (xio->writeMode==GWEN_SyncIo_Http_Mode_Body) {
387  if ((xio->currentWriteBodySize!=-1) &&
388  ((int)size>xio->currentWriteBodySize)) {
389  DBG_ERROR(GWEN_LOGDOMAIN, "Size is beyond total body size (%d)!", size);
390  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
391  return GWEN_ERROR_INVALID;
392  }
393 
394  /* we want to write binary data transparently */
396  rv=GWEN_SyncIo_WriteForced(baseIo, buffer, size);
397  if (rv<0) {
398  xio->writeMode=GWEN_SyncIo_Http_Mode_Error;
399  return rv;
400  }
401  if (xio->currentWriteBodySize!=-1) {
402  xio->currentWriteBodySize-=rv;
403  if (xio->currentWriteBodySize==0)
405  }
406 
407  return rv;
408  }
409 
410  if (xio->writeMode==GWEN_SyncIo_Http_Mode_Error) {
411  DBG_ERROR(GWEN_LOGDOMAIN, "Previous write error");
412  return GWEN_ERROR_GENERIC;
413  }
414 
415  return 0;
416 }
417 
418 
419 
421 {
422  GWEN_SYNCIO_HTTP *xio;
423  GWEN_SYNCIO *baseIo;
424  int rv;
425 
426  assert(sio);
427  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
428  assert(xio);
429 
430  baseIo=GWEN_SyncIo_GetBaseIo(sio);
431  assert(baseIo);
432 
433  /* we want to read a text line, so we can't have a transparent mode in the base layer */
435 
436  /* read a single line */
437  do {
438  uint8_t *p;
439  uint32_t l;
440 
441  GWEN_Buffer_AllocRoom(tbuf, 1024);
442  p=(uint8_t *) GWEN_Buffer_GetPosPointer(tbuf);
444  rv=GWEN_SyncIo_Read(baseIo, p, l);
445  if (rv<0) {
446  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
447  return rv;
448  }
449  else if (rv>0) {
450  GWEN_Buffer_IncrementPos(tbuf, rv);
452  if (p[rv-1]==10) {
453  p[rv-1]=0;
454  break;
455  }
456  }
457  else if (rv==0)
458  break;
459  }
460  while (rv>0);
461 
462  if (GWEN_Buffer_GetUsedBytes(tbuf)<1) {
463  DBG_ERROR(GWEN_LOGDOMAIN, "Nothing received");
464  return GWEN_ERROR_EOF;
465  }
466 
467  return 0;
468 }
469 
470 
471 
473 {
474  GWEN_SYNCIO_HTTP *xio;
475  char *p;
476  char *s;
477  int code;
478 
479  assert(sio);
480  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
481  assert(xio);
482 
483  s=buffer;
484 
485  /* read protocol */
486  p=strchr(s, ' ');
487  if (!p) {
489  "Bad format of HTTP status (%s)", buffer);
490  return GWEN_ERROR_INVALID;
491  }
492  *p=0;
493  p++;
494 
495  GWEN_DB_SetCharValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", s);
496  s=p;
497 
498  /* read status code */
499  while (*p && isdigit((int)*p))
500  p++;
501  if (*p) {
502  *p=0;
503  p++;
504  }
505  if (1!=sscanf(s, "%d", &code)) {
506  DBG_ERROR(GWEN_LOGDOMAIN, "Bad request (status code \"%s\")", s);
507  return GWEN_ERROR_INVALID;
508  }
509  GWEN_DB_SetIntValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "code", code);
510  s=p;
511 
512  /* read text */
513  GWEN_DB_SetCharValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "text", s);
514 
515  return 0;
516 }
517 
518 
519 
520 int GWEN_SyncIo_Http_ParseCommand(GWEN_SYNCIO *sio, const char *buffer)
521 {
522  GWEN_SYNCIO_HTTP *xio;
523  char *tmp;
524  char *p;
525  char *s;
526 
527  assert(sio);
528  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
529  assert(xio);
530 
531  tmp=strdup(buffer);
532  s=tmp;
533 
534  /* read command */
535  p=strchr(s, ' ');
536  if (!p) {
538  "Bad format of HTTP request (%s)", buffer);
539  free(tmp);
540  return GWEN_ERROR_INVALID;
541  }
542  *p=0;
543  p++;
544 
545  GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "command", s);
546  s=p;
547 
548  /* read URL */
549  p=strchr(s, ' ');
550  if (!p) {
552  "Bad format of HTTP request (%s)", buffer);
553  free(tmp);
554  return GWEN_ERROR_INVALID;
555  }
556  *p=0;
557  p++;
558 
559  GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "url", s);
560  s=p;
561 
562  if (*s==0) {
563  /* no protocol information follows, so we assume HTTP/0.9 */
564  DBG_ERROR(GWEN_LOGDOMAIN, "Bad request (not in HTTP>=1.0)");
565  free(tmp);
566  return GWEN_ERROR_INVALID;
567  }
568  else {
569  GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", s);
570  }
571 
572  free(tmp);
573  return 0;
574 }
575 
576 
577 
579 {
580  GWEN_SYNCIO_HTTP *xio;
581  GWEN_SYNCIO *baseIo;
582  GWEN_BUFFER *tbuf;
583  int rv;
584 
585  assert(sio);
586  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
587  assert(xio);
588 
589  DBG_INFO(GWEN_LOGDOMAIN, "Reading status");
590  baseIo=GWEN_SyncIo_GetBaseIo(sio);
591  assert(baseIo);
592 
593  /* read a single line */
594  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
595  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
596  if (rv<0) {
597  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
598  GWEN_Buffer_free(tbuf);
599  return rv;
600  }
601 
602  if (*GWEN_Buffer_GetStart(tbuf)==0) {
603  DBG_INFO(GWEN_LOGDOMAIN, "Empty line received while reading status response, assuming EOF");
604  GWEN_Buffer_free(tbuf);
605  return GWEN_ERROR_EOF;
606  }
607 
609  DBG_DEBUG(GWEN_LOGDOMAIN, "Received HTTP status:");
610  GWEN_Text_LogString((const char *) GWEN_Buffer_GetStart(tbuf),
614  }
615 
617  if (rv<0) {
618  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
619  GWEN_Buffer_free(tbuf);
620  return rv;
621  }
622 
623  GWEN_Buffer_free(tbuf);
624  return 0;
625 }
626 
627 
628 
630 {
631  GWEN_SYNCIO_HTTP *xio;
632  GWEN_SYNCIO *baseIo;
633  GWEN_BUFFER *tbuf;
634  int rv;
635 
636  assert(sio);
637  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
638  assert(xio);
639 
640  DBG_INFO(GWEN_LOGDOMAIN, "Reading command");
641  baseIo=GWEN_SyncIo_GetBaseIo(sio);
642  assert(baseIo);
643 
644  /* read a single line */
645  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
646  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
647  if (rv<0) {
648  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
649  GWEN_Buffer_free(tbuf);
650  return rv;
651  }
652 
654  if (rv<0) {
655  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
656  GWEN_Buffer_free(tbuf);
657  return rv;
658  }
659 
660  GWEN_Buffer_free(tbuf);
661  return 0;
662 }
663 
664 
665 
667 {
668  GWEN_SYNCIO_HTTP *xio;
669  GWEN_SYNCIO *baseIo;
670  char *p;
671  const char *s;
672 
673  assert(sio);
674  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
675  assert(xio);
676 
677  baseIo=GWEN_SyncIo_GetBaseIo(sio);
678  assert(baseIo);
679 
680  /* resolve line continuations */
681  p=buf;
682  while (*p) {
683  p=strchr(p, 10);
684  if (p) {
685  if (p[1]==32 || p[1]==9)
686  /* found a continuation */
687  *p=32;
688  p++;
689  }
690  }
691 
692  /* parse every line */
693  p=buf;
694  while (p && *p) {
695  char *pNext;
696  char *pVarBegin;
697  char *pVarEnd;
698 
699  /* skip blanks */
700  pNext=strchr(p, 10);
701  if (pNext) {
702  *pNext=0;
703  pNext++;
704  }
705  while (*p && (*p==32 || *p==9))
706  p++;
707  if (*p) {
708  pVarBegin=p;
709  while (*p && *p!=':' && *p>32 && *p<127)
710  p++;
711  pVarEnd=p;
712  if (*p!=':') {
713  DBG_INFO(GWEN_LOGDOMAIN, "No separator after variable name in received header");
714  return GWEN_ERROR_BAD_DATA;
715  }
716  *pVarEnd=0;
717  p++;
718 
719  while (*p && (*p==32 || *p==9))
720  p++;
721  if (*p)
722  GWEN_DB_SetCharValue(xio->dbHeaderIn, GWEN_PATH_FLAGS_CREATE_VAR, pVarBegin, p);
723  }
724  p=pNext;
725  }
726 
727  /* default next mode after reading the header is reading the body
728  * (if any, but that will be checked later) */
729  xio->readMode=GWEN_SyncIo_Http_Mode_Body;
730 
731  /* header received, now read some settings from it */
732  s=GWEN_DB_GetCharValue(xio->dbHeaderIn, "Transfer-Encoding", 0, 0);
733  if (s && (-1!=GWEN_Text_ComparePattern(s, "*chunked*", 0))) {
734  /* chunked encoding, this means next we have to read the chunksize */
735  DBG_DEBUG(GWEN_LOGDOMAIN, "Body is \"chunked\"");
736  xio->currentReadChunkSize=-1;
737  xio->readMode=GWEN_SyncIo_Http_Mode_ChunkSize;
738  }
739 
740  /* get size of body */
741  xio->currentReadBodySize=GWEN_DB_GetIntValue(xio->dbHeaderIn, "Content-Length", 0, -1);
742  if (xio->currentReadBodySize==0) {
743  /* no body */
745  }
746  else if (xio->currentReadBodySize==-1) {
747  int rcode;
748 
749  /* no length of body received, assume 0 in case of an error
750  * This eliminates the bug where this module waits for
751  * a timeout when receiving an error from a special server
752  */
753  rcode=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, -1);
754  if (rcode<0 || rcode>=300) {
755  /* no body */
757  }
758  }
759 
760  return 0;
761 }
762 
763 
764 
766 {
767  GWEN_SYNCIO_HTTP *xio;
768  GWEN_SYNCIO *baseIo;
769  GWEN_BUFFER *tbuf;
770  int rv;
771  uint32_t pos;
772  int lines=0;
773 
774  assert(sio);
775  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
776  assert(xio);
777 
778  DBG_INFO(GWEN_LOGDOMAIN, "Reading header");
779  baseIo=GWEN_SyncIo_GetBaseIo(sio);
780  assert(baseIo);
781 
782  /* we want to read a text line, so we can't have a transparent mode in the base layer */
784 
785  /* read a single line */
786  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
787  pos=0;
788  do {
789  uint8_t *p;
790 
791  GWEN_Buffer_AllocRoom(tbuf, 1024);
792  p=(uint8_t *) GWEN_Buffer_GetPosPointer(tbuf);
793  rv=GWEN_SyncIo_Read(baseIo, p, 1024);
794  if (rv<0) {
795  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
796  GWEN_Buffer_free(tbuf);
797  return rv;
798  }
799  else if (rv>0) {
800  GWEN_Buffer_IncrementPos(tbuf, rv);
802  if (p[rv-1]==10) {
803  uint32_t npos;
804 
805  lines++;
806  npos=GWEN_Buffer_GetPos(tbuf);
807  if ((npos-pos)==1) {
808  /* empty line, header finished */
809  break;
810  }
811  pos=npos;
812  }
813  }
814  else if (rv==0)
815  break;
816  }
817  while (rv>0);
818 
819  if (lines<1) {
820  DBG_ERROR(GWEN_LOGDOMAIN, "No header line received");
821  GWEN_Buffer_free(tbuf);
822  return GWEN_ERROR_EOF;
823  }
824 
826  DBG_DEBUG(GWEN_LOGDOMAIN, "Received HTTP header:");
827  GWEN_Text_LogString((const char *) GWEN_Buffer_GetStart(tbuf),
831  }
832 
834  if (rv<0) {
835  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
836  GWEN_Buffer_free(tbuf);
837  return rv;
838  }
839 
840  GWEN_Buffer_free(tbuf);
841  return 0;
842 }
843 
844 
845 
847 {
848  GWEN_SYNCIO_HTTP *xio;
849  GWEN_SYNCIO *baseIo;
850  GWEN_BUFFER *tbuf;
851  int rv;
852  int csize;
853 
854  assert(sio);
855  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
856  assert(xio);
857 
858  DBG_INFO(GWEN_LOGDOMAIN, "Reading chunksize");
859  baseIo=GWEN_SyncIo_GetBaseIo(sio);
860  assert(baseIo);
861 
862  /* read a single line */
863  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
864  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
865  if (rv<0) {
866  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
867  GWEN_Buffer_free(tbuf);
868  return rv;
869  }
870 
871  if (*GWEN_Buffer_GetStart(tbuf)==0) {
872  GWEN_Buffer_Reset(tbuf);
873  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
874  if (rv<0) {
875  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
876  GWEN_Buffer_free(tbuf);
877  return rv;
878  }
879  }
880 
881  if (1!=sscanf(GWEN_Buffer_GetStart(tbuf), "%x", &csize)) {
882  DBG_ERROR(GWEN_LOGDOMAIN, "Bad data received (invalid chunksize specifier: [%s])",
883  GWEN_Buffer_GetStart(tbuf));
884  GWEN_Buffer_free(tbuf);
885  return GWEN_ERROR_BAD_DATA;
886  }
887 
888  xio->currentReadChunkSize=csize;
889 
890  GWEN_Buffer_free(tbuf);
891  return 0;
892 }
893 
894 
895 
896 int GWEN_SyncIo_Http_ReadChunk(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
897 {
898  GWEN_SYNCIO_HTTP *xio;
899  GWEN_SYNCIO *baseIo;
900  int rv;
901 
902  assert(sio);
903  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
904  assert(xio);
905 
906  DBG_DEBUG(GWEN_LOGDOMAIN, "Reading chunk (%d bytes)", (int) size);
907  baseIo=GWEN_SyncIo_GetBaseIo(sio);
908  assert(baseIo);
909 
910  /* we want to read binary data transparently */
912 
913  if ((int)size>xio->currentReadChunkSize)
914  size=xio->currentReadChunkSize;
915 
916  rv=GWEN_SyncIo_Read(baseIo, buffer, size);
917  if (rv<0) {
918  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
919  return rv;
920  }
921 
922  xio->currentReadChunkSize-=rv;
923  if (xio->currentReadBodySize>0)
924  xio->currentReadBodySize-=rv;
925 
926  if (xio->currentReadChunkSize==0) {
927  int rv2;
928  GWEN_BUFFER *tbuf;
929 
930  /* chunk finished, read trailing CR/LF */
931  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
932  rv2=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
933  if (rv2<0) {
934  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
935  GWEN_Buffer_free(tbuf);
936  return rv2;
937  }
938  GWEN_Buffer_free(tbuf);
939 
940  DBG_DEBUG(GWEN_LOGDOMAIN, "Chunk finished.");
941 
942  /* change read mode */
943  xio->readMode=GWEN_SyncIo_Http_Mode_ChunkSize;
944  }
945 
946  return rv;
947 }
948 
949 
950 
951 int GWEN_SyncIo_Http_ReadBody(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
952 {
953  GWEN_SYNCIO_HTTP *xio;
954  GWEN_SYNCIO *baseIo;
955  int rv;
956 
957  assert(size);
958 
959  assert(sio);
960  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
961  assert(xio);
962 
963  DBG_INFO(GWEN_LOGDOMAIN, "Reading body");
964  baseIo=GWEN_SyncIo_GetBaseIo(sio);
965  assert(baseIo);
966 
967  /* we want to read binary data transparently */
969 
970  if ((xio->currentReadBodySize>=0) &&
971  ((int)size>xio->currentReadBodySize)) {
972  DBG_INFO(GWEN_LOGDOMAIN, "Adjusting read body size from %d to %d",
973  size, xio->currentReadBodySize);
974  size=xio->currentReadBodySize;
975  }
976 
977  rv=GWEN_SyncIo_Read(baseIo, buffer, size);
978  if (rv<0) {
979  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
980  return rv;
981  }
982 
983  if (xio->currentReadBodySize>=0)
984  xio->currentReadBodySize-=rv;
985 
986  if (xio->currentReadBodySize==0)
987  /* body finished, change read mode */
989 
990  return rv;
991 }
992 
993 
994 
996 {
997  GWEN_SYNCIO_HTTP *xio;
998  GWEN_SYNCIO *baseIo;
999  int rv;
1000  const char *s;
1001  GWEN_BUFFER *tbuf;
1002 
1003  assert(sio);
1004  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1005  assert(xio);
1006 
1007  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1008  assert(baseIo);
1009 
1010  /* we will construct the line including CR/LF ourselves */
1012 
1013  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
1014 
1015  s=GWEN_DB_GetCharValue(xio->dbCommandOut, "command", 0, "GET");
1016  GWEN_Buffer_AppendString(tbuf, s);
1017  GWEN_Buffer_AppendString(tbuf, " ");
1018 
1019  s=GWEN_DB_GetCharValue(xio->dbCommandOut, "url", 0, "/");
1020  GWEN_Buffer_AppendString(tbuf, s);
1021  GWEN_Buffer_AppendString(tbuf, " ");
1022 
1023  s=GWEN_DB_GetCharValue(xio->dbCommandOut, "protocol", 0, "HTTP/1.0");
1024  GWEN_Buffer_AppendString(tbuf, s);
1025  GWEN_Buffer_AppendString(tbuf, "\r\n");
1026 
1028  DBG_DEBUG(GWEN_LOGDOMAIN, "Sending HTTP command:");
1029  GWEN_Text_LogString((const char *) GWEN_Buffer_GetStart(tbuf),
1033  }
1034 
1035  /* write */
1036  rv=GWEN_SyncIo_WriteForced(baseIo,
1037  (const uint8_t *) GWEN_Buffer_GetStart(tbuf),
1038  GWEN_Buffer_GetUsedBytes(tbuf));
1039  if (rv<0) {
1040  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1041  GWEN_Buffer_free(tbuf);
1042  return rv;
1043  }
1044 
1045  GWEN_Buffer_free(tbuf);
1046  return 0;
1047 }
1048 
1049 
1050 
1052 {
1053  GWEN_SYNCIO_HTTP *xio;
1054  GWEN_SYNCIO *baseIo;
1055  int rv;
1056  const char *s;
1057  GWEN_BUFFER *tbuf;
1058  char numbuf[32];
1059  int i;
1060 
1061  assert(sio);
1062  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1063  assert(xio);
1064 
1065  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1066  assert(baseIo);
1067 
1068  /* we will construct the line including CR/LF ourselves */
1070 
1071  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
1072 
1073  s=GWEN_DB_GetCharValue(xio->dbStatusOut, "protocol", 0, "HTTP/1.0");
1074  GWEN_Buffer_AppendString(tbuf, s);
1075  GWEN_Buffer_AppendString(tbuf, " ");
1076 
1077  i=GWEN_DB_GetIntValue(xio->dbStatusOut, "code", 0, -1);
1078  if (i==-1) {
1079  DBG_INFO(GWEN_LOGDOMAIN, "Missing status code");
1080  GWEN_Buffer_free(tbuf);
1081  return GWEN_ERROR_NO_DATA;
1082  }
1083  snprintf(numbuf, sizeof(numbuf), "%d ", i);
1084  GWEN_Buffer_AppendString(tbuf, numbuf);
1085 
1086  s=GWEN_DB_GetCharValue(xio->dbStatusOut, "text", 0, "No text.");
1087  GWEN_Buffer_AppendString(tbuf, s);
1088  GWEN_Buffer_AppendString(tbuf, "\r\n");
1089 
1090  /* write */
1091  rv=GWEN_SyncIo_WriteForced(baseIo,
1092  (const uint8_t *) GWEN_Buffer_GetStart(tbuf),
1093  GWEN_Buffer_GetUsedBytes(tbuf));
1094  if (rv<0) {
1095  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1096  GWEN_Buffer_free(tbuf);
1097  return rv;
1098  }
1099 
1100  GWEN_Buffer_free(tbuf);
1101  return 0;
1102 }
1103 
1104 
1105 
1107 {
1108  GWEN_SYNCIO_HTTP *xio;
1109  GWEN_SYNCIO *baseIo;
1110  int i;
1111  GWEN_DB_NODE *dbVar;
1112  GWEN_BUFFER *tbuf;
1113  int rv;
1114 
1115  assert(sio);
1116  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1117  assert(xio);
1118 
1119  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1120  assert(baseIo);
1121 
1122  /* we will construct the line including CR/LF ourselves */
1124 
1125  /* default next mode after writing the header is writing the body
1126  * (if any, but that will be checked later) */
1127  xio->writeMode=GWEN_SyncIo_Http_Mode_Body;
1128 
1129  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
1130 
1131  i=GWEN_DB_GetIntValue(xio->dbHeaderOut, "Content-Length", 0, -1);
1132  xio->currentWriteBodySize=i;
1133 
1134  dbVar=GWEN_DB_GetFirstVar(xio->dbHeaderOut);
1135  while (dbVar) {
1136  GWEN_DB_NODE *dbVal;
1137 
1138  /* only handle first value */
1139  dbVal=GWEN_DB_GetFirstValue(dbVar);
1140  if (dbVal) {
1141  GWEN_DB_NODE_TYPE vtype;
1142 
1143  vtype=GWEN_DB_GetValueType(dbVal);
1144  if (vtype==GWEN_DB_NodeType_ValueChar) {
1145  const char *s;
1146 
1148  GWEN_Buffer_AppendString(tbuf, ":");
1150  if (s)
1151  GWEN_Buffer_AppendString(tbuf, s);
1152  GWEN_Buffer_AppendString(tbuf, "\r\n");
1153 
1154  if (strcasecmp(GWEN_DB_VariableName(dbVar), "Transfer-Encoding")==0) {
1155  if (s && (-1!=GWEN_Text_ComparePattern(s, "*chunked*", 0))) {
1156  /* chunked encoding, this means next we have to write the chunksize */
1157  xio->writeMode=GWEN_SyncIo_Http_Mode_ChunkSize;
1158  }
1159  }
1160  }
1161  else if (vtype==GWEN_DB_NodeType_ValueInt) {
1162  i=GWEN_DB_GetIntValueFromNode(dbVal);
1163  if (i!=-1 || strcasecmp(GWEN_DB_VariableName(dbVar), "Content-Length")==0) {
1164  char numbuf[32];
1165 
1166  /* don't write body size of -1 */
1168  GWEN_Buffer_AppendString(tbuf, ":");
1169  snprintf(numbuf, sizeof(numbuf), "%d", i);
1170  GWEN_Buffer_AppendString(tbuf, numbuf);
1171  GWEN_Buffer_AppendString(tbuf, "\r\n");
1172  }
1173  }
1174  else {
1175  DBG_INFO(GWEN_LOGDOMAIN, "Variable type %d of var [%s] not supported",
1176  vtype, GWEN_DB_VariableName(dbVar));
1177  return GWEN_ERROR_BAD_DATA;
1178  }
1179  }
1180  dbVar=GWEN_DB_GetNextVar(dbVar);
1181  }
1182 
1183  /* finalize header */
1184  GWEN_Buffer_AppendString(tbuf, "\r\n");
1185 
1187  DBG_DEBUG(GWEN_LOGDOMAIN, "Sending HTTP header:");
1188  GWEN_Text_LogString((const char *) GWEN_Buffer_GetStart(tbuf),
1192  }
1193 
1194  /* write */
1195  rv=GWEN_SyncIo_WriteForced(baseIo,
1196  (const uint8_t *) GWEN_Buffer_GetStart(tbuf),
1197  GWEN_Buffer_GetUsedBytes(tbuf));
1198  if (rv<0) {
1199  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1200  GWEN_Buffer_free(tbuf);
1201  return rv;
1202  }
1203  GWEN_Buffer_free(tbuf);
1204 
1205  if (xio->currentWriteBodySize==0)
1207 
1208  return 0;
1209 }
1210 
1211 
1212 
1214 {
1215  GWEN_SYNCIO_HTTP *xio;
1216  GWEN_SYNCIO *baseIo;
1217  int rv;
1218  char numbuf[32];
1219 
1220  assert(sio);
1221  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1222  assert(xio);
1223 
1224  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1225  assert(baseIo);
1226 
1227  /* we will construct the line including CR/LF ourselves */
1229 
1230  snprintf(numbuf, sizeof(numbuf)-1, "%x\r\n", size);
1231  numbuf[sizeof(numbuf)-1]=0;
1232 
1233  rv=GWEN_SyncIo_WriteForced(baseIo, (const uint8_t *) numbuf, strlen(numbuf));
1234  if (rv<0) {
1235  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1236  return rv;
1237  }
1238 
1239  return 0;
1240 }
1241 
1242 
1243 
1245 {
1246  GWEN_SYNCIO_HTTP *xio;
1247 
1248  assert(sio);
1249  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1250  assert(xio);
1251 
1252  xio->writeMode=GWEN_SyncIo_Http_Mode_Idle;
1253  GWEN_DB_ClearGroup(xio->dbStatusOut, NULL);
1254 }
1255 
1256 
1257 
1258 
1260 {
1261  GWEN_SYNCIO_HTTP *xio;
1262 
1263  assert(sio);
1264  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1265  assert(xio);
1266 
1267  return xio->dbCommandIn;
1268 }
1269 
1270 
1271 
1273 {
1274  GWEN_SYNCIO_HTTP *xio;
1275 
1276  assert(sio);
1277  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1278  assert(xio);
1279 
1280  return xio->dbStatusIn;
1281 }
1282 
1283 
1284 
1286 {
1287  GWEN_SYNCIO_HTTP *xio;
1288 
1289  assert(sio);
1290  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1291  assert(xio);
1292 
1293  return xio->dbHeaderIn;
1294 }
1295 
1296 
1297 
1299 {
1300  GWEN_SYNCIO_HTTP *xio;
1301 
1302  assert(sio);
1303  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1304  assert(xio);
1305 
1306  return xio->dbCommandOut;
1307 }
1308 
1309 
1310 
1312 {
1313  GWEN_SYNCIO_HTTP *xio;
1314 
1315  assert(sio);
1316  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1317  assert(xio);
1318 
1319  return xio->dbStatusOut;
1320 }
1321 
1322 
1323 
1325 {
1326  GWEN_SYNCIO_HTTP *xio;
1327 
1328  assert(sio);
1329  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1330  assert(xio);
1331 
1332  return xio->dbHeaderOut;
1333 }
1334 
1335 
1336 
1337 
1339 {
1340  GWEN_SYNCIO_HTTP *xio;
1341  int rv=0;
1342  int code=0;
1343  int firstRead=1;
1344  int bodySize=-1;
1345  int bytesRead=0;
1346  uint32_t pid;
1347 
1348  assert(sio);
1349  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1350  assert(xio);
1351 
1356  I18N("Network Operation"),
1357  I18N("Receiving data"),
1358  0,
1359  0);
1360 
1361 
1362  /* recv packet (this reads the HTTP body) */
1363  for (;;) {
1364  uint8_t *p;
1365  uint32_t l;
1366 
1367  rv=GWEN_Buffer_AllocRoom(buf, 1024);
1368  if (rv<0) {
1369  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1370  GWEN_Gui_ProgressEnd(pid);
1371  return rv;
1372  }
1373 
1374  p=(uint8_t *) GWEN_Buffer_GetPosPointer(buf);
1376  do {
1377  rv=GWEN_SyncIo_Read(sio, p, l-1);
1378  }
1379  while (rv==GWEN_ERROR_INTERRUPTED);
1380 
1381  if (rv==0) /* EOF met */
1382  break;
1383  else if (rv<0) {
1384  if (rv==GWEN_ERROR_EOF) {
1385  if (bodySize!=-1 && bytesRead<bodySize) {
1387  "EOF met prematurely (%d < %d)",
1388  bytesRead, bodySize);
1389  GWEN_Gui_ProgressEnd(pid);
1390  return GWEN_ERROR_EOF;
1391  }
1392  }
1393  else {
1394  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1395  /*return rv;*/
1396  break;
1397  }
1398  }
1399  else {
1400  GWEN_Buffer_IncrementPos(buf, rv);
1402  if (firstRead) {
1403  GWEN_DB_NODE *db;
1404 
1406  bodySize=GWEN_DB_GetIntValue(db, "Content-length", 0, -1);
1407 
1408  if (bodySize!=-1)
1409  GWEN_Gui_ProgressSetTotal(pid, bodySize);
1410  }
1411  bytesRead+=rv;
1412 
1413  /* advance progress bar */
1414  rv=GWEN_Gui_ProgressAdvance(pid, bytesRead);
1415  if (rv==GWEN_ERROR_USER_ABORTED) {
1416  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1417  GWEN_Gui_ProgressEnd(pid);
1418  return rv;
1419  }
1420  }
1421 
1422  if (bodySize!=-1 && bytesRead>=bodySize) {
1423  break;
1424  }
1425 
1426  firstRead=0;
1427  }
1428  GWEN_Gui_ProgressEnd(pid);
1429 
1430  if (rv<0) {
1431  if (GWEN_Buffer_GetUsedBytes(buf)) {
1432  /* data received, check for common error codes */
1433  if (rv==GWEN_ERROR_EOF || rv==GWEN_ERROR_IO || rv==GWEN_ERROR_SSL) {
1435  "We received an error, but we still got data, "
1436  "so we ignore the error here");
1437  }
1438  else {
1439  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1442  I18N("No message received"));
1443  return rv;
1444  }
1445  }
1446  else {
1447  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1450  I18N("No message received"));
1451  return rv;
1452  }
1453  }
1454 
1456  code=0;
1457  else {
1458  code=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, 0);
1459  if (code) {
1460  const char *s;
1461 
1462  s=GWEN_DB_GetCharValue(xio->dbStatusIn, "text", 0, NULL);
1463  DBG_DEBUG(GWEN_LOGDOMAIN, "HTTP-Status: %d (%s)",
1464  code, s?s:"- no text -");
1466  I18N("HTTP-Status: %d (%s)"),
1467  code, s?s:I18N("- no details -"));
1468  }
1469  else {
1470  DBG_ERROR(GWEN_LOGDOMAIN, "No HTTP status code received");
1473  I18N("No HTTP status code received"));
1474  code=GWEN_ERROR_BAD_DATA;
1475  }
1476  }
1477 
1478  return code;
1479 }
1480 
1481 
1482 
1484 {
1485  GWEN_SYNCIO_HTTP *xio;
1486  int rv;
1487  int code=0;
1488  int firstRead=1;
1489  int bodySize=-1;
1490  int bytesRead=0;
1491  uint32_t pid;
1492 
1493  assert(sio);
1494  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1495  assert(xio);
1496 
1501  I18N("Network Operation"),
1502  I18N("Receiving data"),
1503  0,
1504  0);
1505 
1506  /* recv packet (this reads the HTTP body) */
1507  for (;;) {
1508  uint8_t *p;
1509  uint32_t l;
1510  uint8_t rbuf[1024];
1511 
1512  p=rbuf;
1513  l=sizeof(rbuf);
1514 
1515  do {
1516  rv=GWEN_SyncIo_Read(sio, p, l-1);
1517  }
1518  while (rv==GWEN_ERROR_INTERRUPTED);
1519 
1520  if (rv==0)
1521  break;
1522  else if (rv<0) {
1523  if (rv==GWEN_ERROR_EOF) {
1524  if (bodySize!=-1 && bytesRead<bodySize) {
1526  "EOF met prematurely (%d < %d)",
1527  bytesRead, bodySize);
1528  GWEN_Gui_ProgressEnd(pid);
1529  return GWEN_ERROR_EOF;
1530  }
1531  }
1532  else {
1533  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1534  /*return rv;*/
1535  break;
1536  }
1537  }
1538  else {
1539  int rv2;
1540 
1541  rv2=GWEN_SyncIo_WriteForced(sout, rbuf, rv);
1542  if (rv2<0) {
1543  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
1544  GWEN_Gui_ProgressEnd(pid);
1545  return rv2;
1546  }
1547  if (firstRead) {
1548  GWEN_DB_NODE *db;
1549 
1551  bodySize=GWEN_DB_GetIntValue(db, "Content-length", 0, -1);
1552 
1553  if (bodySize!=-1)
1554  GWEN_Gui_ProgressSetTotal(pid, bodySize);
1555  }
1556  bytesRead+=rv;
1557 
1558  /* advance progress bar */
1559  rv=GWEN_Gui_ProgressAdvance(pid, bytesRead);
1560  if (rv==GWEN_ERROR_USER_ABORTED) {
1561  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1562  GWEN_Gui_ProgressEnd(pid);
1563  return rv;
1564  }
1565  }
1566 
1567  if (bodySize!=-1 && bytesRead>=bodySize) {
1568  break;
1569  }
1570  firstRead=0;
1571  }
1572  GWEN_Gui_ProgressEnd(pid);
1573 
1574 
1575  if (rv<0) {
1576  if (bytesRead) {
1577  /* data received, check for common error codes */
1578  if (rv==GWEN_ERROR_EOF || rv==GWEN_ERROR_IO || rv==GWEN_ERROR_SSL) {
1580  "We received an error, but we still got data, "
1581  "so we ignore the error here");
1582  }
1583  else {
1584  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1587  I18N("No message received"));
1588  return rv;
1589  }
1590  }
1591  else {
1592  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1595  I18N("No message received"));
1596  return rv;
1597  }
1598  }
1599 
1601  code=0;
1602  else {
1603  code=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, 0);
1604  if (code) {
1605  const char *s;
1606 
1607  s=GWEN_DB_GetCharValue(xio->dbStatusIn, "text", 0, NULL);
1608  DBG_DEBUG(GWEN_LOGDOMAIN, "HTTP-Status: %d (%s)",
1609  code, s?s:"- no text -");
1611  I18N("HTTP-Status: %d (%s)"),
1612  code, s?s:I18N("- no details -)"));
1613  }
1614  else {
1615  DBG_ERROR(GWEN_LOGDOMAIN, "No HTTP status code received");
1618  I18N("No HTTP status code received"));
1619  code=GWEN_ERROR_BAD_DATA;
1620  }
1621  }
1622 
1623  return code;
1624 }
1625 
1626 
1627 
1628 
int GWEN_SyncIo_WriteForced(GWEN_SYNCIO *sio, const uint8_t *buffer, uint32_t size)
Definition: syncio.c:317
GWENHYWFAR_API int GWEN_Gui_ProgressLog(uint32_t id, GWEN_LOGGER_LEVEL level, const char *text)
Definition: gui_virtual.c:444
char * GWEN_Buffer_GetStart(const GWEN_BUFFER *bf)
Definition: buffer.c:235
int GWENHYWFAR_CB GWEN_SyncIo_Http_Connect(GWEN_SYNCIO *sio)
Definition: syncio_http.c:99
#define I18N(m)
Definition: error.c:42
#define GWEN_DB_FLAGS_OVERWRITE_VARS
Definition: db.h:121
int GWEN_SyncIo_Connect(GWEN_SYNCIO *sio)
Definition: syncio.c:97
GWENHYWFAR_API int GWEN_Gui_ProgressAdvance(uint32_t id, uint32_t progress)
Definition: gui_virtual.c:420
void GWEN_SyncIo_SubFlags(GWEN_SYNCIO *sio, uint32_t fl)
Definition: syncio.c:188
struct GWEN_DB_NODE GWEN_DB_NODE
Definition: db.h:228
int GWEN_Buffer_AllocRoom(GWEN_BUFFER *bf, uint32_t size)
Definition: buffer.c:285
uint32_t GWEN_Buffer_GetMaxUnsegmentedWrite(GWEN_BUFFER *bf)
Definition: buffer.c:528
int GWEN_SyncIo_Http_ParseHeader(GWEN_SYNCIO *sio, char *buf)
Definition: syncio_http.c:666
int GWEN_SyncIo_Http_RecvBodyToSio(GWEN_SYNCIO *sio, GWEN_SYNCIO *sout)
Definition: syncio_http.c:1483
void GWEN_DB_Group_free(GWEN_DB_NODE *n)
Definition: db.c:421
#define GWEN_ERROR_INVALID
Definition: error.h:67
int GWENHYWFAR_CB GWEN_SyncIo_Http_Disconnect(GWEN_SYNCIO *sio)
Definition: syncio_http.c:131
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbHeaderOut(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1324
void GWEN_SyncIo_Http_SetWriteIdle(GWEN_SYNCIO *sio)
Definition: syncio_http.c:1244
uint32_t GWEN_Buffer_GetUsedBytes(const GWEN_BUFFER *bf)
Definition: buffer.c:277
#define GWEN_GUI_PROGRESS_ALLOW_EMBED
Definition: gui.h:196
int GWEN_SyncIo_Read(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition: syncio.c:133
int GWEN_SyncIo_Http_RecvBody(GWEN_SYNCIO *sio, GWEN_BUFFER *buf)
Definition: syncio_http.c:1338
int GWEN_SyncIo_Http_ReadStatus(GWEN_SYNCIO *sio)
Definition: syncio_http.c:578
GWENHYWFAR_API int GWEN_Gui_ProgressSetTotal(uint32_t id, uint64_t total)
Definition: gui_virtual.c:432
GWEN_SYNCIO_WRITE_FN GWEN_SyncIo_SetWriteFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_WRITE_FN fn)
Definition: syncio.c:304
#define GWEN_FREE_OBJECT(varname)
Definition: memory.h:61
#define NULL
Definition: binreloc.c:300
GWEN_SYNCIO_CONNECT_FN GWEN_SyncIo_SetConnectFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_CONNECT_FN fn)
Definition: syncio.c:252
#define GWEN_SYNCIO_FLAGS_TRANSPARENT
Definition: syncio.h:55
int GWEN_SyncIo_Http_ParseCommand(GWEN_SYNCIO *sio, const char *buffer)
Definition: syncio_http.c:520
uint32_t GWEN_SyncIo_GetFlags(const GWEN_SYNCIO *sio)
Definition: syncio.c:161
#define GWEN_GUI_PROGRESS_DELAY
Definition: gui.h:192
int GWEN_Buffer_AdjustUsedBytes(GWEN_BUFFER *bf)
Definition: buffer.c:469
int GWEN_SyncIo_Http_ReadChunk(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition: syncio_http.c:896
#define GWEN_LOGDOMAIN
Definition: logger.h:35
void GWEN_SyncIo_SetStatus(GWEN_SYNCIO *sio, GWEN_SYNCIO_STATUS st)
Definition: syncio.c:206
uint32_t GWEN_Buffer_GetPos(const GWEN_BUFFER *bf)
Definition: buffer.c:253
void GWENHYWFAR_CB GWEN_SyncIo_Http_FreeData(GWEN_UNUSED void *bp, void *p)
Definition: syncio_http.c:80
GWEN_BUFFER * GWEN_Buffer_new(char *buffer, uint32_t size, uint32_t used, int take)
Definition: buffer.c:42
GWEN_SYNCIO * GWEN_SyncIo_GetBaseIo(const GWEN_SYNCIO *sio)
Definition: syncio.c:224
char * GWEN_Buffer_GetPosPointer(const GWEN_BUFFER *bf)
Definition: buffer.c:549
#define GWEN_ERROR_IO
Definition: error.h:123
void GWEN_Buffer_Reset(GWEN_BUFFER *bf)
Definition: buffer.c:650
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbStatusOut(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1311
int GWEN_Buffer_IncrementPos(GWEN_BUFFER *bf, uint32_t i)
Definition: buffer.c:452
#define GWEN_ERROR_INTERRUPTED
Definition: error.h:74
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbHeaderIn(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1285
int GWEN_SyncIo_Http_ReadBody(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition: syncio_http.c:951
int GWEN_SyncIo_Http_ParseStatus(GWEN_SYNCIO *sio, char *buffer)
Definition: syncio_http.c:472
#define GWEN_ERROR_NOT_CONNECTED
Definition: error.h:120
GWEN_SYNCIO * GWEN_SyncIo_Http_new(GWEN_SYNCIO *baseIo)
Definition: syncio_http.c:52
#define GWEN_ERROR_SSL
Definition: error.h:105
#define GWEN_ERROR_BAD_DATA
Definition: error.h:121
GWEN_DB_NODE * GWEN_DB_GetFirstVar(GWEN_DB_NODE *n)
Definition: db.c:479
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbStatusIn(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1272
#define GWEN_NEW_OBJECT(typ, varname)
Definition: memory.h:55
struct GWEN_SYNCIO GWEN_SYNCIO
Definition: syncio.h:40
#define GWENHYWFAR_CB
Definition: gwenhywfarapi.h:89
#define DBG_DEBUG(dbg_logger, format, args...)
Definition: debug.h:214
int GWEN_SyncIo_Http_ReadLine(GWEN_SYNCIO *sio, GWEN_BUFFER *tbuf)
Definition: syncio_http.c:420
GWENHYWFAR_API int GWEN_Gui_ProgressLog2(uint32_t id, GWEN_LOGGER_LEVEL level, const char *text,...)
Definition: gui_virtual.c:458
#define GWEN_ERROR_GENERIC
Definition: error.h:62
void GWEN_Text_LogString(const char *s, unsigned int l, const char *logDomain, GWEN_LOGGER_LEVEL lv)
Definition: text.c:1606
#define GWEN_SYNCIO_FLAGS_PASSIVE
Definition: syncio.h:57
const char * GWEN_DB_GetCharValue(GWEN_DB_NODE *n, const char *path, int idx, const char *defVal)
Definition: db.c:971
GWEN_SYNCIO_STATUS GWEN_SyncIo_GetStatus(const GWEN_SYNCIO *sio)
Definition: syncio.c:197
const char * GWEN_DB_VariableName(GWEN_DB_NODE *n)
Definition: db.c:1928
void GWEN_Buffer_free(GWEN_BUFFER *bf)
Definition: buffer.c:89
struct GWEN_BUFFER GWEN_BUFFER
A dynamically resizeable text buffer.
Definition: buffer.h:38
int GWENHYWFAR_CB GWEN_SyncIo_Http_Write(GWEN_SYNCIO *sio, const uint8_t *buffer, uint32_t size)
Definition: syncio_http.c:312
void GWEN_SyncIo_AddFlags(GWEN_SYNCIO *sio, uint32_t fl)
Definition: syncio.c:179
GWENHYWFAR_API uint32_t GWEN_Gui_ProgressStart(uint32_t progressFlags, const char *title, const char *text, uint64_t total, uint32_t guiid)
Definition: gui_virtual.c:404
GWENHYWFAR_API int GWEN_Gui_ProgressEnd(uint32_t id)
Definition: gui_virtual.c:480
#define GWEN_PATH_FLAGS_CREATE_VAR
Definition: path.h:103
int GWEN_SyncIo_Http_ReadHeader(GWEN_SYNCIO *sio)
Definition: syncio_http.c:765
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbCommandOut(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1298
#define DBG_ERROR(dbg_logger, format, args...)
Definition: debug.h:97
#define GWEN_ERROR_EOF
Definition: error.h:96
int GWEN_SyncIo_Http_WriteHeader(GWEN_SYNCIO *sio)
Definition: syncio_http.c:1106
int GWEN_SyncIo_Disconnect(GWEN_SYNCIO *sio)
Definition: syncio.c:109
#define GWEN_GUI_PROGRESS_SHOW_PROGRESS
Definition: gui.h:197
int GWEN_Text_ComparePattern(const char *w, const char *p, int sensecase)
Definition: text.c:1208
int GWEN_DB_SetCharValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, const char *val)
Definition: db.c:997
GWEN_SYNCIO * GWEN_SyncIo_new(const char *typeName, GWEN_SYNCIO *baseIo)
Definition: syncio.c:51
GWEN_DB_NODE * GWEN_DB_GetFirstValue(GWEN_DB_NODE *n)
Definition: db.c:518
GWEN_SYNCIO_DISCONNECT_FN GWEN_SyncIo_SetDisconnectFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_DISCONNECT_FN fn)
Definition: syncio.c:265
#define DBG_INFO(dbg_logger, format, args...)
Definition: debug.h:181
GWEN_DB_NODE * GWEN_DB_GetNextVar(GWEN_DB_NODE *n)
Definition: db.c:500
#define GWEN_SYNCIO_HTTP_TYPE
Definition: syncio_http.h:33
GWEN_DB_NODE_TYPE
Definition: db.h:233
void GWEN_SyncIo_Http_SetReadIdle(GWEN_SYNCIO *sio)
Definition: syncio_http.c:161
int GWEN_DB_GetIntValue(GWEN_DB_NODE *n, const char *path, int idx, int defVal)
Definition: db.c:1163
GWEN_DB_NODE * GWEN_DB_Group_new(const char *name)
Definition: db.c:173
int GWEN_Logger_GetLevel(const char *logDomain)
Definition: logger.c:638
#define GWEN_INHERIT(bt, t)
Definition: inherit.h:264
GWEN_SYNCIO_READ_FN GWEN_SyncIo_SetReadFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_READ_FN fn)
Definition: syncio.c:291
int GWENHYWFAR_CB GWEN_SyncIo_Http_Read(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition: syncio_http.c:174
int GWEN_DB_SetIntValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, int val)
Definition: db.c:1202
#define GWEN_ERROR_USER_ABORTED
Definition: error.h:65
#define GWEN_ERROR_NO_DATA
Definition: error.h:94
int GWEN_DB_GetIntValueFromNode(const GWEN_DB_NODE *n)
Definition: db.c:607
int GWEN_SyncIo_Http_WriteStatus(GWEN_SYNCIO *sio)
Definition: syncio_http.c:1051
int GWEN_SyncIo_Http_ReadCommand(GWEN_SYNCIO *sio)
Definition: syncio_http.c:629
int GWEN_DB_ClearGroup(GWEN_DB_NODE *n, const char *path)
Definition: db.c:944
#define GWEN_INHERIT_SETDATA(bt, t, element, data, fn)
Definition: inherit.h:292
int GWEN_SyncIo_Http_ReadChunkSize(GWEN_SYNCIO *sio)
Definition: syncio_http.c:846
int GWEN_SyncIo_Http_WriteCommand(GWEN_SYNCIO *sio)
Definition: syncio_http.c:995
#define GWEN_UNUSED
int GWEN_Buffer_AppendString(GWEN_BUFFER *bf, const char *buffer)
Definition: buffer.c:989
GWEN_DB_NODE_TYPE GWEN_DB_GetValueType(GWEN_DB_NODE *n)
Definition: db.c:563
#define GWEN_INHERIT_GETDATA(bt, t, element)
Definition: inherit.h:271
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbCommandIn(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1259
const char * GWEN_DB_GetCharValueFromNode(const GWEN_DB_NODE *n)
Definition: db.c:578
#define GWEN_GUI_PROGRESS_SHOW_ABORT
Definition: gui.h:194
int GWEN_SyncIo_Http_WriteChunkSize(GWEN_SYNCIO *sio, uint32_t size)
Definition: syncio_http.c:1213