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