gwenhywfar 4.0.3
|
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