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
48GWEN_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);
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
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) {
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
520int 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])",
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
896int 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
951int 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),
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),
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) {
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),
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);
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);
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);
1418 return rv;
1419 }
1420 }
1421
1422 if (bodySize!=-1 && bytesRead>=bodySize) {
1423 break;
1424 }
1425
1426 firstRead=0;
1427 }
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"));
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);
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);
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);
1563 return rv;
1564 }
1565 }
1566
1567 if (bodySize!=-1 && bytesRead>=bodySize) {
1568 break;
1569 }
1570 firstRead=0;
1571 }
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"));
1620 }
1621 }
1622
1623 return code;
1624}
1625
1626
1627
1628
#define NULL
Definition: binreloc.c:300
GWEN_BUFFER * GWEN_Buffer_new(char *buffer, uint32_t size, uint32_t used, int take)
Definition: buffer.c:42
int GWEN_Buffer_IncrementPos(GWEN_BUFFER *bf, uint32_t i)
Definition: buffer.c:452
uint32_t GWEN_Buffer_GetMaxUnsegmentedWrite(GWEN_BUFFER *bf)
Definition: buffer.c:528
void GWEN_Buffer_Reset(GWEN_BUFFER *bf)
Definition: buffer.c:650
int GWEN_Buffer_AdjustUsedBytes(GWEN_BUFFER *bf)
Definition: buffer.c:469
char * GWEN_Buffer_GetPosPointer(const GWEN_BUFFER *bf)
Definition: buffer.c:549
uint32_t GWEN_Buffer_GetPos(const GWEN_BUFFER *bf)
Definition: buffer.c:253
void GWEN_Buffer_free(GWEN_BUFFER *bf)
Definition: buffer.c:89
int GWEN_Buffer_AppendString(GWEN_BUFFER *bf, const char *buffer)
Definition: buffer.c:989
uint32_t GWEN_Buffer_GetUsedBytes(const GWEN_BUFFER *bf)
Definition: buffer.c:277
char * GWEN_Buffer_GetStart(const GWEN_BUFFER *bf)
Definition: buffer.c:235
int GWEN_Buffer_AllocRoom(GWEN_BUFFER *bf, uint32_t size)
Definition: buffer.c:285
const char * GWEN_DB_GetCharValue(GWEN_DB_NODE *n, const char *path, int idx, const char *defVal)
Definition: db.c:971
int GWEN_DB_ClearGroup(GWEN_DB_NODE *n, const char *path)
Definition: db.c:944
GWEN_DB_NODE * GWEN_DB_GetNextVar(GWEN_DB_NODE *n)
Definition: db.c:500
GWEN_DB_NODE * GWEN_DB_Group_new(const char *name)
Definition: db.c:173
const char * GWEN_DB_GetCharValueFromNode(const GWEN_DB_NODE *n)
Definition: db.c:578
GWEN_DB_NODE_TYPE GWEN_DB_GetValueType(GWEN_DB_NODE *n)
Definition: db.c:563
int GWEN_DB_SetIntValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, int val)
Definition: db.c:1202
GWEN_DB_NODE * GWEN_DB_GetFirstVar(GWEN_DB_NODE *n)
Definition: db.c:479
int GWEN_DB_SetCharValue(GWEN_DB_NODE *n, uint32_t flags, const char *path, const char *val)
Definition: db.c:997
const char * GWEN_DB_VariableName(GWEN_DB_NODE *n)
Definition: db.c:1928
GWEN_DB_NODE * GWEN_DB_GetFirstValue(GWEN_DB_NODE *n)
Definition: db.c:518
int GWEN_DB_GetIntValue(GWEN_DB_NODE *n, const char *path, int idx, int defVal)
Definition: db.c:1163
int GWEN_DB_GetIntValueFromNode(const GWEN_DB_NODE *n)
Definition: db.c:607
void GWEN_DB_Group_free(GWEN_DB_NODE *n)
Definition: db.c:421
GWEN_DB_NODE_TYPE
Definition: db.h:233
@ GWEN_DB_NodeType_ValueInt
Definition: db.h:243
@ GWEN_DB_NodeType_ValueChar
Definition: db.h:241
#define GWEN_DB_FLAGS_OVERWRITE_VARS
Definition: db.h:121
struct GWEN_DB_NODE GWEN_DB_NODE
Definition: db.h:228
#define DBG_DEBUG(dbg_logger, format, args...)
Definition: debug.h:214
#define DBG_INFO(dbg_logger, format, args...)
Definition: debug.h:181
#define DBG_ERROR(dbg_logger, format, args...)
Definition: debug.h:97
#define I18N(m)
Definition: error.c:42
#define GWEN_ERROR_SSL
Definition: error.h:105
#define GWEN_ERROR_INVALID
Definition: error.h:67
#define GWEN_ERROR_BAD_DATA
Definition: error.h:121
#define GWEN_ERROR_NOT_CONNECTED
Definition: error.h:120
#define GWEN_ERROR_IO
Definition: error.h:123
#define GWEN_ERROR_GENERIC
Definition: error.h:62
#define GWEN_ERROR_USER_ABORTED
Definition: error.h:65
#define GWEN_ERROR_INTERRUPTED
Definition: error.h:74
#define GWEN_ERROR_NO_DATA
Definition: error.h:94
#define GWEN_ERROR_EOF
Definition: error.h:96
struct GWEN_BUFFER GWEN_BUFFER
A dynamically resizeable text buffer.
Definition: buffer.h:38
#define GWEN_GUI_PROGRESS_DELAY
Definition: gui.h:192
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
#define GWEN_GUI_PROGRESS_SHOW_PROGRESS
Definition: gui.h:197
GWENHYWFAR_API int GWEN_Gui_ProgressEnd(uint32_t id)
Definition: gui_virtual.c:480
GWENHYWFAR_API int GWEN_Gui_ProgressLog(uint32_t id, GWEN_LOGGER_LEVEL level, const char *text)
Definition: gui_virtual.c:444
#define GWEN_GUI_PROGRESS_SHOW_ABORT
Definition: gui.h:194
GWENHYWFAR_API int GWEN_Gui_ProgressSetTotal(uint32_t id, uint64_t total)
Definition: gui_virtual.c:432
GWENHYWFAR_API int GWEN_Gui_ProgressLog2(uint32_t id, GWEN_LOGGER_LEVEL level, const char *text,...)
Definition: gui_virtual.c:458
GWENHYWFAR_API int GWEN_Gui_ProgressAdvance(uint32_t id, uint32_t progress)
Definition: gui_virtual.c:420
#define GWEN_GUI_PROGRESS_ALLOW_EMBED
Definition: gui.h:196
#define GWEN_UNUSED
#define GWENHYWFAR_CB
Definition: gwenhywfarapi.h:89
#define GWEN_INHERIT_SETDATA(bt, t, element, data, fn)
Definition: inherit.h:292
#define GWEN_INHERIT(bt, t)
Definition: inherit.h:264
#define GWEN_INHERIT_GETDATA(bt, t, element)
Definition: inherit.h:271
int GWEN_Logger_GetLevel(const char *logDomain)
Definition: logger.c:638
#define GWEN_LOGDOMAIN
Definition: logger.h:35
@ GWEN_LoggerLevel_Debug
Definition: logger.h:72
@ GWEN_LoggerLevel_Error
Definition: logger.h:68
#define GWEN_FREE_OBJECT(varname)
Definition: memory.h:61
#define GWEN_NEW_OBJECT(typ, varname)
Definition: memory.h:55
#define GWEN_PATH_FLAGS_CREATE_VAR
Definition: path.h:103
uint32_t GWEN_SyncIo_GetFlags(const GWEN_SYNCIO *sio)
Definition: syncio.c:161
int GWEN_SyncIo_Connect(GWEN_SYNCIO *sio)
Definition: syncio.c:97
void GWEN_SyncIo_AddFlags(GWEN_SYNCIO *sio, uint32_t fl)
Definition: syncio.c:179
GWEN_SYNCIO * GWEN_SyncIo_new(const char *typeName, GWEN_SYNCIO *baseIo)
Definition: syncio.c:51
GWEN_SYNCIO_READ_FN GWEN_SyncIo_SetReadFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_READ_FN fn)
Definition: syncio.c:291
GWEN_SYNCIO * GWEN_SyncIo_GetBaseIo(const GWEN_SYNCIO *sio)
Definition: syncio.c:224
GWEN_SYNCIO_DISCONNECT_FN GWEN_SyncIo_SetDisconnectFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_DISCONNECT_FN fn)
Definition: syncio.c:265
void GWEN_SyncIo_SubFlags(GWEN_SYNCIO *sio, uint32_t fl)
Definition: syncio.c:188
GWEN_SYNCIO_WRITE_FN GWEN_SyncIo_SetWriteFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_WRITE_FN fn)
Definition: syncio.c:304
int GWEN_SyncIo_WriteForced(GWEN_SYNCIO *sio, const uint8_t *buffer, uint32_t size)
Definition: syncio.c:317
GWEN_SYNCIO_STATUS GWEN_SyncIo_GetStatus(const GWEN_SYNCIO *sio)
Definition: syncio.c:197
int GWEN_SyncIo_Read(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition: syncio.c:133
GWEN_SYNCIO_CONNECT_FN GWEN_SyncIo_SetConnectFn(GWEN_SYNCIO *sio, GWEN_SYNCIO_CONNECT_FN fn)
Definition: syncio.c:252
void GWEN_SyncIo_SetStatus(GWEN_SYNCIO *sio, GWEN_SYNCIO_STATUS st)
Definition: syncio.c:206
int GWEN_SyncIo_Disconnect(GWEN_SYNCIO *sio)
Definition: syncio.c:109
#define GWEN_SYNCIO_FLAGS_PASSIVE
Definition: syncio.h:57
struct GWEN_SYNCIO GWEN_SYNCIO
Definition: syncio.h:40
@ GWEN_SyncIo_Status_Connected
Definition: syncio.h:49
@ GWEN_SyncIo_Status_Disconnected
Definition: syncio.h:48
#define GWEN_SYNCIO_FLAGS_TRANSPARENT
Definition: syncio.h:55
int GWEN_SyncIo_Http_WriteStatus(GWEN_SYNCIO *sio)
Definition: syncio_http.c:1051
int GWEN_SyncIo_Http_WriteCommand(GWEN_SYNCIO *sio)
Definition: syncio_http.c:995
int GWEN_SyncIo_Http_ReadLine(GWEN_SYNCIO *sio, GWEN_BUFFER *tbuf)
Definition: syncio_http.c:420
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbCommandOut(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1298
GWEN_SYNCIO * GWEN_SyncIo_Http_new(GWEN_SYNCIO *baseIo)
Definition: syncio_http.c:52
int GWEN_SyncIo_Http_RecvBody(GWEN_SYNCIO *sio, GWEN_BUFFER *buf)
Definition: syncio_http.c:1338
int GWEN_SyncIo_Http_ReadCommand(GWEN_SYNCIO *sio)
Definition: syncio_http.c:629
int GWEN_SyncIo_Http_WriteHeader(GWEN_SYNCIO *sio)
Definition: syncio_http.c:1106
void GWENHYWFAR_CB GWEN_SyncIo_Http_FreeData(GWEN_UNUSED void *bp, void *p)
Definition: syncio_http.c:80
int GWEN_SyncIo_Http_ParseCommand(GWEN_SYNCIO *sio, const char *buffer)
Definition: syncio_http.c:520
int GWEN_SyncIo_Http_RecvBodyToSio(GWEN_SYNCIO *sio, GWEN_SYNCIO *sout)
Definition: syncio_http.c:1483
int GWEN_SyncIo_Http_ReadChunkSize(GWEN_SYNCIO *sio)
Definition: syncio_http.c:846
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbStatusOut(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1311
int GWEN_SyncIo_Http_ReadHeader(GWEN_SYNCIO *sio)
Definition: syncio_http.c:765
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
int GWEN_SyncIo_Http_ReadStatus(GWEN_SYNCIO *sio)
Definition: syncio_http.c:578
int GWEN_SyncIo_Http_ParseHeader(GWEN_SYNCIO *sio, char *buf)
Definition: syncio_http.c:666
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbStatusIn(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1272
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbHeaderIn(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1285
int GWENHYWFAR_CB GWEN_SyncIo_Http_Write(GWEN_SYNCIO *sio, const uint8_t *buffer, uint32_t size)
Definition: syncio_http.c:312
int GWENHYWFAR_CB GWEN_SyncIo_Http_Disconnect(GWEN_SYNCIO *sio)
Definition: syncio_http.c:131
int GWENHYWFAR_CB GWEN_SyncIo_Http_Read(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition: syncio_http.c:174
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbHeaderOut(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1324
int GWEN_SyncIo_Http_WriteChunkSize(GWEN_SYNCIO *sio, uint32_t size)
Definition: syncio_http.c:1213
GWEN_DB_NODE * GWEN_SyncIo_Http_GetDbCommandIn(const GWEN_SYNCIO *sio)
Definition: syncio_http.c:1259
int GWEN_SyncIo_Http_ReadChunk(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition: syncio_http.c:896
int GWENHYWFAR_CB GWEN_SyncIo_Http_Connect(GWEN_SYNCIO *sio)
Definition: syncio_http.c:99
void GWEN_SyncIo_Http_SetReadIdle(GWEN_SYNCIO *sio)
Definition: syncio_http.c:161
void GWEN_SyncIo_Http_SetWriteIdle(GWEN_SYNCIO *sio)
Definition: syncio_http.c:1244
#define GWEN_SYNCIO_HTTP_TYPE
Definition: syncio_http.h:33
int GWEN_Text_ComparePattern(const char *w, const char *p, int sensecase)
Definition: text.c:1208
void GWEN_Text_LogString(const char *s, unsigned int l, const char *logDomain, GWEN_LOGGER_LEVEL lv)
Definition: text.c:1606