gwenhywfar  4.3.3
httpsession.c
Go to the documentation of this file.
1 /***************************************************************************
2  begin : Fri Feb 15 2008
3  copyright : (C) 2008-2011 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_tls.h>
23 #include <gwenhywfar/syncio_http.h>
24 #include <gwenhywfar/syncio_file.h>
25 
26 #include <gwenhywfar/misc.h>
27 #include <gwenhywfar/debug.h>
28 #include <gwenhywfar/gui.h>
29 
30 #include <assert.h>
31 #include <unistd.h>
32 
33 
35 
36 
37 
38 GWEN_HTTP_SESSION *GWEN_HttpSession_new(const char *url, const char *defaultProto, int defaultPort) {
39  GWEN_HTTP_SESSION *sess;
40 
42  assert(sess);
43  sess->usage=1;
45  if (url)
46  sess->url=strdup(url);
47  if (defaultProto)
48  sess->defaultProtocol=strdup(defaultProto);
49  sess->defaultPort=defaultPort;
50 
51  return sess;
52 }
53 
54 
55 
57  assert(sess);
58  assert(sess->usage);
59  sess->usage++;
60 }
61 
62 
63 
65  if (sess) {
66  assert(sess->usage);
67  if (sess->usage==1) {
69  GWEN_SyncIo_free(sess->syncIo);
70  free(sess->url);
71  free(sess->defaultProtocol);
72  free(sess->httpUserAgent);
73  free(sess->httpContentType);
74  GWEN_FREE_OBJECT(sess);
75  }
76  else {
77  sess->usage--;
78  }
79  }
80 }
81 
82 
83 
85  assert(sess);
86  assert(sess->usage);
87 
88  return sess->flags;
89 }
90 
91 
92 
93 void GWEN_HttpSession_SetFlags(GWEN_HTTP_SESSION *sess, uint32_t fl) {
94  assert(sess);
95  assert(sess->usage);
96 
97  sess->flags=fl;
98 }
99 
100 
101 
103  assert(sess);
104  assert(sess->usage);
105 
106  sess->flags|=fl;
107 }
108 
109 
110 
112  assert(sess);
113  assert(sess->usage);
114 
115  sess->flags&=~fl;
116 }
117 
118 
119 
121  assert(sess);
122  assert(sess->usage);
123 
124  return sess->httpUserAgent;
125 }
126 
127 
128 
130  assert(sess);
131  assert(sess->usage);
132 
133  free(sess->httpUserAgent);
134  if (s)
135  sess->httpUserAgent=strdup(s);
136  else
137  sess->httpUserAgent=NULL;
138 }
139 
140 
141 
143  assert(sess);
144  assert(sess->usage);
145 
146  return sess->httpContentType;
147 }
148 
149 
150 
152  assert(sess);
153  assert(sess->usage);
154 
155  free(sess->httpContentType);
156  if (s)
157  sess->httpContentType=strdup(s);
158  else
159  sess->httpContentType=NULL;
160 }
161 
162 
163 
165  assert(sess);
166  assert(sess->usage);
167 
168  return sess->httpVMajor;
169 }
170 
171 
172 
174  assert(sess);
175  assert(sess->usage);
176 
177  sess->httpVMajor=i;
178 }
179 
180 
181 
183  assert(sess);
184  assert(sess->usage);
185 
186  return sess->httpVMinor;
187 }
188 
189 
190 
192  assert(sess);
193  assert(sess->usage);
194 
195  sess->httpVMinor=i;
196 }
197 
198 
199 
200 
201 
202 
204  GWEN_SYNCIO *sio;
205  GWEN_SYNCIO *sioTls;
206  GWEN_DB_NODE *db;
207  int rv;
208 
209  rv=GWEN_Gui_GetSyncIo(sess->url,
210  (sess->defaultProtocol)?(sess->defaultProtocol):"http",
211  sess->defaultPort,
212  &sio);
213  if (rv<0) {
214  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
215  return rv;
216  }
217 
218  if (strcasecmp(GWEN_SyncIo_GetTypeName(sio), GWEN_SYNCIO_HTTP_TYPE)!=0) {
219  DBG_ERROR(GWEN_LOGDOMAIN, "URL does not lead to a HTTP layer");
220  GWEN_SyncIo_free(sio);
221  return GWEN_ERROR_INVALID;
222  }
223 
224  /* prepare TLS layer */
226  if (sioTls) {
227  GWEN_SyncIo_AddFlags(sioTls,
230 
231  if (sess->flags & GWEN_HTTP_SESSION_FLAGS_FORCE_SSL3)
233  }
234 
235 
236  /* prepare HTTP out header */
238  if (sess->flags & GWEN_HTTP_SESSION_FLAGS_NO_CACHE) {
240  "Pragma", "no-cache");
242  "Cache-control", "no cache");
243  }
244  if (sess->httpContentType)
246  "Content-type", sess->httpContentType);
247 
248  if (sess->httpUserAgent)
250  "User-Agent", sess->httpUserAgent);
251  GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Connection", "close");
252  GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-length", 0);
253 
254  sess->syncIo=sio;
255 
256  return 0;
257 }
258 
259 
260 
262  assert(sess);
263  assert(sess->usage);
264 
265  if (sess->syncIo) {
266  GWEN_SyncIo_Disconnect(sess->syncIo);
267  GWEN_SyncIo_free(sess->syncIo);
268  sess->syncIo=NULL;
269  }
270 
271  return 0;
272 }
273 
274 
275 
277  const char *httpCommand,
278  const uint8_t *buf, uint32_t blen) {
279  int rv;
280 
281  assert(sess);
282  assert(sess->usage);
283 
284  /* first connect to server */
287  I18N("Connecting to server..."));
288  rv=GWEN_SyncIo_Connect(sess->syncIo);
289  if (rv==GWEN_ERROR_SSL) {
290  GWEN_SYNCIO *sioTls;
291 
292  /* try again with alternated SSLv3 flag */
294  "SSL-Error connecting (%d), retrying", rv);
295  GWEN_SyncIo_Disconnect(sess->syncIo);
296 
298  if (sioTls) {
299  if (sess->flags & GWEN_HTTP_SESSION_FLAGS_FORCE_SSL3) {
300  DBG_INFO(GWEN_LOGDOMAIN, "Retrying to connect (non-SSLv3)");
303  I18N("Retrying to connect (non-SSLv3)"));
305  rv=GWEN_SyncIo_Connect(sess->syncIo);
306  if (rv==0) {
308  }
309  }
310  else {
311  DBG_INFO(GWEN_LOGDOMAIN, "Retrying to connect (SSLv3)");
314  I18N("Retrying to connect (SSLv3)"));
316  rv=GWEN_SyncIo_Connect(sess->syncIo);
317  if (rv==0) {
319  }
320  }
321  }
322  }
323 
324  if (rv<0) {
325  DBG_INFO(GWEN_LOGDOMAIN, "Could not connect to server (%d)", rv);
328  I18N("Could not connect to server"));
329  GWEN_SyncIo_Disconnect(sess->syncIo);
330  return rv;
331  }
332  else {
333  GWEN_DB_NODE *db;
334 
337  I18N("Connected."));
338 
339  /* set command */
340  db=GWEN_SyncIo_Http_GetDbCommandOut(sess->syncIo);
342  "command",
343  httpCommand);
344  if (sess->httpVMajor) {
345  char numbuf[32];
346 
347  snprintf(numbuf, sizeof(numbuf)-1, "HTTP/%d.%d",
348  sess->httpVMajor, sess->httpVMinor);
349  numbuf[sizeof(numbuf)-1]=0;
351  "protocol",
352  numbuf);
353  }
354  else
356  "protocol",
357  "HTTP/1.0");
358 
359  /* set content length */
360  db=GWEN_SyncIo_Http_GetDbHeaderOut(sess->syncIo);
362  "Content-length", blen);
363 
366  I18N("Sending message..."));
367 
368  /* send request */
369  rv=GWEN_SyncIo_WriteForced(sess->syncIo, buf, blen);
370  if (rv<0) {
371  DBG_INFO(GWEN_LOGDOMAIN, "Could not send message (%d)", rv);
374  I18N("Could not send message (%d)"),
375  rv);
376  GWEN_SyncIo_Disconnect(sess->syncIo);
377  return rv;
378  }
379 
380  DBG_INFO(GWEN_LOGDOMAIN, "Message sent.");
383  I18N("Message sent."));
384  return 0;
385  }
386 }
387 
388 
389 
391  int rv;
392 
393  assert(sess);
394  assert(sess->usage);
395 
396  rv=GWEN_SyncIo_Http_RecvBody(sess->syncIo, buf);
397  if (rv<0) {
398  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
399  return rv;
400  }
401  else if (rv<200 || rv>299) {
402  /* response is only ok for continuation (100) code */
403  if (rv==100) {
404  DBG_INFO(GWEN_LOGDOMAIN, "Continue...");
405  }
406  else {
407  GWEN_DB_NODE *dbHeaderIn;
408 
409  dbHeaderIn=GWEN_SyncIo_Http_GetDbHeaderIn(sess->syncIo);
410 
411  if (rv==301 || rv==303 || rv==305 || rv==307) {
412  /* moved */
413  if (dbHeaderIn) {
414  const char *s;
415 
416  s=GWEN_DB_GetCharValue(dbHeaderIn, "Location", 0, 0);
417  if (s) {
418  switch(rv) {
419  case 301:
420  case 303:
421  GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved permanently to %s"), s);
422  break;
423  case 305:
424  GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Use proxy at %s"), s);
425  break;
426  case 307:
427  GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved temporarily to %s"), s);
428  break;
429  default:
430  GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved to %s"), s);
431  } /* switch */
432  }
433  }
434  } /* if moved */
435  }
436  }
437 
438  return rv;
439 }
440 
441 
442 
444  int rv;
445  uint32_t pos;
446 
447  /* read response */
448  pos=GWEN_Buffer_GetPos(buf);
449  for (;;) {
452  I18N("Receiving response..."));
453  rv=GWEN_HttpSession__RecvPacket(sess, buf);
454  if (rv<0 || rv<200 || rv>299) {
456  "Error receiving packet (%d)", rv);
457  GWEN_SyncIo_Disconnect(sess->syncIo);
458  return rv;
459  }
460  if (rv!=100)
461  break;
464  I18N("Received continuation response."));
465  GWEN_Buffer_Crop(buf, 0, pos);
466  }
467 
470  I18N("Response received."));
471 
472  /* disconnect */
475  I18N("Disconnecting from server..."));
476  GWEN_SyncIo_Disconnect(sess->syncIo);
479  I18N("Disconnected."));
480  return rv;
481 }
482 
483 
484 
486  int rv;
487 
488  assert(sess);
489  assert(sess->usage);
490 
491  rv=GWEN_SyncIo_Http_RecvBodyToSio(sess->syncIo, sio);
492  if (rv<0) {
493  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
494  return rv;
495  }
496  else if (rv<200 || rv>299) {
497  /* response is only ok for continuation (100) code */
498  if (rv==100) {
499  DBG_INFO(GWEN_LOGDOMAIN, "Continue...");
500  }
501  else {
502  GWEN_DB_NODE *dbHeaderIn;
503 
504  dbHeaderIn=GWEN_SyncIo_Http_GetDbHeaderIn(sess->syncIo);
505 
506  if (rv==301 || rv==303 || rv==305 || rv==307) {
507  /* moved */
508  if (dbHeaderIn) {
509  const char *s;
510 
511  s=GWEN_DB_GetCharValue(dbHeaderIn, "Location", 0, 0);
512  if (s) {
513  switch(rv) {
514  case 301:
515  case 303:
516  GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved permanently to %s"), s);
517  break;
518  case 305:
519  GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Use proxy at %s"), s);
520  break;
521  case 307:
522  GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved temporarily to %s"), s);
523  break;
524  default:
525  GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved to %s"), s);
526  } /* switch */
527  }
528  }
529  } /* if moved */
530  }
531  }
532 
533  return rv;
534 }
535 
536 
537 
539  int rv;
540 
541  /* read response */
542  for (;;) {
543  GWEN_SYNCIO *sio;
544 
553  rv=GWEN_SyncIo_Connect(sio);
554  if (rv<0) {
555  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
556  GWEN_SyncIo_free(sio);
557  return rv;
558  }
559 
562  I18N("Receiving response..."));
563  rv=GWEN_HttpSession__RecvPacketToSio(sess, sio);
564  if (rv<0 || rv<200 || rv>299) {
566  "Error receiving packet (%d)", rv);
568  GWEN_SyncIo_free(sio);
569  unlink(fname);
570  GWEN_SyncIo_Disconnect(sess->syncIo);
571  return rv;
572  }
573  if (rv!=100) {
574  int rv2;
575 
576  /* flush file and close it */
577  rv2=GWEN_SyncIo_Flush(sio);
578  if (rv2<0) {
579  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
580  GWEN_SyncIo_free(sio);
581  return rv2;
582  }
583  rv2=GWEN_SyncIo_Disconnect(sio);
584  if (rv2<0) {
585  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv2);
586  GWEN_SyncIo_free(sio);
587  return rv2;
588  }
589  GWEN_SyncIo_free(sio);
590  break;
591  }
594  I18N("Received continuation response."));
596  GWEN_SyncIo_free(sio);
597  unlink(fname);
598  }
599 
602  I18N("Response received."));
603 
604  /* disconnect */
607  I18N("Disconnecting from server..."));
608  GWEN_SyncIo_Disconnect(sess->syncIo);
611  I18N("Disconnected."));
612  return rv;
613 }
614 
615 
616 
618  int rv;
619 
620  assert(sess);
621  assert(sess->usage);
622 
623  /* first connect to server */
626  I18N("Connecting to server..."));
627  rv=GWEN_SyncIo_Connect(sess->syncIo);
628  if (rv==GWEN_ERROR_SSL) {
629  GWEN_SYNCIO *sioTls;
630 
631  /* try again with alternated SSLv3 flag */
633  "SSL-Error connecting (%d), retrying", rv);
634  GWEN_SyncIo_Disconnect(sess->syncIo);
635 
637  if (sioTls) {
638  if (sess->flags & GWEN_HTTP_SESSION_FLAGS_FORCE_SSL3) {
639  DBG_INFO(GWEN_LOGDOMAIN, "Retrying to connect (non-SSLv3)");
642  I18N("Retrying to connect (non-SSLv3)"));
644  rv=GWEN_SyncIo_Connect(sess->syncIo);
645  if (rv==0) {
647  }
648  }
649  else {
650  DBG_INFO(GWEN_LOGDOMAIN, "Retrying to connect (SSLv3)");
653  I18N("Retrying to connect (SSLv3)"));
655  rv=GWEN_SyncIo_Connect(sess->syncIo);
656  if (rv==0) {
658  }
659  }
660  }
661  }
662 
663  if (rv<0) {
664  DBG_INFO(GWEN_LOGDOMAIN, "Could not connect to server (%d)", rv);
667  I18N("Could not connect to server"));
668  GWEN_SyncIo_Disconnect(sess->syncIo);
669  return rv;
670  }
671  else {
674  I18N("Connected."));
675 
676  GWEN_SyncIo_Disconnect(sess->syncIo);
679  I18N("Disconnected."));
680  return 0;
681  }
682 }
683 
684 
685 
686