1 /***************************************************************************
2 begin : Fri Feb 15 2008
3 copyright : (C) 2019 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * Please see toplevel file COPYING for license details *
8 ***************************************************************************/
9
10
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14
15 #define DISABLE_DEBUGLOG
16
17
18 #include "httpsession_p.h"
19 #include "i18n_l.h"
20
21 #include <gwenhywfar/syncio.h>
22 #include <gwenhywfar/syncio_socket.h>
23 #include <gwenhywfar/syncio_tls.h>
24 #include <gwenhywfar/syncio_http.h>
25 #include <gwenhywfar/syncio_file.h>
26
27 #include <gwenhywfar/misc.h>
28 #include <gwenhywfar/debug.h>
29 #include <gwenhywfar/gui.h>
30 #include <gwenhywfar/text.h>
31
32 #include <assert.h>
33 #include <unistd.h>
34
35
GWEN_INHERIT_FUNCTIONS(GWEN_HTTP_SESSION)36 GWEN_INHERIT_FUNCTIONS(GWEN_HTTP_SESSION)
37
38
39
40 GWEN_HTTP_SESSION *GWEN_HttpSession_new(const char *url, const char *defaultProto, int defaultPort)
41 {
42 GWEN_HTTP_SESSION *sess;
43
44 GWEN_NEW_OBJECT(GWEN_HTTP_SESSION, sess);
45 assert(sess);
46 sess->usage=1;
47 GWEN_INHERIT_INIT(GWEN_HTTP_SESSION, sess);
48 if (url)
49 sess->url=strdup(url);
50 if (defaultProto)
51 sess->defaultProtocol=strdup(defaultProto);
52 sess->defaultPort=defaultPort;
53
54 return sess;
55 }
56
57
58
GWEN_HttpSession_fromSocketPassive(GWEN_SOCKET * sk,const char * proto,int port)59 GWEN_HTTP_SESSION *GWEN_HttpSession_fromSocketPassive(GWEN_SOCKET *sk, const char *proto, int port)
60 {
61 GWEN_HTTP_SESSION *sess;
62 GWEN_SYNCIO *baseSio;
63 GWEN_SYNCIO *sio;
64
65 GWEN_NEW_OBJECT(GWEN_HTTP_SESSION, sess);
66 assert(sess);
67 sess->usage=1;
68 GWEN_INHERIT_INIT(GWEN_HTTP_SESSION, sess);
69
70 baseSio=GWEN_SyncIo_Socket_TakeOver(sk);
71 if (baseSio==NULL) {
72 DBG_ERROR(GWEN_LOGDOMAIN, "Error on GWEN_SyncIo_Socket_TakeOver()");
73 GWEN_HttpSession_free(sess);
74 return NULL;
75 }
76
77 /* extend syncio to support the given protocol */
78 sio=GWEN_Gui_ExtendSyncIo(NULL, proto, port, baseSio);
79 if (sio==NULL) {
80 DBG_ERROR(GWEN_LOGDOMAIN, "Error on GWEN_Gui_ExtendSyncIo()");
81 GWEN_HttpSession_free(sess);
82 return NULL;
83 }
84
85 sess->syncIo=sio;
86 sess->flags|=GWEN_HTTP_SESSION_FLAGS_PASSIVE;
87
88 /* add PASSIVE flag to every syncIO in the chain */
89 while (sio) {
90 GWEN_SyncIo_AddFlags(sio, GWEN_SYNCIO_FLAGS_PASSIVE);
91 sio=GWEN_SyncIo_GetBaseIo(sio);
92 }
93
94 return sess;
95 }
96
97
98
GWEN_HttpSession_fromSyncIoPassive(GWEN_SYNCIO * sio)99 GWEN_HTTP_SESSION *GWEN_HttpSession_fromSyncIoPassive(GWEN_SYNCIO *sio)
100 {
101 GWEN_HTTP_SESSION *sess;
102
103 GWEN_NEW_OBJECT(GWEN_HTTP_SESSION, sess);
104 assert(sess);
105 sess->usage=1;
106 GWEN_INHERIT_INIT(GWEN_HTTP_SESSION, sess);
107
108 sess->syncIo=sio;
109 sess->flags|=GWEN_HTTP_SESSION_FLAGS_PASSIVE;
110
111 /* add PASSIVE flag to every syncIO in the chain */
112 while (sio) {
113 GWEN_SyncIo_AddFlags(sio, GWEN_SYNCIO_FLAGS_PASSIVE);
114 sio=GWEN_SyncIo_GetBaseIo(sio);
115 }
116
117 return sess;
118 }
119
120
121
GWEN_HttpSession_Attach(GWEN_HTTP_SESSION * sess)122 void GWEN_HttpSession_Attach(GWEN_HTTP_SESSION *sess)
123 {
124 assert(sess);
125 assert(sess->usage);
126 sess->usage++;
127 }
128
129
130
GWEN_HttpSession_free(GWEN_HTTP_SESSION * sess)131 void GWEN_HttpSession_free(GWEN_HTTP_SESSION *sess)
132 {
133 if (sess) {
134 assert(sess->usage);
135 if (sess->usage==1) {
136 GWEN_INHERIT_FINI(GWEN_HTTP_SESSION, sess);
137 GWEN_SyncIo_free(sess->syncIo);
138 free(sess->url);
139 free(sess->defaultProtocol);
140 free(sess->httpUserAgent);
141 free(sess->httpContentType);
142 GWEN_FREE_OBJECT(sess);
143 }
144 else {
145 sess->usage--;
146 }
147 }
148 }
149
150
151
GWEN_HttpSession_SetInitSyncIoFn(GWEN_HTTP_SESSION * sess,GWEN_HTTPSESSION_INITSYNCIO_FN f)152 GWEN_HTTPSESSION_INITSYNCIO_FN GWEN_HttpSession_SetInitSyncIoFn(GWEN_HTTP_SESSION *sess,
153 GWEN_HTTPSESSION_INITSYNCIO_FN f)
154 {
155 GWEN_HTTPSESSION_INITSYNCIO_FN oldFn;
156
157 oldFn=sess->initSyncIoFn;
158 sess->initSyncIoFn=f;
159 return oldFn;
160 }
161
162
163
GWEN_HttpSession_GetFlags(const GWEN_HTTP_SESSION * sess)164 uint32_t GWEN_HttpSession_GetFlags(const GWEN_HTTP_SESSION *sess)
165 {
166 assert(sess);
167 assert(sess->usage);
168
169 return sess->flags;
170 }
171
172
173
GWEN_HttpSession_SetFlags(GWEN_HTTP_SESSION * sess,uint32_t fl)174 void GWEN_HttpSession_SetFlags(GWEN_HTTP_SESSION *sess, uint32_t fl)
175 {
176 assert(sess);
177 assert(sess->usage);
178
179 sess->flags=fl;
180 }
181
182
183
GWEN_HttpSession_AddFlags(GWEN_HTTP_SESSION * sess,uint32_t fl)184 void GWEN_HttpSession_AddFlags(GWEN_HTTP_SESSION *sess, uint32_t fl)
185 {
186 assert(sess);
187 assert(sess->usage);
188
189 sess->flags|=fl;
190 }
191
192
193
GWEN_HttpSession_SubFlags(GWEN_HTTP_SESSION * sess,uint32_t fl)194 void GWEN_HttpSession_SubFlags(GWEN_HTTP_SESSION *sess, uint32_t fl)
195 {
196 assert(sess);
197 assert(sess->usage);
198
199 sess->flags&=~fl;
200 }
201
202
203
GWEN_HttpSession_GetHttpUserAgent(const GWEN_HTTP_SESSION * sess)204 const char *GWEN_HttpSession_GetHttpUserAgent(const GWEN_HTTP_SESSION *sess)
205 {
206 assert(sess);
207 assert(sess->usage);
208
209 return sess->httpUserAgent;
210 }
211
212
213
GWEN_HttpSession_SetHttpUserAgent(GWEN_HTTP_SESSION * sess,const char * s)214 void GWEN_HttpSession_SetHttpUserAgent(GWEN_HTTP_SESSION *sess, const char *s)
215 {
216 assert(sess);
217 assert(sess->usage);
218
219 free(sess->httpUserAgent);
220 if (s)
221 sess->httpUserAgent=strdup(s);
222 else
223 sess->httpUserAgent=NULL;
224 }
225
226
227
GWEN_HttpSession_GetHttpContentType(const GWEN_HTTP_SESSION * sess)228 const char *GWEN_HttpSession_GetHttpContentType(const GWEN_HTTP_SESSION *sess)
229 {
230 assert(sess);
231 assert(sess->usage);
232
233 return sess->httpContentType;
234 }
235
236
237
GWEN_HttpSession_SetHttpContentType(GWEN_HTTP_SESSION * sess,const char * s)238 void GWEN_HttpSession_SetHttpContentType(GWEN_HTTP_SESSION *sess, const char *s)
239 {
240 assert(sess);
241 assert(sess->usage);
242
243 free(sess->httpContentType);
244 if (s)
245 sess->httpContentType=strdup(s);
246 else
247 sess->httpContentType=NULL;
248 }
249
250
251
GWEN_HttpSession_GetHttpVMajor(const GWEN_HTTP_SESSION * sess)252 int GWEN_HttpSession_GetHttpVMajor(const GWEN_HTTP_SESSION *sess)
253 {
254 assert(sess);
255 assert(sess->usage);
256
257 return sess->httpVMajor;
258 }
259
260
261
GWEN_HttpSession_SetHttpVMajor(GWEN_HTTP_SESSION * sess,int i)262 void GWEN_HttpSession_SetHttpVMajor(GWEN_HTTP_SESSION *sess, int i)
263 {
264 assert(sess);
265 assert(sess->usage);
266
267 sess->httpVMajor=i;
268 }
269
270
271
GWEN_HttpSession_GetHttpVMinor(const GWEN_HTTP_SESSION * sess)272 int GWEN_HttpSession_GetHttpVMinor(const GWEN_HTTP_SESSION *sess)
273 {
274 assert(sess);
275 assert(sess->usage);
276
277 return sess->httpVMinor;
278 }
279
280
281
GWEN_HttpSession_SetHttpVMinor(GWEN_HTTP_SESSION * sess,int i)282 void GWEN_HttpSession_SetHttpVMinor(GWEN_HTTP_SESSION *sess, int i)
283 {
284 assert(sess);
285 assert(sess->usage);
286
287 sess->httpVMinor=i;
288 }
289
290
291
292
293
294
GWEN_HttpSession_Init(GWEN_HTTP_SESSION * sess)295 int GWEN_HttpSession_Init(GWEN_HTTP_SESSION *sess)
296 {
297 GWEN_SYNCIO *sioTls;
298 GWEN_DB_NODE *db;
299 int rv;
300
301 if (!(sess->flags & GWEN_HTTP_SESSION_FLAGS_PASSIVE)) { /* client mode */
302 GWEN_SYNCIO *sio;
303
304 rv=GWEN_Gui_GetSyncIo(sess->url,
305 (sess->defaultProtocol)?(sess->defaultProtocol):"http",
306 sess->defaultPort,
307 &sio);
308 if (rv<0) {
309 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
310 return rv;
311 }
312
313 if (strcasecmp(GWEN_SyncIo_GetTypeName(sio), GWEN_SYNCIO_HTTP_TYPE)!=0) {
314 DBG_ERROR(GWEN_LOGDOMAIN, "URL does not lead to a HTTP layer");
315 GWEN_SyncIo_free(sio);
316 return GWEN_ERROR_INVALID;
317 }
318
319 /* allow derived classes to modify the given GWEN_SIO */
320 rv=GWEN_HttpSession_InitSyncIo(sess, sio);
321 if (rv<0 && rv!=GWEN_ERROR_NOT_IMPLEMENTED) {
322 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
323 GWEN_SyncIo_free(sio);
324 return rv;
325 }
326 sess->syncIo=sio;
327 }
328
329 if (sess->syncIo==NULL) {
330 DBG_ERROR(GWEN_LOGDOMAIN, "No SYNCIO object, SNH!");
331 return GWEN_ERROR_INTERNAL;
332 }
333
334 /* prepare TLS layer */
335 sioTls=GWEN_SyncIo_GetBaseIoByTypeName(sess->syncIo, GWEN_SYNCIO_TLS_TYPE);
336 if (sioTls) {
337 if (!(sess->flags & GWEN_HTTP_SESSION_FLAGS_PASSIVE)) { /* client mode */
338 GWEN_SyncIo_AddFlags(sioTls,
339 GWEN_SYNCIO_TLS_FLAGS_ALLOW_V1_CA_CRT|
340 GWEN_SYNCIO_TLS_FLAGS_ADD_TRUSTED_CAS);
341 }
342 else { /* server mode */
343 }
344
345 if (sess->flags & GWEN_HTTP_SESSION_FLAGS_TLS_IGN_PREMATURE_CLOSE) {
346 /* make TLS layer ignore problem of premature connection termination */
347 GWEN_SyncIo_AddFlags(sioTls, GWEN_SYNCIO_TLS_FLAGS_IGN_PREMATURE_CLOSE);
348 }
349 }
350
351
352 /* prepare HTTP out header */
353 db=GWEN_SyncIo_Http_GetDbHeaderOut(sess->syncIo);
354 if (sess->flags & GWEN_HTTP_SESSION_FLAGS_NO_CACHE) {
355 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
356 "Pragma", "no-cache");
357 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
358 "Cache-control", "no cache");
359 }
360 if (sess->httpContentType)
361 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
362 "Content-type", sess->httpContentType);
363
364 if (sess->httpUserAgent)
365 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
366 "User-Agent", sess->httpUserAgent);
367 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Connection", "close");
368 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-length", 0);
369
370 return 0;
371 }
372
373
374
GWEN_HttpSession_Fini(GWEN_HTTP_SESSION * sess)375 int GWEN_HttpSession_Fini(GWEN_HTTP_SESSION *sess)
376 {
377 assert(sess);
378 assert(sess->usage);
379
380 if (sess->syncIo) {
381 GWEN_SyncIo_Disconnect(sess->syncIo);
382 GWEN_SyncIo_free(sess->syncIo);
383 sess->syncIo=NULL;
384 }
385
386 return 0;
387 }
388
389
390
GWEN_HttpSession_SendPacket(GWEN_HTTP_SESSION * sess,const char * httpCommand,const uint8_t * buf,uint32_t blen)391 int GWEN_HttpSession_SendPacket(GWEN_HTTP_SESSION *sess,
392 const char *httpCommand,
393 const uint8_t *buf, uint32_t blen)
394 {
395 int rv;
396
397 assert(sess);
398 assert(sess->usage);
399
400 /* first connect to server */
401 GWEN_Gui_ProgressLog(0,
402 GWEN_LoggerLevel_Debug,
403 I18N("Connecting to server..."));
404 rv=GWEN_SyncIo_Connect(sess->syncIo);
405 if (rv<0) {
406 if (rv==GWEN_ERROR_SSL) {
407 DBG_NOTICE(GWEN_LOGDOMAIN,
408 "SSL-Error connecting (%d)", rv);
409 }
410 DBG_INFO(GWEN_LOGDOMAIN, "Could not connect to server (%d)", rv);
411 GWEN_Gui_ProgressLog(0,
412 GWEN_LoggerLevel_Error,
413 I18N("Could not connect to server"));
414 GWEN_SyncIo_Disconnect(sess->syncIo);
415 return rv;
416 }
417 else {
418 GWEN_DB_NODE *db;
419
420 GWEN_Gui_ProgressLog(0,
421 GWEN_LoggerLevel_Debug,
422 I18N("Connected."));
423
424 /* set command */
425 db=GWEN_SyncIo_Http_GetDbCommandOut(sess->syncIo);
426 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
427 "command",
428 httpCommand);
429 if (sess->httpVMajor) {
430 char numbuf[32];
431
432 snprintf(numbuf, sizeof(numbuf)-1, "HTTP/%d.%d",
433 sess->httpVMajor, sess->httpVMinor);
434 numbuf[sizeof(numbuf)-1]=0;
435 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
436 "protocol",
437 numbuf);
438 }
439 else
440 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
441 "protocol",
442 "HTTP/1.0");
443
444 /* set content length */
445 db=GWEN_SyncIo_Http_GetDbHeaderOut(sess->syncIo);
446 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
447 "Content-length", blen);
448
449 GWEN_Gui_ProgressLog(0,
450 GWEN_LoggerLevel_Debug,
451 I18N("Sending message..."));
452
453 /* send request */
454 rv=GWEN_SyncIo_WriteForced(sess->syncIo, buf, blen);
455 if (rv<0) {
456 DBG_INFO(GWEN_LOGDOMAIN, "Could not send message (%d)", rv);
457 GWEN_Gui_ProgressLog2(0,
458 GWEN_LoggerLevel_Error,
459 I18N("Could not send message (%d)"),
460 rv);
461 GWEN_SyncIo_Disconnect(sess->syncIo);
462 return rv;
463 }
464
465 DBG_INFO(GWEN_LOGDOMAIN, "Message sent.");
466 GWEN_Gui_ProgressLog(0,
467 GWEN_LoggerLevel_Debug,
468 I18N("Message sent."));
469 return 0;
470 }
471 }
472
473
474
GWEN_HttpSession_SendStatus(GWEN_HTTP_SESSION * sess,int resultCode,const char * resultText,const uint8_t * buf,uint32_t blen)475 int GWEN_HttpSession_SendStatus(GWEN_HTTP_SESSION *sess,
476 int resultCode,
477 const char *resultText,
478 const uint8_t *buf, uint32_t blen)
479 {
480 int rv;
481 GWEN_DB_NODE *db;
482
483 assert(sess);
484 assert(sess->usage);
485
486 if (!(sess->flags & GWEN_HTTP_SESSION_FLAGS_PASSIVE)) { /* client mode */
487 DBG_ERROR(GWEN_LOGDOMAIN, "In client mode, cannot send status");
488 return GWEN_ERROR_INVALID;
489 }
490
491 /* set result */
492 db=GWEN_SyncIo_Http_GetDbStatusOut(sess->syncIo);
493 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "code", resultCode);
494 if (resultText && *resultText)
495 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "text", resultText);
496
497 /* set protocol */
498 if (sess->httpVMajor) {
499 char numbuf[32];
500
501 snprintf(numbuf, sizeof(numbuf)-1, "HTTP/%d.%d", sess->httpVMajor, sess->httpVMinor);
502 numbuf[sizeof(numbuf)-1]=0;
503 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", numbuf);
504 }
505 else
506 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "protocol", "HTTP/1.0");
507
508 /* set content length */
509 db=GWEN_SyncIo_Http_GetDbHeaderOut(sess->syncIo);
510 GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-length", blen);
511
512 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Debug, I18N("Sending response..."));
513
514 /* send request */
515 rv=GWEN_SyncIo_WriteForced(sess->syncIo, buf, blen);
516 if (rv<0) {
517 DBG_INFO(GWEN_LOGDOMAIN, "Could not send message (%d)", rv);
518 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Error, I18N("Could not send message (%d)"), rv);
519 GWEN_SyncIo_Disconnect(sess->syncIo);
520 return rv;
521 }
522
523 DBG_INFO(GWEN_LOGDOMAIN, "Message sent.");
524 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Debug, I18N("Message sent."));
525
526 /* disconnect */
527 GWEN_Gui_ProgressLog(0,
528 GWEN_LoggerLevel_Debug,
529 I18N("Disconnecting from server..."));
530 GWEN_SyncIo_Disconnect(sess->syncIo);
531 GWEN_Gui_ProgressLog(0,
532 GWEN_LoggerLevel_Debug,
533 I18N("Disconnected."));
534
535 return 0;
536 }
537
538
539
GWEN_HttpSession__RecvPacket(GWEN_HTTP_SESSION * sess,GWEN_BUFFER * buf)540 int GWEN_HttpSession__RecvPacket(GWEN_HTTP_SESSION *sess, GWEN_BUFFER *buf)
541 {
542 int rv;
543
544 assert(sess);
545 assert(sess->usage);
546
547 rv=GWEN_SyncIo_Http_RecvBody(sess->syncIo, buf);
548 if (rv<0) {
549 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
550 return rv;
551 }
552 else if ((rv>0 && rv<200) || rv>299) {
553 /* response is only ok for continuation (100) code */
554 if (rv==100) {
555 DBG_INFO(GWEN_LOGDOMAIN, "Continue...");
556 }
557 else {
558 GWEN_DB_NODE *dbHeaderIn;
559
560 dbHeaderIn=GWEN_SyncIo_Http_GetDbHeaderIn(sess->syncIo);
561
562 if (GWEN_Logger_GetLevel(GWEN_LOGDOMAIN)>=GWEN_LoggerLevel_Info) {
563 DBG_INFO(GWEN_LOGDOMAIN, "Detailed Error Log For Packet:");
564
565 if (dbHeaderIn) {
566 DBG_INFO(GWEN_LOGDOMAIN, "Recevied this HTTP header:");
567 GWEN_DB_Dump(dbHeaderIn, 2);
568 }
569 else {
570 DBG_INFO(GWEN_LOGDOMAIN, "-- No HTTP header recevied --");
571 }
572
573 if (GWEN_Buffer_GetUsedBytes(buf)) {
574 DBG_INFO(GWEN_LOGDOMAIN, "Recevied this body:");
575 GWEN_Text_LogString(GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf),
576 GWEN_LOGDOMAIN, GWEN_LoggerLevel_Info);
577 }
578 else {
579 DBG_INFO(GWEN_LOGDOMAIN, "-- No body recevied --");
580 }
581
582 }
583
584 if (rv==301 || rv==303 || rv==305 || rv==307) {
585 /* moved */
586 if (dbHeaderIn) {
587 const char *s;
588
589 s=GWEN_DB_GetCharValue(dbHeaderIn, "Location", 0, 0);
590 if (s) {
591 switch (rv) {
592 case 301:
593 case 303:
594 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved permanently to %s"), s);
595 break;
596 case 305:
597 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Use proxy at %s"), s);
598 break;
599 case 307:
600 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved temporarily to %s"), s);
601 break;
602 default:
603 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved to %s"), s);
604 } /* switch */
605 }
606 }
607 } /* if moved */
608 }
609 }
610
611 return rv;
612 }
613
614
615
GWEN_HttpSession_RecvPacket(GWEN_HTTP_SESSION * sess,GWEN_BUFFER * buf)616 int GWEN_HttpSession_RecvPacket(GWEN_HTTP_SESSION *sess, GWEN_BUFFER *buf)
617 {
618 int rv;
619 uint32_t pos;
620
621 /* read response */
622 pos=GWEN_Buffer_GetPos(buf);
623 for (;;) {
624 GWEN_Gui_ProgressLog(0,
625 GWEN_LoggerLevel_Debug,
626 I18N("Receiving response..."));
627 rv=GWEN_HttpSession__RecvPacket(sess, buf);
628 if (rv<0 || rv<200 || rv>299) {
629 DBG_INFO(GWEN_LOGDOMAIN,
630 "Error receiving packet (%d)", rv);
631 GWEN_SyncIo_Disconnect(sess->syncIo);
632 return rv;
633 }
634 if (rv!=100)
635 break;
636 GWEN_Gui_ProgressLog(0,
637 GWEN_LoggerLevel_Debug,
638 I18N("Received continuation response."));
639 GWEN_Buffer_Crop(buf, 0, pos);
640 }
641
642 GWEN_Gui_ProgressLog(0,
643 GWEN_LoggerLevel_Debug,
644 I18N("Response received."));
645
646 /* disconnect */
647 GWEN_Gui_ProgressLog(0,
648 GWEN_LoggerLevel_Debug,
649 I18N("Disconnecting from server..."));
650 GWEN_SyncIo_Disconnect(sess->syncIo);
651 GWEN_Gui_ProgressLog(0,
652 GWEN_LoggerLevel_Debug,
653 I18N("Disconnected."));
654 return rv;
655 }
656
657
658
GWEN_HttpSession_RecvCommand(GWEN_HTTP_SESSION * sess,GWEN_DB_NODE * dbCommandAndHeader,GWEN_BUFFER * buf)659 int GWEN_HttpSession_RecvCommand(GWEN_HTTP_SESSION *sess,
660 GWEN_DB_NODE *dbCommandAndHeader,
661 GWEN_BUFFER *buf)
662 {
663 int rv;
664 GWEN_DB_NODE *db;
665 uint32_t pos;
666
667 if (!(sess->flags & GWEN_HTTP_SESSION_FLAGS_PASSIVE)) { /* client mode */
668 DBG_ERROR(GWEN_LOGDOMAIN, "In client mode, cannot receive command.");
669 return GWEN_ERROR_INVALID;
670 }
671
672 /* read response */
673 pos=GWEN_Buffer_GetPos(buf);
674 for (;;) {
675 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Debug, I18N("Receiving command..."));
676 rv=GWEN_HttpSession__RecvPacket(sess, buf);
677 if (rv<0 || (rv>0 && rv<200) || rv>299) {
678 DBG_INFO(GWEN_LOGDOMAIN, "Error receiving packet (%d)", rv);
679 GWEN_SyncIo_Disconnect(sess->syncIo);
680 return rv;
681 }
682 if (rv!=100)
683 break;
684 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Debug, I18N("Received continuation response."));
685 GWEN_Buffer_Crop(buf, 0, pos);
686 }
687
688 GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Debug, I18N("Command received."));
689
690
691 /* copy command db */
692 db=GWEN_SyncIo_Http_GetDbCommandIn(sess->syncIo);
693 if (db) {
694 GWEN_DB_NODE *dbDest;
695
696 dbDest=GWEN_DB_GetGroup(dbCommandAndHeader, GWEN_DB_FLAGS_OVERWRITE_GROUPS, "command");
697 assert(dbDest);
698 GWEN_DB_AddGroupChildren(dbDest, db);
699 }
700
701 /* copy header db */
702 db=GWEN_SyncIo_Http_GetDbHeaderIn(sess->syncIo);
703 if (db) {
704 GWEN_DB_NODE *dbDest;
705
706 dbDest=GWEN_DB_GetGroup(dbCommandAndHeader, GWEN_DB_FLAGS_OVERWRITE_GROUPS, "header");
707 assert(dbDest);
708 GWEN_DB_AddGroupChildren(dbDest, db);
709 }
710
711 return rv;
712 }
713
714
715
GWEN_HttpSession__RecvPacketToSio(GWEN_HTTP_SESSION * sess,GWEN_SYNCIO * sio)716 int GWEN_HttpSession__RecvPacketToSio(GWEN_HTTP_SESSION *sess, GWEN_SYNCIO *sio)
717 {
718 int rv;
719
720 assert(sess);
721 assert(sess->usage);
722
723 rv=GWEN_SyncIo_Http_RecvBodyToSio(sess->syncIo, sio);
724 if (rv<0) {
725 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
726 return rv;
727 }
728 else if (rv<200 || rv>299) {
729 /* response is only ok for continuation (100) code */
730 if (rv==100) {
731 DBG_INFO(GWEN_LOGDOMAIN, "Continue...");
732 }
733 else {
734 GWEN_DB_NODE *dbHeaderIn;
735
736 dbHeaderIn=GWEN_SyncIo_Http_GetDbHeaderIn(sess->syncIo);
737
738 if (rv==301 || rv==303 || rv==305 || rv==307) {
739 /* moved */
740 if (dbHeaderIn) {
741 const char *s;
742
743 s=GWEN_DB_GetCharValue(dbHeaderIn, "Location", 0, 0);
744 if (s) {
745 switch (rv) {
746 case 301:
747 case 303:
748 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved permanently to %s"), s);
749 break;
750 case 305:
751 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Use proxy at %s"), s);
752 break;
753 case 307:
754 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved temporarily to %s"), s);
755 break;
756 default:
757 GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved to %s"), s);
758 } /* switch */
759 }
760 }
761 } /* if moved */
762 }
763 }
764
765 return rv;
766 }
767
768
769
GWEN_HttpSession_RecvPacketToFile(GWEN_HTTP_SESSION * sess,const char * fname)770 int GWEN_HttpSession_RecvPacketToFile(GWEN_HTTP_SESSION *sess, const char *fname)
771 {
772 int rv;
773
774 /* read response */
775 for (;;) {
776 GWEN_SYNCIO *sio;
777
778 sio=GWEN_SyncIo_File_new(fname, GWEN_SyncIo_File_CreationMode_CreateAlways);
779 GWEN_SyncIo_AddFlags(sio,
780 GWEN_SYNCIO_FILE_FLAGS_READ |
781 GWEN_SYNCIO_FILE_FLAGS_WRITE |
782 GWEN_SYNCIO_FILE_FLAGS_UREAD |
783 GWEN_SYNCIO_FILE_FLAGS_UWRITE |
784 GWEN_SYNCIO_FILE_FLAGS_GREAD |
785 GWEN_SYNCIO_FILE_FLAGS_GWRITE);
786 rv=GWEN_SyncIo_Connect(sio);
787 if (rv<0) {
788 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
789 GWEN_SyncIo_free(sio);
790 return rv;
791 }
792
793 GWEN_Gui_ProgressLog(0,
794 GWEN_LoggerLevel_Debug,
795 I18N("Receiving response..."));
796 rv=GWEN_HttpSession__RecvPacketToSio(sess, sio);
797 if (rv<0 || rv<200 || rv>299) {
798 DBG_INFO(GWEN_LOGDOMAIN,
799 "Error receiving packet (%d)", rv);
800 GWEN_SyncIo_Disconnect(sio);
801 GWEN_SyncIo_free(sio);
802 unlink(fname);
803 GWEN_SyncIo_Disconnect(sess->syncIo);
804 return rv;
805 }
806 if (rv!=100) {
807 int rv2;
808
809 /* flush file and close it */
810 rv2=GWEN_SyncIo_Flush(sio);
811 if (rv2<0) {
812 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
813 GWEN_SyncIo_free(sio);
814 return rv2;
815 }
816 rv2=GWEN_SyncIo_Disconnect(sio);
817 if (rv2<0) {
818 DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
819 GWEN_SyncIo_free(sio);
820 return rv2;
821 }
822 GWEN_SyncIo_free(sio);
823 break;
824 }
825 GWEN_Gui_ProgressLog(0,
826 GWEN_LoggerLevel_Debug,
827 I18N("Received continuation response."));
828 GWEN_SyncIo_Disconnect(sio);
829 GWEN_SyncIo_free(sio);
830 unlink(fname);
831 }
832
833 GWEN_Gui_ProgressLog(0,
834 GWEN_LoggerLevel_Debug,
835 I18N("Response received."));
836
837 /* disconnect */
838 GWEN_Gui_ProgressLog(0,
839 GWEN_LoggerLevel_Debug,
840 I18N("Disconnecting from server..."));
841 GWEN_SyncIo_Disconnect(sess->syncIo);
842 GWEN_Gui_ProgressLog(0,
843 GWEN_LoggerLevel_Debug,
844 I18N("Disconnected."));
845 return rv;
846 }
847
848
849
GWEN_HttpSession_ConnectionTest(GWEN_HTTP_SESSION * sess)850 int GWEN_HttpSession_ConnectionTest(GWEN_HTTP_SESSION *sess)
851 {
852 int rv;
853
854 assert(sess);
855 assert(sess->usage);
856
857 /* connect to server */
858 GWEN_Gui_ProgressLog(0,
859 GWEN_LoggerLevel_Notice,
860 I18N("Connecting to server..."));
861 rv=GWEN_SyncIo_Connect(sess->syncIo);
862 if (rv<0) {
863 if (rv==GWEN_ERROR_SSL) {
864 DBG_NOTICE(GWEN_LOGDOMAIN, "SSL-Error connecting (%d)", rv);
865 }
866 DBG_INFO(GWEN_LOGDOMAIN, "Could not connect to server (%d)", rv);
867 GWEN_Gui_ProgressLog(0,
868 GWEN_LoggerLevel_Error,
869 I18N("Could not connect to server"));
870 GWEN_SyncIo_Disconnect(sess->syncIo);
871 return rv;
872 }
873 else {
874 GWEN_Gui_ProgressLog(0,
875 GWEN_LoggerLevel_Notice,
876 I18N("Connected."));
877
878 GWEN_SyncIo_Disconnect(sess->syncIo);
879 GWEN_Gui_ProgressLog(0,
880 GWEN_LoggerLevel_Notice,
881 I18N("Disconnected."));
882 return 0;
883 }
884 }
885
886
887
GWEN_HttpSession_InitSyncIo(GWEN_HTTP_SESSION * sess,GWEN_SYNCIO * sio)888 int GWEN_HttpSession_InitSyncIo(GWEN_HTTP_SESSION *sess, GWEN_SYNCIO *sio)
889 {
890 if (sess->initSyncIoFn)
891 return sess->initSyncIoFn(sess, sio);
892 DBG_INFO(GWEN_LOGDOMAIN, "initSyncIoFn not set");
893 return GWEN_ERROR_NOT_IMPLEMENTED;
894 }
895
896
897
898
899
900
901
902