gwenhywfar  4.99.8beta
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  }
452  while(rv>0);
453 
454  if (GWEN_Buffer_GetUsedBytes(tbuf)<1) {
455  DBG_ERROR(GWEN_LOGDOMAIN, "Nothing received");
456  return GWEN_ERROR_EOF;
457  }
458 
459  return 0;
460 }
461 
462 
463 
464 int GWEN_SyncIo_Http_ParseStatus(GWEN_SYNCIO *sio, char *buffer) {
465  GWEN_SYNCIO_HTTP *xio;
466  char *p;
467  char *s;
468  int code;
469 
470  assert(sio);
471  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
472  assert(xio);
473 
474  s=buffer;
475 
476  /* read protocol */
477  p=strchr(s, ' ');
478  if (!p) {
480  "Bad format of HTTP status (%s)", buffer);
481  return GWEN_ERROR_INVALID;
482  }
483  *p=0;
484  p++;
485 
486  GWEN_DB_SetCharValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", s);
487  s=p;
488 
489  /* read status code */
490  while(*p && isdigit((int)*p))
491  p++;
492  if (*p) {
493  *p=0;
494  p++;
495  }
496  if (1!=sscanf(s, "%d", &code)) {
497  DBG_ERROR(GWEN_LOGDOMAIN, "Bad request (status code \"%s\")", s);
498  return GWEN_ERROR_INVALID;
499  }
500  GWEN_DB_SetIntValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "code", code);
501  s=p;
502 
503  /* read text */
504  GWEN_DB_SetCharValue(xio->dbStatusIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "text", s);
505 
506  return 0;
507 }
508 
509 
510 
511 int GWEN_SyncIo_Http_ParseCommand(GWEN_SYNCIO *sio, const char *buffer) {
512  GWEN_SYNCIO_HTTP *xio;
513  char *tmp;
514  char *p;
515  char *s;
516 
517  assert(sio);
518  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
519  assert(xio);
520 
521  tmp=strdup(buffer);
522  s=tmp;
523 
524  /* read command */
525  p=strchr(s, ' ');
526  if (!p) {
528  "Bad format of HTTP request (%s)", buffer);
529  free(tmp);
530  return GWEN_ERROR_INVALID;
531  }
532  *p=0;
533  p++;
534 
535  GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "command", s);
536  s=p;
537 
538  /* read URL */
539  p=strchr(s, ' ');
540  if (!p) {
542  "Bad format of HTTP request (%s)", buffer);
543  free(tmp);
544  return GWEN_ERROR_INVALID;
545  }
546  *p=0;
547  p++;
548 
549  GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "url", s);
550  s=p;
551 
552  if (*s==0) {
553  /* no protocol information follows, so we assume HTTP/0.9 */
554  DBG_ERROR(GWEN_LOGDOMAIN, "Bad request (not in HTTP>=1.0)");
555  free(tmp);
556  return GWEN_ERROR_INVALID;
557  }
558  else {
559  GWEN_DB_SetCharValue(xio->dbCommandIn, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", s);
560  }
561 
562  free(tmp);
563  return 0;
564 }
565 
566 
567 
569  GWEN_SYNCIO_HTTP *xio;
570  GWEN_SYNCIO *baseIo;
571  GWEN_BUFFER *tbuf;
572  int rv;
573 
574  assert(sio);
575  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
576  assert(xio);
577 
578  DBG_INFO(GWEN_LOGDOMAIN, "Reading status");
579  baseIo=GWEN_SyncIo_GetBaseIo(sio);
580  assert(baseIo);
581 
582  /* read a single line */
583  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
584  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
585  if (rv<0) {
586  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
587  GWEN_Buffer_free(tbuf);
588  return rv;
589  }
590 
591  if (*GWEN_Buffer_GetStart(tbuf)==0) {
592  DBG_INFO(GWEN_LOGDOMAIN, "Empty line received while reading status response, assuming EOF");
593  GWEN_Buffer_free(tbuf);
594  return GWEN_ERROR_EOF;
595  }
596 
598  DBG_DEBUG(GWEN_LOGDOMAIN, "Received HTTP status:");
599  GWEN_Text_LogString((const char*) GWEN_Buffer_GetStart(tbuf),
603  }
604 
606  if (rv<0) {
607  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
608  GWEN_Buffer_free(tbuf);
609  return rv;
610  }
611 
612  GWEN_Buffer_free(tbuf);
613  return 0;
614 }
615 
616 
617 
619  GWEN_SYNCIO_HTTP *xio;
620  GWEN_SYNCIO *baseIo;
621  GWEN_BUFFER *tbuf;
622  int rv;
623 
624  assert(sio);
625  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
626  assert(xio);
627 
628  DBG_INFO(GWEN_LOGDOMAIN, "Reading command");
629  baseIo=GWEN_SyncIo_GetBaseIo(sio);
630  assert(baseIo);
631 
632  /* read a single line */
633  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
634  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
635  if (rv<0) {
636  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
637  GWEN_Buffer_free(tbuf);
638  return rv;
639  }
640 
642  if (rv<0) {
643  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
644  GWEN_Buffer_free(tbuf);
645  return rv;
646  }
647 
648  GWEN_Buffer_free(tbuf);
649  return 0;
650 }
651 
652 
653 
655  GWEN_SYNCIO_HTTP *xio;
656  GWEN_SYNCIO *baseIo;
657  char *p;
658  const char *s;
659 
660  assert(sio);
661  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
662  assert(xio);
663 
664  baseIo=GWEN_SyncIo_GetBaseIo(sio);
665  assert(baseIo);
666 
667  /* resolve line continuations */
668  p=buf;
669  while(*p) {
670  p=strchr(p, 10);
671  if (p) {
672  if (p[1]==32 || p[1]==9)
673  /* found a continuation */
674  *p=32;
675  p++;
676  }
677  }
678 
679  /* parse every line */
680  p=buf;
681  while(p && *p) {
682  char *pNext;
683  char *pVarBegin;
684  char *pVarEnd;
685 
686  /* skip blanks */
687  pNext=strchr(p, 10);
688  if (pNext) {
689  *pNext=0;
690  pNext++;
691  }
692  while(*p && (*p==32 || *p==9))
693  p++;
694  if (*p) {
695  pVarBegin=p;
696  while(*p && *p!=':' && *p>32 && *p<127)
697  p++;
698  pVarEnd=p;
699  if (*p!=':') {
700  DBG_INFO(GWEN_LOGDOMAIN, "No separator after variable name in received header");
701  return GWEN_ERROR_BAD_DATA;
702  }
703  *pVarEnd=0;
704  p++;
705 
706  while(*p && (*p==32 || *p==9))
707  p++;
708  if (*p)
709  GWEN_DB_SetCharValue(xio->dbHeaderIn, GWEN_PATH_FLAGS_CREATE_VAR, pVarBegin, p);
710  }
711  p=pNext;
712  }
713 
714  /* default next mode after reading the header is reading the body
715  * (if any, but that will be checked later) */
716  xio->readMode=GWEN_SyncIo_Http_Mode_Body;
717 
718  /* header received, now read some settings from it */
719  s=GWEN_DB_GetCharValue(xio->dbHeaderIn, "Transfer-Encoding", 0, 0);
720  if (s && (-1!=GWEN_Text_ComparePattern(s, "*chunked*", 0))) {
721  /* chunked encoding, this means next we have to read the chunksize */
722  DBG_DEBUG(GWEN_LOGDOMAIN, "Body is \"chunked\"");
723  xio->currentReadChunkSize=-1;
724  xio->readMode=GWEN_SyncIo_Http_Mode_ChunkSize;
725  }
726 
727  /* get size of body */
728  xio->currentReadBodySize=GWEN_DB_GetIntValue(xio->dbHeaderIn, "Content-Length", 0, -1);
729  if (xio->currentReadBodySize==0) {
730  /* no body */
732  }
733  else if (xio->currentReadBodySize==-1) {
734  int rcode;
735 
736  /* no length of body received, assume 0 in case of an error
737  * This eliminates the bug where this module waits for
738  * a timeout when receiving an error from a special server
739  */
740  rcode=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, -1);
741  if (rcode<0 || rcode>=300) {
742  /* no body */
744  }
745  }
746 
747  return 0;
748 }
749 
750 
751 
753  GWEN_SYNCIO_HTTP *xio;
754  GWEN_SYNCIO *baseIo;
755  GWEN_BUFFER *tbuf;
756  int rv;
757  uint32_t pos;
758  int lines=0;
759 
760  assert(sio);
761  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
762  assert(xio);
763 
764  DBG_INFO(GWEN_LOGDOMAIN, "Reading header");
765  baseIo=GWEN_SyncIo_GetBaseIo(sio);
766  assert(baseIo);
767 
768  /* we want to read a text line, so we can't have a transparent mode in the base layer */
770 
771  /* read a single line */
772  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
773  pos=0;
774  do {
775  uint8_t *p;
776 
777  GWEN_Buffer_AllocRoom(tbuf, 1024);
778  p=(uint8_t*) GWEN_Buffer_GetPosPointer(tbuf);
779  rv=GWEN_SyncIo_Read(baseIo, p, 1024);
780  if (rv<0) {
781  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
782  GWEN_Buffer_free(tbuf);
783  return rv;
784  }
785  else if (rv>0) {
786  GWEN_Buffer_IncrementPos(tbuf, rv);
788  if (p[rv-1]==10) {
789  uint32_t npos;
790 
791  lines++;
792  npos=GWEN_Buffer_GetPos(tbuf);
793  if ((npos-pos)==1) {
794  /* empty line, header finished */
795  break;
796  }
797  pos=npos;
798  }
799  }
800  else if (rv==0)
801  break;
802  }
803  while(rv>0);
804 
805  if (lines<1) {
806  DBG_ERROR(GWEN_LOGDOMAIN, "No header line received");
807  GWEN_Buffer_free(tbuf);
808  return GWEN_ERROR_EOF;
809  }
810 
812  DBG_DEBUG(GWEN_LOGDOMAIN, "Received HTTP header:");
813  GWEN_Text_LogString((const char*) GWEN_Buffer_GetStart(tbuf),
817  }
818 
820  if (rv<0) {
821  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
822  GWEN_Buffer_free(tbuf);
823  return rv;
824  }
825 
826  GWEN_Buffer_free(tbuf);
827  return 0;
828 }
829 
830 
831 
833  GWEN_SYNCIO_HTTP *xio;
834  GWEN_SYNCIO *baseIo;
835  GWEN_BUFFER *tbuf;
836  int rv;
837  int csize;
838 
839  assert(sio);
840  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
841  assert(xio);
842 
843  DBG_INFO(GWEN_LOGDOMAIN, "Reading chunksize");
844  baseIo=GWEN_SyncIo_GetBaseIo(sio);
845  assert(baseIo);
846 
847  /* read a single line */
848  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
849  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
850  if (rv<0) {
851  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
852  GWEN_Buffer_free(tbuf);
853  return rv;
854  }
855 
856  if (*GWEN_Buffer_GetStart(tbuf)==0) {
857  GWEN_Buffer_Reset(tbuf);
858  rv=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
859  if (rv<0) {
860  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
861  GWEN_Buffer_free(tbuf);
862  return rv;
863  }
864  }
865 
866  if (1!=sscanf(GWEN_Buffer_GetStart(tbuf), "%x", &csize)) {
867  DBG_ERROR(GWEN_LOGDOMAIN, "Bad data received (invalid chunksize specifier: [%s])",
868  GWEN_Buffer_GetStart(tbuf));
869  GWEN_Buffer_free(tbuf);
870  return GWEN_ERROR_BAD_DATA;
871  }
872 
873  xio->currentReadChunkSize=csize;
874 
875  GWEN_Buffer_free(tbuf);
876  return 0;
877 }
878 
879 
880 
881 int GWEN_SyncIo_Http_ReadChunk(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size) {
882  GWEN_SYNCIO_HTTP *xio;
883  GWEN_SYNCIO *baseIo;
884  int rv;
885 
886  assert(sio);
887  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
888  assert(xio);
889 
890  DBG_DEBUG(GWEN_LOGDOMAIN, "Reading chunk (%d bytes)", (int) size);
891  baseIo=GWEN_SyncIo_GetBaseIo(sio);
892  assert(baseIo);
893 
894  /* we want to read binary data transparently */
896 
897  if (size>xio->currentReadChunkSize)
898  size=xio->currentReadChunkSize;
899 
900  rv=GWEN_SyncIo_Read(baseIo, buffer, size);
901  if (rv<0) {
902  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
903  return rv;
904  }
905 
906  xio->currentReadChunkSize-=rv;
907  if (xio->currentReadBodySize>0)
908  xio->currentReadBodySize-=rv;
909 
910  if (xio->currentReadChunkSize==0) {
911  int rv2;
912  GWEN_BUFFER *tbuf;
913 
914  /* chunk finished, read trailing CR/LF */
915  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
916  rv2=GWEN_SyncIo_Http_ReadLine(sio, tbuf);
917  if (rv2<0) {
918  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
919  GWEN_Buffer_free(tbuf);
920  return rv2;
921  }
922  GWEN_Buffer_free(tbuf);
923 
924  DBG_DEBUG(GWEN_LOGDOMAIN, "Chunk finished.");
925 
926  /* change read mode */
927  xio->readMode=GWEN_SyncIo_Http_Mode_ChunkSize;
928  }
929 
930  return rv;
931 }
932 
933 
934 
935 int GWEN_SyncIo_Http_ReadBody(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size) {
936  GWEN_SYNCIO_HTTP *xio;
937  GWEN_SYNCIO *baseIo;
938  int rv;
939 
940  assert(size);
941 
942  assert(sio);
943  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
944  assert(xio);
945 
946  DBG_INFO(GWEN_LOGDOMAIN, "Reading body");
947  baseIo=GWEN_SyncIo_GetBaseIo(sio);
948  assert(baseIo);
949 
950  /* we want to read binary data transparently */
952 
953  if ((xio->currentReadBodySize>=0) &&
954  (size>xio->currentReadBodySize)) {
955  DBG_INFO(GWEN_LOGDOMAIN, "Adjusting read body size from %d to %d",
956  size, xio->currentReadBodySize);
957  size=xio->currentReadBodySize;
958  }
959 
960  rv=GWEN_SyncIo_Read(baseIo, buffer, size);
961  if (rv<0) {
962  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
963  return rv;
964  }
965 
966  if (xio->currentReadBodySize>=0)
967  xio->currentReadBodySize-=rv;
968 
969  if (xio->currentReadBodySize==0)
970  /* body finished, change read mode */
972 
973  return rv;
974 }
975 
976 
977 
979  GWEN_SYNCIO_HTTP *xio;
980  GWEN_SYNCIO *baseIo;
981  int rv;
982  const char *s;
983  GWEN_BUFFER *tbuf;
984 
985  assert(sio);
986  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
987  assert(xio);
988 
989  baseIo=GWEN_SyncIo_GetBaseIo(sio);
990  assert(baseIo);
991 
992  /* we will construct the line including CR/LF ourselves */
994 
995  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
996 
997  s=GWEN_DB_GetCharValue(xio->dbCommandOut, "command", 0, "GET");
998  GWEN_Buffer_AppendString(tbuf, s);
999  GWEN_Buffer_AppendString(tbuf, " ");
1000 
1001  s=GWEN_DB_GetCharValue(xio->dbCommandOut, "url", 0, "/");
1002  GWEN_Buffer_AppendString(tbuf, s);
1003  GWEN_Buffer_AppendString(tbuf, " ");
1004 
1005  s=GWEN_DB_GetCharValue(xio->dbCommandOut, "protocol", 0, "HTTP/1.0");
1006  GWEN_Buffer_AppendString(tbuf, s);
1007  GWEN_Buffer_AppendString(tbuf, "\r\n");
1008 
1010  DBG_DEBUG(GWEN_LOGDOMAIN, "Sending HTTP command:");
1011  GWEN_Text_LogString((const char*) GWEN_Buffer_GetStart(tbuf),
1015  }
1016 
1017  /* write */
1018  rv=GWEN_SyncIo_WriteForced(baseIo,
1019  (const uint8_t*) GWEN_Buffer_GetStart(tbuf),
1020  GWEN_Buffer_GetUsedBytes(tbuf));
1021  if (rv<0) {
1022  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1023  GWEN_Buffer_free(tbuf);
1024  return rv;
1025  }
1026 
1027  GWEN_Buffer_free(tbuf);
1028  return 0;
1029 }
1030 
1031 
1032 
1034  GWEN_SYNCIO_HTTP *xio;
1035  GWEN_SYNCIO *baseIo;
1036  int rv;
1037  const char *s;
1038  GWEN_BUFFER *tbuf;
1039  char numbuf[32];
1040  int i;
1041 
1042  assert(sio);
1043  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1044  assert(xio);
1045 
1046  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1047  assert(baseIo);
1048 
1049  /* we will construct the line including CR/LF ourselves */
1051 
1052  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
1053 
1054  s=GWEN_DB_GetCharValue(xio->dbStatusOut, "protocol", 0, "HTTP/1.0");
1055  GWEN_Buffer_AppendString(tbuf, s);
1056  GWEN_Buffer_AppendString(tbuf, " ");
1057 
1058  i=GWEN_DB_GetIntValue(xio->dbStatusOut, "code", 0, -1);
1059  if (i==-1) {
1060  DBG_INFO(GWEN_LOGDOMAIN, "Missing status code");
1061  GWEN_Buffer_free(tbuf);
1062  return GWEN_ERROR_NO_DATA;
1063  }
1064  snprintf(numbuf, sizeof(numbuf), "%d ", i);
1065  GWEN_Buffer_AppendString(tbuf, numbuf);
1066 
1067  s=GWEN_DB_GetCharValue(xio->dbStatusOut, "text", 0, "No text.");
1068  GWEN_Buffer_AppendString(tbuf, s);
1069  GWEN_Buffer_AppendString(tbuf, "\r\n");
1070 
1071  /* write */
1072  rv=GWEN_SyncIo_WriteForced(baseIo,
1073  (const uint8_t*) GWEN_Buffer_GetStart(tbuf),
1074  GWEN_Buffer_GetUsedBytes(tbuf));
1075  if (rv<0) {
1076  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1077  GWEN_Buffer_free(tbuf);
1078  return rv;
1079  }
1080 
1081  GWEN_Buffer_free(tbuf);
1082  return 0;
1083 }
1084 
1085 
1086 
1088  GWEN_SYNCIO_HTTP *xio;
1089  GWEN_SYNCIO *baseIo;
1090  int i;
1091  GWEN_DB_NODE *dbVar;
1092  GWEN_BUFFER *tbuf;
1093  int rv;
1094 
1095  assert(sio);
1096  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1097  assert(xio);
1098 
1099  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1100  assert(baseIo);
1101 
1102  /* we will construct the line including CR/LF ourselves */
1104 
1105  /* default next mode after writing the header is writing the body
1106  * (if any, but that will be checked later) */
1107  xio->writeMode=GWEN_SyncIo_Http_Mode_Body;
1108 
1109  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
1110 
1111  i=GWEN_DB_GetIntValue(xio->dbHeaderOut, "Content-Length", 0, -1);
1112  xio->currentWriteBodySize=i;
1113 
1114  dbVar=GWEN_DB_GetFirstVar(xio->dbHeaderOut);
1115  while (dbVar) {
1116  GWEN_DB_NODE *dbVal;
1117 
1118  /* only handle first value */
1119  dbVal=GWEN_DB_GetFirstValue(dbVar);
1120  if (dbVal) {
1121  GWEN_DB_NODE_TYPE vtype;
1122 
1123  vtype=GWEN_DB_GetValueType(dbVal);
1124  if (vtype==GWEN_DB_NodeType_ValueChar) {
1125  const char *s;
1126 
1128  GWEN_Buffer_AppendString(tbuf, ":");
1130  if (s)
1131  GWEN_Buffer_AppendString(tbuf, s);
1132  GWEN_Buffer_AppendString(tbuf, "\r\n");
1133 
1134  if (strcasecmp(GWEN_DB_VariableName(dbVar), "Transfer-Encoding")==0) {
1135  if (s && (-1!=GWEN_Text_ComparePattern(s, "*chunked*", 0))) {
1136  /* chunked encoding, this means next we have to write the chunksize */
1137  xio->writeMode=GWEN_SyncIo_Http_Mode_ChunkSize;
1138  }
1139  }
1140  }
1141  else if (vtype==GWEN_DB_NodeType_ValueInt) {
1142  i=GWEN_DB_GetIntValueFromNode(dbVal);
1143  if (i!=-1 || strcasecmp(GWEN_DB_VariableName(dbVar), "Content-Length")==0) {
1144  char numbuf[32];
1145 
1146  /* don't write body size of -1 */
1148  GWEN_Buffer_AppendString(tbuf, ":");
1149  snprintf(numbuf, sizeof(numbuf), "%d", i);
1150  GWEN_Buffer_AppendString(tbuf, numbuf);
1151  GWEN_Buffer_AppendString(tbuf, "\r\n");
1152  }
1153  }
1154  else {
1155  DBG_INFO(GWEN_LOGDOMAIN, "Variable type %d of var [%s] not supported",
1156  vtype, GWEN_DB_VariableName(dbVar));
1157  return GWEN_ERROR_BAD_DATA;
1158  }
1159  }
1160  dbVar=GWEN_DB_GetNextVar(dbVar);
1161  }
1162 
1163  /* finalize header */
1164  GWEN_Buffer_AppendString(tbuf, "\r\n");
1165 
1167  DBG_DEBUG(GWEN_LOGDOMAIN, "Sending HTTP header:");
1168  GWEN_Text_LogString((const char*) GWEN_Buffer_GetStart(tbuf),
1172  }
1173 
1174  /* write */
1175  rv=GWEN_SyncIo_WriteForced(baseIo,
1176  (const uint8_t*) GWEN_Buffer_GetStart(tbuf),
1177  GWEN_Buffer_GetUsedBytes(tbuf));
1178  if (rv<0) {
1179  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1180  GWEN_Buffer_free(tbuf);
1181  return rv;
1182  }
1183  GWEN_Buffer_free(tbuf);
1184 
1185  if (xio->currentWriteBodySize==0)
1187 
1188  return 0;
1189 }
1190 
1191 
1192 
1194  GWEN_SYNCIO_HTTP *xio;
1195  GWEN_SYNCIO *baseIo;
1196  int rv;
1197  char numbuf[32];
1198 
1199  assert(sio);
1200  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1201  assert(xio);
1202 
1203  baseIo=GWEN_SyncIo_GetBaseIo(sio);
1204  assert(baseIo);
1205 
1206  /* we will construct the line including CR/LF ourselves */
1208 
1209  snprintf(numbuf, sizeof(numbuf)-1, "%x\r\n", size);
1210  numbuf[sizeof(numbuf)-1]=0;
1211 
1212  rv=GWEN_SyncIo_WriteForced(baseIo, (const uint8_t*) numbuf, strlen(numbuf));
1213  if (rv<0) {
1214  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1215  return rv;
1216  }
1217 
1218  return 0;
1219 }
1220 
1221 
1222 
1224  GWEN_SYNCIO_HTTP *xio;
1225 
1226  assert(sio);
1227  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1228  assert(xio);
1229 
1230  xio->writeMode=GWEN_SyncIo_Http_Mode_Idle;
1231  GWEN_DB_ClearGroup(xio->dbStatusOut, NULL);
1232 }
1233 
1234 
1235 
1236 
1238  GWEN_SYNCIO_HTTP *xio;
1239 
1240  assert(sio);
1241  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1242  assert(xio);
1243 
1244  return xio->dbCommandIn;
1245 }
1246 
1247 
1248 
1250  GWEN_SYNCIO_HTTP *xio;
1251 
1252  assert(sio);
1253  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1254  assert(xio);
1255 
1256  return xio->dbStatusIn;
1257 }
1258 
1259 
1260 
1262  GWEN_SYNCIO_HTTP *xio;
1263 
1264  assert(sio);
1265  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1266  assert(xio);
1267 
1268  return xio->dbHeaderIn;
1269 }
1270 
1271 
1272 
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->dbCommandOut;
1281 }
1282 
1283 
1284 
1286  GWEN_SYNCIO_HTTP *xio;
1287 
1288  assert(sio);
1289  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1290  assert(xio);
1291 
1292  return xio->dbStatusOut;
1293 }
1294 
1295 
1296 
1298  GWEN_SYNCIO_HTTP *xio;
1299 
1300  assert(sio);
1301  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1302  assert(xio);
1303 
1304  return xio->dbHeaderOut;
1305 }
1306 
1307 
1308 
1309 
1311  GWEN_SYNCIO_HTTP *xio;
1312  int rv;
1313  int code=0;
1314  int firstRead=1;
1315  int bodySize=-1;
1316  int bytesRead=0;
1317  uint32_t pid;
1318 
1319  assert(sio);
1320  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1321  assert(xio);
1322 
1327  I18N("Network Operation"),
1328  I18N("Receiving data"),
1329  0,
1330  0);
1331 
1332 
1333  /* recv packet (this reads the HTTP body) */
1334  for (;;) {
1335  uint8_t *p;
1336  uint32_t l;
1337 
1338  rv=GWEN_Buffer_AllocRoom(buf, 1024);
1339  if (rv<0) {
1340  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1341  GWEN_Gui_ProgressEnd(pid);
1342  return rv;
1343  }
1344 
1345  p=(uint8_t*) GWEN_Buffer_GetPosPointer(buf);
1347  do {
1348  rv=GWEN_SyncIo_Read(sio, p, l-1);
1349  }
1350  while(rv==GWEN_ERROR_INTERRUPTED);
1351 
1352  if (rv==0)
1353  break;
1354  else if (rv<0) {
1355  if (rv==GWEN_ERROR_EOF) {
1356  if (bodySize!=-1 && bytesRead<bodySize) {
1358  "EOF met prematurely (%d < %d)",
1359  bytesRead, bodySize);
1360  GWEN_Gui_ProgressEnd(pid);
1361  return GWEN_ERROR_EOF;
1362  }
1363  }
1364  else {
1365  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1366  /*return rv;*/
1367  break;
1368  }
1369  }
1370  else {
1371  GWEN_Buffer_IncrementPos(buf, rv);
1373  if (firstRead) {
1374  GWEN_DB_NODE *db;
1375 
1377  bodySize=GWEN_DB_GetIntValue(db, "Content-length", 0, -1);
1378 
1379  if (bodySize!=-1)
1380  GWEN_Gui_ProgressSetTotal(pid, bodySize);
1381  }
1382  bytesRead+=rv;
1383 
1384  /* advance progress bar */
1385  rv=GWEN_Gui_ProgressAdvance(pid, bytesRead);
1386  if (rv==GWEN_ERROR_USER_ABORTED) {
1387  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1388  GWEN_Gui_ProgressEnd(pid);
1389  return rv;
1390  }
1391  }
1392 
1393  if (bodySize!=-1 && bytesRead>=bodySize) {
1394  break;
1395  }
1396 
1397  firstRead=0;
1398  }
1399  GWEN_Gui_ProgressEnd(pid);
1400 
1401  if (rv<0) {
1402  if (GWEN_Buffer_GetUsedBytes(buf)) {
1403  /* data received, check for common error codes */
1404  if (rv==GWEN_ERROR_EOF || rv==GWEN_ERROR_IO || rv==GWEN_ERROR_SSL) {
1406  "We received an error, but we still got data, "
1407  "so we ignore the error here");
1408  }
1409  else {
1410  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1413  I18N("No message received"));
1414  return rv;
1415  }
1416  }
1417  else {
1418  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1421  I18N("No message received"));
1422  return rv;
1423  }
1424  }
1425 
1427  code=0;
1428  else {
1429  code=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, 0);
1430  if (code) {
1431  const char *s;
1432 
1433  s=GWEN_DB_GetCharValue(xio->dbStatusIn, "text", 0, NULL);
1434  DBG_DEBUG(GWEN_LOGDOMAIN, "HTTP-Status: %d (%s)",
1435  code, s?s:"- no text -");
1437  I18N("HTTP-Status: %d (%s)"),
1438  code, s?s:I18N("- no details -"));
1439  }
1440  else {
1441  DBG_ERROR(GWEN_LOGDOMAIN, "No HTTP status code received");
1444  I18N("No HTTP status code received"));
1445  code=GWEN_ERROR_BAD_DATA;
1446  }
1447  }
1448 
1449  return code;
1450 }
1451 
1452 
1453 
1455  GWEN_SYNCIO_HTTP *xio;
1456  int rv;
1457  int code=0;
1458  int firstRead=1;
1459  int bodySize=-1;
1460  int bytesRead=0;
1461  uint32_t pid;
1462 
1463  assert(sio);
1464  xio=GWEN_INHERIT_GETDATA(GWEN_SYNCIO, GWEN_SYNCIO_HTTP, sio);
1465  assert(xio);
1466 
1471  I18N("Network Operation"),
1472  I18N("Receiving data"),
1473  0,
1474  0);
1475 
1476  /* recv packet (this reads the HTTP body) */
1477  for (;;) {
1478  uint8_t *p;
1479  uint32_t l;
1480  uint8_t rbuf[1024];
1481 
1482  p=rbuf;
1483  l=sizeof(rbuf);
1484 
1485  do {
1486  rv=GWEN_SyncIo_Read(sio, p, l-1);
1487  }
1488  while(rv==GWEN_ERROR_INTERRUPTED);
1489 
1490  if (rv==0)
1491  break;
1492  else if (rv<0) {
1493  if (rv==GWEN_ERROR_EOF) {
1494  if (bodySize!=-1 && bytesRead<bodySize) {
1496  "EOF met prematurely (%d < %d)",
1497  bytesRead, bodySize);
1498  GWEN_Gui_ProgressEnd(pid);
1499  return GWEN_ERROR_EOF;
1500  }
1501  }
1502  else {
1503  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1504  /*return rv;*/
1505  break;
1506  }
1507  }
1508  else {
1509  int rv2;
1510 
1511  rv2=GWEN_SyncIo_WriteForced(sout, rbuf, rv);
1512  if (rv2<0) {
1513  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
1514  GWEN_Gui_ProgressEnd(pid);
1515  return rv2;
1516  }
1517  if (firstRead) {
1518  GWEN_DB_NODE *db;
1519 
1521  bodySize=GWEN_DB_GetIntValue(db, "Content-length", 0, -1);
1522 
1523  if (bodySize!=-1)
1524  GWEN_Gui_ProgressSetTotal(pid, bodySize);
1525  }
1526  bytesRead+=rv;
1527 
1528  /* advance progress bar */
1529  rv=GWEN_Gui_ProgressAdvance(pid, bytesRead);
1530  if (rv==GWEN_ERROR_USER_ABORTED) {
1531  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
1532  GWEN_Gui_ProgressEnd(pid);
1533  return rv;
1534  }
1535  }
1536 
1537  if (bodySize!=-1 && bytesRead>=bodySize) {
1538  break;
1539  }
1540  firstRead=0;
1541  }
1542  GWEN_Gui_ProgressEnd(pid);
1543 
1544 
1545  if (rv<0) {
1546  if (bytesRead) {
1547  /* data received, check for common error codes */
1548  if (rv==GWEN_ERROR_EOF || rv==GWEN_ERROR_IO || rv==GWEN_ERROR_SSL) {
1550  "We received an error, but we still got data, "
1551  "so we ignore the error here");
1552  }
1553  else {
1554  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1557  I18N("No message received"));
1558  return rv;
1559  }
1560  }
1561  else {
1562  DBG_INFO(GWEN_LOGDOMAIN, "No message received (%d)", rv);
1565  I18N("No message received"));
1566  return rv;
1567  }
1568  }
1569 
1571  code=0;
1572  else {
1573  code=GWEN_DB_GetIntValue(xio->dbStatusIn, "code", 0, 0);
1574  if (code) {
1575  const char *s;
1576 
1577  s=GWEN_DB_GetCharValue(xio->dbStatusIn, "text", 0, NULL);
1578  DBG_DEBUG(GWEN_LOGDOMAIN, "HTTP-Status: %d (%s)",
1579  code, s?s:"- no text -");
1581  I18N("HTTP-Status: %d (%s)"),
1582  code, s?s:I18N("- no details -)"));
1583  }
1584  else {
1585  DBG_ERROR(GWEN_LOGDOMAIN, "No HTTP status code received");
1588  I18N("No HTTP status code received"));
1589  code=GWEN_ERROR_BAD_DATA;
1590  }
1591  }
1592 
1593  return code;
1594 }
1595 
1596 
1597 
1598 
int GWEN_SyncIo_WriteForced(GWEN_SYNCIO *sio, const uint8_t *buffer, uint32_t size)
Definition: syncio.c:295
int GWEN_Gui_ProgressLog(uint32_t id, GWEN_LOGGER_LEVEL level, const char *text)
Definition: gui.c:940
char * GWEN_Buffer_GetStart(const GWEN_BUFFER *bf)
Definition: buffer.c:223
int GWENHYWFAR_CB GWEN_SyncIo_Http_Connect(GWEN_SYNCIO *sio)
Definition: syncio_http.c:97
#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:94
int GWEN_Gui_ProgressAdvance(uint32_t id, uint32_t progress)
Definition: gui.c:920
void GWEN_SyncIo_SubFlags(GWEN_SYNCIO *sio, uint32_t fl)
Definition: syncio.c:177
struct GWEN_DB_NODE GWEN_DB_NODE
Definition: db.h:228
int GWEN_Buffer_AllocRoom(GWEN_BUFFER *bf, uint32_t size)
Definition: buffer.c:273
uint32_t GWEN_Buffer_GetMaxUnsegmentedWrite(GWEN_BUFFER *bf)
Definition: buffer.c:569
int GWEN_SyncIo_Http_ParseHeader(GWEN_SYNCIO *sio, char *buf)
Definition: syncio_http.c:654
int GWEN_SyncIo_Http_RecvBodyToSio(GWEN_SYNCIO *sio, GWEN_SYNCIO *sout)
Definition: syncio_http.c:1454
void GWEN_DB_Group_free(GWEN_DB_NODE *n)
Definition: db.c:369
#define GWEN_ERROR_INVALID
Definition: error.h:67
int GWENHYWFAR_CB GWEN_SyncIo_Http_Disconnect(GWEN_SYNCIO *sio)
Definition: syncio_http.c:128
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbHeaderOut(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1297
void GWEN_SyncIo_Http_SetWriteIdle(GWEN_SYNCIO *sio)
Definition: syncio_http.c:1223
uint32_t GWEN_Buffer_GetUsedBytes(const GWEN_BUFFER *bf)
Definition: buffer.c:266
#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:127
int GWEN_SyncIo_Http_RecvBody(GWEN_SYNCIO *sio, GWEN_BUFFER *buf)
Definition: syncio_http.c:1310
int GWEN_SyncIo_Http_ReadStatus(GWEN_SYNCIO *sio)
Definition: syncio_http.c:568
int GWEN_Gui_ProgressSetTotal(uint32_t id, uint64_t total)
Definition: gui.c:930
GWEN_SYNCIO_WRITE_FN GWEN_SyncIo_SetWriteFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_WRITE_FN fn)
Definition: syncio.c:283
#define GWEN_FREE_OBJECT(varname)
Definition: memory.h:92
#define NULL
Definition: binreloc.c:290
GWEN_SYNCIO_CONNECT_FN GWEN_SyncIo_SetConnectFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_CONNECT_FN fn)
Definition: syncio.c:235
#define GWEN_SYNCIO_FLAGS_TRANSPARENT
Definition: syncio.h:55
int GWEN_SyncIo_Http_ParseCommand(GWEN_SYNCIO *sio, const char *buffer)
Definition: syncio_http.c:511
uint32_t GWEN_SyncIo_GetFlags(const GWEN_SYNCIO *sio)
Definition: syncio.c:153
#define GWEN_GUI_PROGRESS_DELAY
Definition: gui.h:192
int GWEN_Buffer_AdjustUsedBytes(GWEN_BUFFER *bf)
Definition: buffer.c:513
int GWEN_SyncIo_Http_ReadChunk(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition: syncio_http.c:881
#define GWEN_LOGDOMAIN
Definition: logger.h:35
void GWEN_SyncIo_SetStatus(GWEN_SYNCIO *sio, GWEN_SYNCIO_STATUS st)
Definition: syncio.c:193
uint32_t GWEN_Buffer_GetPos(const GWEN_BUFFER *bf)
Definition: buffer.c:239
GWEN_BUFFER * GWEN_Buffer_new(char *buffer, uint32_t size, uint32_t used, int take)
Definition: buffer.c:38
GWEN_SYNCIO * GWEN_SyncIo_GetBaseIo(const GWEN_SYNCIO *sio)
Definition: syncio.c:209
char * GWEN_Buffer_GetPosPointer(const GWEN_BUFFER *bf)
Definition: buffer.c:588
#define GWEN_ERROR_IO
Definition: error.h:123
void GWEN_Buffer_Reset(GWEN_BUFFER *bf)
Definition: buffer.c:684
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbStatusOut(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1285
int GWEN_Buffer_IncrementPos(GWEN_BUFFER *bf, uint32_t i)
Definition: buffer.c:495
#define GWEN_ERROR_INTERRUPTED
Definition: error.h:74
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbHeaderIn(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1261
int GWEN_SyncIo_Http_ReadBody(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition: syncio_http.c:935
int GWEN_SyncIo_Http_ParseStatus(GWEN_SYNCIO *sio, char *buffer)
Definition: syncio_http.c:464
#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:423
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbStatusIn(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1249
#define GWEN_NEW_OBJECT(typ, varname)
Definition: memory.h:86
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:192
int GWEN_SyncIo_Http_ReadLine(GWEN_SYNCIO *sio, GWEN_BUFFER *tbuf)
Definition: syncio_http.c:413
int GWEN_Gui_ProgressLog2(uint32_t id, GWEN_LOGGER_LEVEL level, const char *fmt,...)
Definition: gui.c:951
#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:1551
#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:897
GWEN_SYNCIO_STATUS GWEN_SyncIo_GetStatus(const GWEN_SYNCIO *sio)
Definition: syncio.c:185
const char * GWEN_DB_VariableName(GWEN_DB_NODE *n)
Definition: db.c:1776
void GWEN_Buffer_free(GWEN_BUFFER *bf)
Definition: buffer.c:83
struct GWEN_BUFFER GWEN_BUFFER
A dynamically resizeable text buffer.
Definition: buffer.h:41
int GWENHYWFAR_CB GWEN_SyncIo_Http_Write(GWEN_SYNCIO *sio, const uint8_t *buffer, uint32_t size)
Definition: syncio_http.c:306
void GWEN_SyncIo_AddFlags(GWEN_SYNCIO *sio, uint32_t fl)
Definition: syncio.c:169
uint32_t GWEN_Gui_ProgressStart(uint32_t progressFlags, const char *title, const char *text, uint64_t total, uint32_t guiid)
Definition: gui.c:903
int GWEN_Gui_ProgressEnd(uint32_t id)
Definition: gui.c:971
#define GWEN_PATH_FLAGS_CREATE_VAR
Definition: path.h:103
int GWEN_SyncIo_Http_ReadHeader(GWEN_SYNCIO *sio)
Definition: syncio_http.c:752
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbCommandOut(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1273
#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:1087
int GWEN_SyncIo_Disconnect(GWEN_SYNCIO *sio)
Definition: syncio.c:105
#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:1162
int GWEN_DB_SetCharValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, const char *val)
Definition: db.c:922
GWEN_SYNCIO * GWEN_SyncIo_new(const char *typeName, GWEN_SYNCIO *baseIo)
Definition: syncio.c:51
void GWENHYWFAR_CB GWEN_SyncIo_Http_FreeData(void *bp, void *p)
Definition: syncio_http.c:79
GWEN_DB_NODE * GWEN_DB_GetFirstValue(GWEN_DB_NODE *n)
Definition: db.c:460
GWEN_SYNCIO_DISCONNECT_FN GWEN_SyncIo_SetDisconnectFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_DISCONNECT_FN fn)
Definition: syncio.c:247
#define DBG_INFO(dbg_logger, format, args...)
Definition: debug.h:164
GWEN_DB_NODE * GWEN_DB_GetNextVar(GWEN_DB_NODE *n)
Definition: db.c:443
#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:157
int GWEN_DB_GetIntValue(GWEN_DB_NODE *n, const char *path, int idx, int defVal)
Definition: db.c:1048
GWEN_DB_NODE * GWEN_DB_Group_new(const char *name)
Definition: db.c:131
int GWEN_Logger_GetLevel(const char *logDomain)
Definition: logger.c:614
#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:271
int GWENHYWFAR_CB GWEN_SyncIo_Http_Read(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition: syncio_http.c:169
int GWEN_DB_SetIntValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, int val)
Definition: db.c:1086
#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:544
int GWEN_SyncIo_Http_WriteStatus(GWEN_SYNCIO *sio)
Definition: syncio_http.c:1033
int GWEN_SyncIo_Http_ReadCommand(GWEN_SYNCIO *sio)
Definition: syncio_http.c:618
int GWEN_DB_ClearGroup(GWEN_DB_NODE *n, const char *path)
Definition: db.c:871
#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:832
int GWEN_SyncIo_Http_WriteCommand(GWEN_SYNCIO *sio)
Definition: syncio_http.c:978
int GWEN_Buffer_AppendString(GWEN_BUFFER *bf, const char *buffer)
Definition: buffer.c:1014
GWEN_DB_NODE_TYPE GWEN_DB_GetValueType(GWEN_DB_NODE *n)
Definition: db.c:503
#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:1237
const char * GWEN_DB_GetCharValueFromNode(const GWEN_DB_NODE *n)
Definition: db.c:517
#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:1193