gwenhywfar 4.0.3

httpsession.c

Go to the documentation of this file.
00001 /***************************************************************************
00002     begin       : Fri Feb 15 2008
00003     copyright   : (C) 2008 by Martin Preuss
00004     email       : martin@libchipcard.de
00005 
00006  ***************************************************************************
00007  *          Please see toplevel file COPYING for license details           *
00008  ***************************************************************************/
00009 
00010 
00011 #ifdef HAVE_CONFIG_H
00012 # include <config.h>
00013 #endif
00014 
00015 #define DISABLE_DEBUGLOG
00016 
00017 
00018 #include "httpsession_p.h"
00019 #include "i18n_l.h"
00020 
00021 #include <gwenhywfar/syncio.h>
00022 #include <gwenhywfar/syncio_tls.h>
00023 #include <gwenhywfar/syncio_http.h>
00024 
00025 #include <gwenhywfar/misc.h>
00026 #include <gwenhywfar/debug.h>
00027 #include <gwenhywfar/gui.h>
00028 
00029 #include <assert.h>
00030 
00031 
00032 GWEN_INHERIT_FUNCTIONS(GWEN_HTTP_SESSION)
00033 
00034 
00035 
00036 GWEN_HTTP_SESSION *GWEN_HttpSession_new(const char *url, const char *defaultProto, int defaultPort) {
00037   GWEN_HTTP_SESSION *sess;
00038 
00039   GWEN_NEW_OBJECT(GWEN_HTTP_SESSION, sess);
00040   assert(sess);
00041   sess->usage=1;
00042   GWEN_INHERIT_INIT(GWEN_HTTP_SESSION, sess);
00043   if (url)
00044     sess->url=strdup(url);
00045   if (defaultProto)
00046     sess->defaultProtocol=strdup(defaultProto);
00047   sess->defaultPort=defaultPort;
00048 
00049   return sess;
00050 }
00051 
00052 
00053 
00054 void GWEN_HttpSession_Attach(GWEN_HTTP_SESSION *sess) {
00055   assert(sess);
00056   assert(sess->usage);
00057   sess->usage++;
00058 }
00059 
00060 
00061 
00062 void GWEN_HttpSession_free(GWEN_HTTP_SESSION *sess) {
00063   if (sess) {
00064     assert(sess->usage);
00065     if (sess->usage==1) {
00066       GWEN_INHERIT_FINI(GWEN_HTTP_SESSION, sess);
00067       GWEN_SyncIo_free(sess->syncIo);
00068       free(sess->url);
00069       free(sess->defaultProtocol);
00070       free(sess->httpUserAgent);
00071       free(sess->httpContentType);
00072       GWEN_FREE_OBJECT(sess);
00073     }
00074     else {
00075       sess->usage--;
00076     }
00077   }
00078 }
00079 
00080 
00081 
00082 uint32_t GWEN_HttpSession_GetFlags(const GWEN_HTTP_SESSION *sess) {
00083   assert(sess);
00084   assert(sess->usage);
00085 
00086   return sess->flags;
00087 }
00088 
00089 
00090 
00091 void GWEN_HttpSession_SetFlags(GWEN_HTTP_SESSION *sess, uint32_t fl) {
00092   assert(sess);
00093   assert(sess->usage);
00094 
00095   sess->flags=fl;
00096 }
00097 
00098 
00099 
00100 void GWEN_HttpSession_AddFlags(GWEN_HTTP_SESSION *sess, uint32_t fl) {
00101   assert(sess);
00102   assert(sess->usage);
00103 
00104   sess->flags|=fl;
00105 }
00106 
00107 
00108 
00109 void GWEN_HttpSession_SubFlags(GWEN_HTTP_SESSION *sess, uint32_t fl) {
00110   assert(sess);
00111   assert(sess->usage);
00112 
00113   sess->flags&=~fl;
00114 }
00115 
00116 
00117 
00118 const char *GWEN_HttpSession_GetHttpUserAgent(const GWEN_HTTP_SESSION *sess) {
00119   assert(sess);
00120   assert(sess->usage);
00121 
00122   return sess->httpUserAgent;
00123 }
00124 
00125 
00126 
00127 void GWEN_HttpSession_SetHttpUserAgent(GWEN_HTTP_SESSION *sess, const char *s) {
00128   assert(sess);
00129   assert(sess->usage);
00130 
00131   free(sess->httpUserAgent);
00132   if (s)
00133     sess->httpUserAgent=strdup(s);
00134   else
00135     sess->httpUserAgent=NULL;
00136 }
00137 
00138 
00139 
00140 const char *GWEN_HttpSession_GetHttpContentType(const GWEN_HTTP_SESSION *sess) {
00141   assert(sess);
00142   assert(sess->usage);
00143 
00144   return sess->httpContentType;
00145 }
00146 
00147 
00148 
00149 void GWEN_HttpSession_SetHttpContentType(GWEN_HTTP_SESSION *sess, const char *s) {
00150   assert(sess);
00151   assert(sess->usage);
00152 
00153   free(sess->httpContentType);
00154   if (s)
00155     sess->httpContentType=strdup(s);
00156   else
00157     sess->httpContentType=NULL;
00158 }
00159 
00160 
00161 
00162 int GWEN_HttpSession_GetHttpVMajor(const GWEN_HTTP_SESSION *sess) {
00163   assert(sess);
00164   assert(sess->usage);
00165 
00166   return sess->httpVMajor;
00167 }
00168 
00169 
00170 
00171 void GWEN_HttpSession_SetHttpVMajor(GWEN_HTTP_SESSION *sess, int i) {
00172   assert(sess);
00173   assert(sess->usage);
00174 
00175   sess->httpVMajor=i;
00176 }
00177 
00178 
00179 
00180 int GWEN_HttpSession_GetHttpVMinor(const GWEN_HTTP_SESSION *sess) {
00181   assert(sess);
00182   assert(sess->usage);
00183 
00184   return sess->httpVMinor;
00185 }
00186 
00187 
00188 
00189 void GWEN_HttpSession_SetHttpVMinor(GWEN_HTTP_SESSION *sess, int i) {
00190   assert(sess);
00191   assert(sess->usage);
00192 
00193   sess->httpVMinor=i;
00194 }
00195 
00196 
00197 
00198 
00199 
00200 
00201 int GWEN_HttpSession_Init(GWEN_HTTP_SESSION *sess) {
00202   GWEN_SYNCIO *sio;
00203   GWEN_SYNCIO *sioTls;
00204   GWEN_DB_NODE *db;
00205   int rv;
00206 
00207   rv=GWEN_Gui_GetSyncIo(sess->url,
00208                         (sess->defaultProtocol)?(sess->defaultProtocol):"http",
00209                         sess->defaultPort,
00210                         &sio);
00211   if (rv<0) {
00212     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00213     return rv;
00214   }
00215 
00216   if (strcasecmp(GWEN_SyncIo_GetTypeName(sio), GWEN_SYNCIO_HTTP_TYPE)!=0) {
00217     DBG_ERROR(GWEN_LOGDOMAIN, "URL does not lead to a HTTP layer");
00218     GWEN_SyncIo_free(sio);
00219     return GWEN_ERROR_INVALID;
00220   }
00221 
00222   /* prepare TLS layer */
00223   sioTls=GWEN_SyncIo_GetBaseIoByTypeName(sio, GWEN_SYNCIO_TLS_TYPE);
00224   if (sioTls) {
00225     GWEN_SyncIo_AddFlags(sioTls,
00226                          GWEN_SYNCIO_TLS_FLAGS_ALLOW_V1_CA_CRT|
00227                          GWEN_SYNCIO_TLS_FLAGS_ADD_TRUSTED_CAS);
00228 
00229     if (sess->flags & GWEN_HTTP_SESSION_FLAGS_FORCE_SSL3)
00230       GWEN_SyncIo_AddFlags(sioTls, GWEN_SYNCIO_TLS_FLAGS_FORCE_SSL_V3);
00231   }
00232 
00233 
00234   /* prepare HTTP out header */
00235   db=GWEN_SyncIo_Http_GetDbHeaderOut(sio);
00236   if (sess->flags & GWEN_HTTP_SESSION_FLAGS_NO_CACHE) {
00237     GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
00238                          "Pragma", "no-cache");
00239     GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
00240                          "Cache-control", "no cache");
00241   }
00242   if (sess->httpContentType)
00243     GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
00244                          "Content-type", sess->httpContentType);
00245 
00246   if (sess->httpUserAgent)
00247     GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
00248                          "User-Agent", sess->httpUserAgent);
00249   GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Connection", "close");
00250   GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-length", 0);
00251 
00252   sess->syncIo=sio;
00253 
00254   return 0;
00255 }
00256 
00257 
00258 
00259 int GWEN_HttpSession_Fini(GWEN_HTTP_SESSION *sess) {
00260   assert(sess);
00261   assert(sess->usage);
00262 
00263   if (sess->syncIo) {
00264     GWEN_SyncIo_Disconnect(sess->syncIo);
00265     GWEN_SyncIo_free(sess->syncIo);
00266     sess->syncIo=NULL;
00267   }
00268 
00269   return 0;
00270 }
00271 
00272 
00273 
00274 int GWEN_HttpSession_SendPacket(GWEN_HTTP_SESSION *sess,
00275                                 const char *httpCommand,
00276                                 const uint8_t *buf, uint32_t blen) {
00277   int rv;
00278 
00279   assert(sess);
00280   assert(sess->usage);
00281 
00282   /* first connect to server */
00283   GWEN_Gui_ProgressLog(0,
00284                        GWEN_LoggerLevel_Notice,
00285                        I18N("Connecting to server..."));
00286   rv=GWEN_SyncIo_Connect(sess->syncIo);
00287   if (rv==GWEN_ERROR_SSL) {
00288     GWEN_SYNCIO *sioTls;
00289 
00290     /* try again with alternated SSLv3 flag */
00291     DBG_NOTICE(GWEN_LOGDOMAIN,
00292                "SSL-Error connecting (%d), retrying", rv);
00293     GWEN_SyncIo_Disconnect(sess->syncIo);
00294 
00295     sioTls=GWEN_SyncIo_GetBaseIoByTypeName(sess->syncIo, GWEN_SYNCIO_TLS_TYPE);
00296     if (sioTls) {
00297       if (sess->flags & GWEN_HTTP_SESSION_FLAGS_FORCE_SSL3) {
00298         DBG_INFO(GWEN_LOGDOMAIN, "Retrying to connect (non-SSLv3)");
00299         GWEN_Gui_ProgressLog(0,
00300                              GWEN_LoggerLevel_Info,
00301                              I18N("Retrying to connect (non-SSLv3)"));
00302         GWEN_SyncIo_SubFlags(sioTls, GWEN_SYNCIO_TLS_FLAGS_FORCE_SSL_V3);
00303         rv=GWEN_SyncIo_Connect(sess->syncIo);
00304         if (rv==0) {
00305           GWEN_HttpSession_SubFlags(sess, GWEN_HTTP_SESSION_FLAGS_FORCE_SSL3);
00306         }
00307       }
00308       else {
00309         DBG_INFO(GWEN_LOGDOMAIN, "Retrying to connect (SSLv3)");
00310         GWEN_Gui_ProgressLog(0,
00311                              GWEN_LoggerLevel_Info,
00312                              I18N("Retrying to connect (SSLv3)"));
00313         GWEN_SyncIo_AddFlags(sioTls, GWEN_SYNCIO_TLS_FLAGS_FORCE_SSL_V3);
00314         rv=GWEN_SyncIo_Connect(sess->syncIo);
00315         if (rv==0) {
00316           GWEN_HttpSession_AddFlags(sess, GWEN_HTTP_SESSION_FLAGS_FORCE_SSL3);
00317         }
00318       }
00319     }
00320   }
00321 
00322   if (rv<0) {
00323     DBG_INFO(GWEN_LOGDOMAIN, "Could not connect to server (%d)", rv);
00324     GWEN_Gui_ProgressLog(0,
00325                          GWEN_LoggerLevel_Error,
00326                          I18N("Could not connect to server"));
00327     GWEN_SyncIo_Disconnect(sess->syncIo);
00328     return rv;
00329   }
00330   else {
00331     GWEN_DB_NODE *db;
00332 
00333     GWEN_Gui_ProgressLog(0,
00334                          GWEN_LoggerLevel_Info,
00335                          I18N("Connected."));
00336 
00337     /* set command */
00338     db=GWEN_SyncIo_Http_GetDbCommandOut(sess->syncIo);
00339     GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
00340                          "command",
00341                          httpCommand);
00342     if (sess->httpVMajor) {
00343       char numbuf[32];
00344 
00345       snprintf(numbuf, sizeof(numbuf)-1, "HTTP/%d.%d",
00346                sess->httpVMajor, sess->httpVMinor);
00347       numbuf[sizeof(numbuf)-1]=0;
00348       GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
00349                            "protocol",
00350                            numbuf);
00351     }
00352     else
00353       GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
00354                            "protocol",
00355                            "HTTP/1.0");
00356 
00357     /* set content length */
00358     db=GWEN_SyncIo_Http_GetDbHeaderOut(sess->syncIo);
00359     GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS,
00360                         "Content-length", blen);
00361 
00362     GWEN_Gui_ProgressLog(0,
00363                          GWEN_LoggerLevel_Info,
00364                          I18N("Sending message..."));
00365 
00366     /* send request */
00367     rv=GWEN_SyncIo_WriteForced(sess->syncIo, buf, blen);
00368     if (rv<0) {
00369       DBG_INFO(GWEN_LOGDOMAIN, "Could not send message (%d)", rv);
00370       GWEN_Gui_ProgressLog2(0,
00371                             GWEN_LoggerLevel_Error,
00372                             I18N("Could not send message (%d)"),
00373                             rv);
00374       GWEN_SyncIo_Disconnect(sess->syncIo);
00375       return rv;
00376     }
00377 
00378     DBG_INFO(GWEN_LOGDOMAIN, "Message sent.");
00379     GWEN_Gui_ProgressLog(0,
00380                          GWEN_LoggerLevel_Info,
00381                          I18N("Message sent."));
00382     return 0;
00383   }
00384 }
00385 
00386 
00387 
00388 int GWEN_HttpSession__RecvPacket(GWEN_HTTP_SESSION *sess, GWEN_BUFFER *buf) {
00389   int rv;
00390 
00391   assert(sess);
00392   assert(sess->usage);
00393 
00394   rv=GWEN_SyncIo_Http_RecvBody(sess->syncIo, buf);
00395   if (rv<0) {
00396     DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
00397     return rv;
00398   }
00399   else if (rv<200 || rv>299) {
00400     /* response is only ok for continuation (100) code */
00401     if (rv==100) {
00402       DBG_INFO(GWEN_LOGDOMAIN, "Continue...");
00403     }
00404     else {
00405       GWEN_DB_NODE *dbHeaderIn;
00406 
00407       dbHeaderIn=GWEN_SyncIo_Http_GetDbHeaderIn(sess->syncIo);
00408 
00409       if (rv==301 || rv==303 || rv==305 || rv==307) {
00410         /* moved */
00411         if (dbHeaderIn) {
00412           const char *s;
00413 
00414           s=GWEN_DB_GetCharValue(dbHeaderIn, "Location", 0, 0);
00415           if (s) {
00416             switch(rv) {
00417             case 301:
00418             case 303:
00419               GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved permanently to %s"), s);
00420               break;
00421             case 305:
00422               GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Use proxy at %s"), s);
00423               break;
00424             case 307:
00425               GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved temporarily to %s"), s);
00426               break;
00427             default:
00428               GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Warning, I18N("HTTP: Moved to %s"), s);
00429             } /* switch */
00430           }
00431         }
00432       } /* if moved */
00433     }
00434   }
00435 
00436   return rv;
00437 }
00438 
00439 
00440 
00441 int GWEN_HttpSession_RecvPacket(GWEN_HTTP_SESSION *sess, GWEN_BUFFER *buf) {
00442   int rv;
00443   uint32_t pos;
00444 
00445   /* read response */
00446   pos=GWEN_Buffer_GetPos(buf);
00447   for (;;) {
00448     GWEN_Gui_ProgressLog(0,
00449                          GWEN_LoggerLevel_Info,
00450                          I18N("Waiting for response..."));
00451     rv=GWEN_HttpSession__RecvPacket(sess, buf);
00452     if (rv<0 || rv<200 || rv>299) {
00453       DBG_INFO(GWEN_LOGDOMAIN,
00454                "Error receiving packet (%d)", rv);
00455       GWEN_SyncIo_Disconnect(sess->syncIo);
00456       return rv;
00457     }
00458     if (rv!=100)
00459       break;
00460     GWEN_Gui_ProgressLog(0,
00461                          GWEN_LoggerLevel_Info,
00462                          I18N("Received continuation response."));
00463     GWEN_Buffer_Crop(buf, 0, pos);
00464   }
00465 
00466   GWEN_Gui_ProgressLog(0,
00467                        GWEN_LoggerLevel_Info,
00468                        I18N("Response received."));
00469 
00470   /* disconnect */
00471   GWEN_Gui_ProgressLog(0,
00472                        GWEN_LoggerLevel_Info,
00473                        I18N("Disconnecting from server..."));
00474   GWEN_SyncIo_Disconnect(sess->syncIo);
00475   GWEN_Gui_ProgressLog(0,
00476                        GWEN_LoggerLevel_Info,
00477                        I18N("Disconnected."));
00478   return rv;
00479 }
00480 
00481 
00482 
00483 int GWEN_HttpSession_ConnectionTest(GWEN_HTTP_SESSION *sess) {
00484   int rv;
00485 
00486   assert(sess);
00487   assert(sess->usage);
00488 
00489   /* first connect to server */
00490   GWEN_Gui_ProgressLog(0,
00491                        GWEN_LoggerLevel_Notice,
00492                        I18N("Connecting to server..."));
00493   rv=GWEN_SyncIo_Connect(sess->syncIo);
00494   if (rv==GWEN_ERROR_SSL) {
00495     GWEN_SYNCIO *sioTls;
00496 
00497     /* try again with alternated SSLv3 flag */
00498     DBG_NOTICE(GWEN_LOGDOMAIN,
00499                "SSL-Error connecting (%d), retrying", rv);
00500     GWEN_SyncIo_Disconnect(sess->syncIo);
00501 
00502     sioTls=GWEN_SyncIo_GetBaseIoByTypeName(sess->syncIo, GWEN_SYNCIO_TLS_TYPE);
00503     if (sioTls) {
00504       if (sess->flags & GWEN_HTTP_SESSION_FLAGS_FORCE_SSL3) {
00505         DBG_INFO(GWEN_LOGDOMAIN, "Retrying to connect (non-SSLv3)");
00506         GWEN_Gui_ProgressLog(0,
00507                              GWEN_LoggerLevel_Info,
00508                              I18N("Retrying to connect (non-SSLv3)"));
00509         GWEN_SyncIo_SubFlags(sioTls, GWEN_SYNCIO_TLS_FLAGS_FORCE_SSL_V3);
00510         rv=GWEN_SyncIo_Connect(sess->syncIo);
00511         if (rv==0) {
00512           GWEN_HttpSession_SubFlags(sess, GWEN_HTTP_SESSION_FLAGS_FORCE_SSL3);
00513         }
00514       }
00515       else {
00516         DBG_INFO(GWEN_LOGDOMAIN, "Retrying to connect (SSLv3)");
00517         GWEN_Gui_ProgressLog(0,
00518                              GWEN_LoggerLevel_Info,
00519                              I18N("Retrying to connect (SSLv3)"));
00520         GWEN_SyncIo_AddFlags(sioTls, GWEN_SYNCIO_TLS_FLAGS_FORCE_SSL_V3);
00521         rv=GWEN_SyncIo_Connect(sess->syncIo);
00522         if (rv==0) {
00523           GWEN_HttpSession_AddFlags(sess, GWEN_HTTP_SESSION_FLAGS_FORCE_SSL3);
00524         }
00525       }
00526     }
00527   }
00528 
00529   if (rv<0) {
00530     DBG_INFO(GWEN_LOGDOMAIN, "Could not connect to server (%d)", rv);
00531     GWEN_Gui_ProgressLog(0,
00532                          GWEN_LoggerLevel_Error,
00533                          I18N("Could not connect to server"));
00534     GWEN_SyncIo_Disconnect(sess->syncIo);
00535     return rv;
00536   }
00537   else {
00538     GWEN_Gui_ProgressLog(0,
00539                          GWEN_LoggerLevel_Info,
00540                          I18N("Connected."));
00541 
00542     GWEN_SyncIo_Disconnect(sess->syncIo);
00543     GWEN_Gui_ProgressLog(0,
00544                          GWEN_LoggerLevel_Info,
00545                          I18N("Disconnected."));
00546     return 0;
00547   }
00548 }
00549 
00550 
00551 
00552