diff options
Diffstat (limited to 'src/htslib.c')
-rw-r--r-- | src/htslib.c | 1319 |
1 files changed, 913 insertions, 406 deletions
diff --git a/src/htslib.c b/src/htslib.c index e4e6006..3954f9c 100644 --- a/src/htslib.c +++ b/src/htslib.c @@ -50,8 +50,16 @@ Please visit our Website: http://www.httrack.com #if HTS_WIN #include <direct.h> #else +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#endif #include <stdlib.h> #include <string.h> #include <time.h> @@ -61,11 +69,7 @@ Please visit our Website: http://www.httrack.com #if HTS_WIN #include <sys/utime.h> #else -#if HTS_PLATFORM!=3 #include <utime.h> -#else -#include <utime.h> -#endif #endif /* END specific definitions */ @@ -95,7 +99,7 @@ int IPV6_resolver = 0; /* détection complémentaire */ -const char hts_detect[][32] = { +const char* hts_detect[] = { "archive", "background", "data", // OBJECT @@ -112,13 +116,13 @@ const char hts_detect[][32] = { }; /* détecter début */ -const char hts_detectbeg[][32] = { +const char* hts_detectbeg[] = { "hotspot", /* hotspot1=..,hotspot2=.. */ "" }; /* ne pas détcter de liens dedans */ -const char hts_nodetect[][32] = { +const char* hts_nodetect[] = { "accept-charset", "accesskey", "action", @@ -160,7 +164,7 @@ const char hts_nodetect[][32] = { /* détection de mini-code javascript */ /* ALSO USED: detection based on the name: onXXX="<tag>" where XXX starts with upper case letter */ -const char hts_detect_js[][32] = { +const char* hts_detect_js[] = { "onAbort", "onBlur", "onChange", @@ -184,30 +188,42 @@ const char hts_detect_js[][32] = { "onSelect", "onSubmit", "onUnload", + "style", /* hack for CSS code data */ + "" +}; + +const char* hts_main_mime[] = { + "application", + "audio", + "image", + "message", + "multipart", + "text", + "video", "" }; /* détection "...URL=<url>" */ -const char hts_detectURL[][32] = { +const char* hts_detectURL[] = { "content", "" }; /* tags où l'URL doit être réécrite mais non capturée */ -const char hts_detectandleave[][32] = { +const char* hts_detectandleave[] = { "action", "" }; -/* ne pas renommer les types renvoyés (couvent types inconnus) */ -const char hts_mime_keep[][32] = { +/* ne pas renommer les types renvoyés (souvent types inconnus) */ +const char* hts_mime_keep[] = { "application/octet-stream", "text/plain", "" }; /* pas de type mime connu, mais extension connue */ -const char hts_ext_dynamic[][32] = { +const char* hts_ext_dynamic[] = { "php3", "php", "php4", @@ -218,11 +234,14 @@ const char hts_ext_dynamic[][32] = { "pl", /*"exe",*/ "cfm", + "nsf", /* lotus */ "" }; -/* types MIME */ -const char hts_mime[][2][32] = { +/* types MIME + note: application/octet-stream should not be used here +*/ +const char* hts_mime[][2] = { {"application/acad","dwg"}, {"application/arj","arj"}, {"application/clariscad","ccad"}, @@ -386,24 +405,167 @@ const char hts_mime[][2][32] = { {"x-conference/x-cooltalk","ice"}, /*{"application/x-httpd-cgi","cgi"},*/ {"x-world/x-vrml","wrl"}, - + + /* More from w3schools.com */ + { "application/envoy", "evy" }, + { "application/fractals", "fif" }, + { "application/futuresplash", "spl" }, + { "application/hta", "hta" }, + { "application/internet-property-stream", "acx" }, + { "application/msword", "dot" }, + { "application/olescript", "axs" }, + { "application/pics-rules", "prf" }, + { "application/pkcs10", "p10" }, + { "application/pkix-crl", "crl" }, + { "application/set-payment-initiation", "setpay" }, + { "application/set-registration-initiation", "setreg" }, + { "application/vnd.ms-excel", "xla" }, + { "application/vnd.ms-excel", "xlc" }, + { "application/vnd.ms-excel", "xlm" }, + { "application/vnd.ms-excel", "xls" }, + { "application/vnd.ms-excel", "xlt" }, + { "application/vnd.ms-excel", "xlw" }, + { "application/vnd.ms-pkicertstore", "sst" }, + { "application/vnd.ms-pkiseccat", "cat" }, + { "application/vnd.ms-powerpoint", "pot" }, + { "application/vnd.ms-powerpoint", "pps" }, + { "application/vnd.ms-powerpoint", "ppt" }, + { "application/vnd.ms-project", "mpp" }, + { "application/vnd.ms-works", "wcm" }, + { "application/vnd.ms-works", "wdb" }, + { "application/vnd.ms-works", "wks" }, + { "application/vnd.ms-works", "wps" }, + { "application/x-compress", "z" }, + { "application/x-compressed", "tgz" }, + { "application/x-internet-signup", "ins" }, + { "application/x-internet-signup", "isp" }, + { "application/x-iphone", "iii" }, + { "application/x-javascript", "js" }, + { "application/x-msaccess", "mdb" }, + { "application/x-mscardfile", "crd" }, + { "application/x-msclip", "clp" }, + { "application/x-msmediaview", "m13" }, + { "application/x-msmediaview", "m14" }, + { "application/x-msmediaview", "mvb" }, + { "application/x-msmetafile", "wmf" }, + { "application/x-msmoney", "mny" }, + { "application/x-mspublisher", "pub" }, + { "application/x-msschedule", "scd" }, + { "application/x-msterminal", "trm" }, + { "application/x-perfmon", "pma" }, + { "application/x-perfmon", "pmc" }, + { "application/x-perfmon", "pml" }, + { "application/x-perfmon", "pmr" }, + { "application/x-perfmon", "pmw" }, + { "application/x-pkcs12", "p12" }, + { "application/x-pkcs12", "pfx" }, + { "application/x-pkcs7-certificates", "p7b" }, + { "application/x-pkcs7-certificates", "spc" }, + { "application/x-pkcs7-certreqresp", "p7r" }, + { "application/x-pkcs7-mime", "p7c" }, + { "application/x-pkcs7-mime", "p7m" }, + { "application/x-pkcs7-signature", "p7s" }, + { "application/x-troff-me", "me" }, + { "application/x-x509-ca-cert", "cer" }, + { "application/x-x509-ca-cert", "crt" }, + { "application/x-x509-ca-cert", "der" }, + { "application/ynd.ms-pkipko", "pko" }, + { "audio/mid", "mid" }, + { "audio/mid", "rmi" }, + { "audio/mpeg", "mp3" }, + { "audio/x-mpegurl", "m3u" }, + { "image/bmp", "bmp" }, + { "image/cis-cod", "cod" }, + { "image/pipeg", "jfif" }, + { "image/x-cmx", "cmx" }, + { "image/x-icon", "ico" }, + { "image/x-portable-bitmap", "pbm" }, + { "message/rfc822", "mht" }, + { "message/rfc822", "mhtml" }, + { "message/rfc822", "nws" }, + { "text/css", "css" }, + { "text/h323", "323" }, + { "text/html", "stm" }, + { "text/iuls", "uls" }, + { "text/plain", "bas" }, + { "text/scriptlet", "sct" }, + { "text/webviewhtml", "htt" }, + { "text/x-component", "htc" }, + { "text/x-vcard", "vcf" }, + { "video/mpeg", "mp2" }, + { "video/mpeg", "mpa" }, + { "video/mpeg", "mpv2" }, + { "video/x-la-asf", "lsf" }, + { "video/x-la-asf", "lsx" }, + { "video/x-ms-asf", "asf" }, + { "video/x-ms-asf", "asr" }, + { "video/x-ms-asf", "asx" }, + { "x-world/x-vrml", "flr" }, + { "x-world/x-vrml", "vrml" }, + { "x-world/x-vrml", "wrz" }, + { "x-world/x-vrml", "xaf" }, + { "x-world/x-vrml", "xof" }, + + /* Various */ + { "application/ogg", "ogg" }, + {"*","class"}, {"",""}}; // Reserved (RFC2396) -#define CHAR_RESERVED(c) ( strchr(";/?:@&=+$,",(unsigned char)(c)) != 0 ) +#define CIS(c,ch) ( ((unsigned char)(c)) == (ch) ) +#define CHAR_RESERVED(c) ( CIS(c,';') \ + || CIS(c,'/') \ + || CIS(c,'?') \ + || CIS(c,':') \ + || CIS(c,'@') \ + || CIS(c,'&') \ + || CIS(c,'=') \ + || CIS(c,'+') \ + || CIS(c,'$') \ + || CIS(c,',') ) +//#define CHAR_RESERVED(c) ( strchr(";/?:@&=+$,",(unsigned char)(c)) != 0 ) // Delimiters (RFC2396) -#define CHAR_DELIM(c) ( strchr("<>#%\"",(unsigned char)(c)) != 0 ) +#define CHAR_DELIM(c) ( CIS(c,'<') \ + || CIS(c,'>') \ + || CIS(c,'#') \ + || CIS(c,'%') \ + || CIS(c,'\"') ) +//#define CHAR_DELIM(c) ( strchr("<>#%\"",(unsigned char)(c)) != 0 ) // Unwise (RFC2396) -#define CHAR_UNWISE(c) ( strchr("{}|\\^[]`",(unsigned char)(c)) != 0 ) +#define CHAR_UNWISE(c) ( CIS(c,'{') \ + || CIS(c,'}') \ + || CIS(c,'|') \ + || CIS(c,'\\') \ + || CIS(c,'^') \ + || CIS(c,'[') \ + || CIS(c,']') \ + || CIS(c,'`') ) +//#define CHAR_UNWISE(c) ( strchr("{}|\\^[]`",(unsigned char)(c)) != 0 ) // Special (escape chars) (RFC2396 + >127 ) #define CHAR_LOW(c) ( ((unsigned char)(c) <= 31) ) #define CHAR_HIG(c) ( ((unsigned char)(c) >= 127) ) #define CHAR_SPECIAL(c) ( CHAR_LOW(c) || CHAR_HIG(c) ) // We try to avoid them and encode them instead -#define CHAR_XXAVOID(c) ( strchr(" *'\"!",(unsigned char)(c)) != 0 ) +#define CHAR_XXAVOID(c) ( CIS(c,' ') \ + || CIS(c,'*') \ + || CIS(c,'\'') \ + || CIS(c,'\"') \ + || CIS(c,'!') ) +//#define CHAR_XXAVOID(c) ( strchr(" *'\"!",(unsigned char)(c)) != 0 ) +#define CHAR_MARK(c) ( CIS(c,'-') \ + || CIS(c,'_') \ + || CIS(c,'.') \ + || CIS(c,'!') \ + || CIS(c,'~') \ + || CIS(c,'*') \ + || CIS(c,'\'') \ + || CIS(c,'(') \ + || CIS(c,')') ) +//#define CHAR_MARK(c) ( strchr("-_.!~*'()",(unsigned char)(c)) != 0 ) + // conversion éventuelle / vers antislash @@ -413,7 +575,7 @@ char* antislash(char* s) { char* a; NOSTATIC_RESERVE(buff, char, HTS_URLMAXSIZE*2); - strcpy(buff,s); + strcpybuff(buff,s); while(a=strchr(buff,'/')) *a='\\'; return buff; } @@ -442,7 +604,7 @@ htsblk httpget(char* url) { retour.size=0; retour.msg[0]='\0'; retour.statuscode=-1; - strcpy(retour.msg,"Error invalid URL"); + strcpybuff(retour.msg,"Error invalid URL"); return retour; } @@ -514,7 +676,7 @@ int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* f if (retour) { if (retour->msg) { if (!strnotempty(retour->msg)) { - strcpy(retour->msg,"Connect error"); + strcpybuff(retour->msg,"Connect error"); } } } @@ -531,8 +693,8 @@ int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* f if (!fexist(fconv(unescape_http(fil)))) if (fexist(fconv(unescape_http(fil+1)))) { char tempo[HTS_URLMAXSIZE*2]; - strcpy(tempo,fil+1); - strcpy(fil,tempo); + strcpybuff(tempo,fil+1); + strcpybuff(fil,tempo); } // Ouvrir @@ -540,9 +702,9 @@ int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* f retour->msg[0]='\0'; soc=INVALID_SOCKET; if (retour->totalsize<0) - strcpy(retour->msg,"Unable to open file"); + strcpybuff(retour->msg,"Unable to open local file"); else if (retour->totalsize==0) - strcpy(retour->msg,"File empty"); + strcpybuff(retour->msg,"File empty"); else { // Note: On passe par un FILE* (plus propre) //soc=open(fil,O_RDONLY,0); // en lecture seule! @@ -555,13 +717,13 @@ int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* f retour->soc=soc; if (soc!=INVALID_SOCKET) { retour->statuscode=200; // OK - strcpy(retour->msg,"OK"); + strcpybuff(retour->msg,"OK"); guess_httptype(retour->contenttype,fil); } else if (strnotempty(retour->msg)==0) - strcpy(retour->msg,"Unable to open file"); + strcpybuff(retour->msg,"Unable to open local file"); return soc; // renvoyer } else { // HEAD ou POST : interdit sur un local!!!! (c'est idiot!) - strcpy(retour->msg,"Unexpected Head/Post local request"); + strcpybuff(retour->msg,"Unexpected Head/Post local request"); soc=INVALID_SOCKET; // erreur retour->soc=soc; return soc; @@ -647,10 +809,10 @@ int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char buff[0]='\0'; // header Date - //strcat(buff,"Date: "); + //strcatbuff(buff,"Date: "); //time_gmt_rfc822(buff); // obtenir l'heure au format rfc822 //sendc("\n"); - //strcat(buff,buff); + //strcatbuff(buff,buff); // possibilité non documentée: >post: et >postfile: // si présence d'un tag >post: alors executer un POST @@ -686,58 +848,58 @@ int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char if (strnotempty(buff)==0) { // PAS POSTFILE // Type de requète? if ((search_tag) && (mode==0)) { - strcat(buff,"POST "); + strcatbuff(buff,"POST "); } else if (mode==0) { // GET - strcat(buff,"GET "); + strcatbuff(buff,"GET "); } else { // if (mode==1) { if (!retour->req.http11) // forcer HTTP/1.0 - strcat(buff,"GET "); // certains serveurs (cgi) buggent avec HEAD + strcatbuff(buff,"GET "); // certains serveurs (cgi) buggent avec HEAD else - strcat(buff,"HEAD "); + strcatbuff(buff,"HEAD "); } // si on gère un proxy, il faut une Absolute URI: on ajoute avant http://www.adr.dom - if (retour->req.proxy.active) { + if ( retour->req.proxy.active && (strncmp(adr,"https://", 8) != 0) ) { if (!link_has_authority(adr)) { // default http #if HDEBUG printf("Proxy Use: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port); #endif - strcat(buff,"http://"); - strcat(buff,jump_identification(adr)); + strcatbuff(buff,"http://"); + strcatbuff(buff,jump_identification(adr)); } else { // ftp:// en proxy http #if HDEBUG printf("Proxy Use for ftp: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port); #endif direct_url=1; // ne pas analyser user/pass - strcat(buff,adr); + strcatbuff(buff,adr); } } // NOM DU FICHIER // on slash doit être présent en début, sinon attention aux bad request! (400) - if (*fil!='/') strcat(buff,"/"); + if (*fil!='/') strcatbuff(buff,"/"); { char tempo[HTS_URLMAXSIZE*2]; tempo[0]='\0'; if (search_tag) - strncat(tempo,fil,(int) (search_tag - fil)); + strncatbuff(tempo,fil,(int) (search_tag - fil)); else - strcpy(tempo,fil); + strcpybuff(tempo,fil); escape_check_url(tempo); - strcat(buff,tempo); // avec échappement + strcatbuff(buff,tempo); // avec échappement } // protocole if (!retour->req.http11) { // forcer HTTP/1.0 //use_11=0; - strcat(buff," HTTP/1.0\x0d\x0a"); + strcatbuff(buff," HTTP/1.0\x0d\x0a"); } else { // Requète 1.1 //use_11=1; - strcat(buff," HTTP/1.1\x0d\x0a"); + strcatbuff(buff," HTTP/1.1\x0d\x0a"); } /* supplemental data */ - if (xsend) strcat(buff,xsend); // éventuelles autres lignes + if (xsend) strcatbuff(buff,xsend); // éventuelles autres lignes // tester proxy authentication if (retour->req.proxy.active) { @@ -748,12 +910,12 @@ int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char char user_pass[256]; autorisation[0]=user_pass[0]='\0'; // - strncat(user_pass,astart,(int) (a - astart) - 1); - strcpy(user_pass,unescape_http(user_pass)); - code64(user_pass,autorisation); - strcat(buff,"Proxy-Authorization: Basic "); - strcat(buff,autorisation); - strcat(buff,H_CRLF); + strncatbuff(user_pass,astart,(int) (a - astart) - 1); + strcpybuff(user_pass,unescape_http(user_pass)); + code64((unsigned char*)user_pass,(int)strlen(user_pass),(unsigned char*)autorisation,0); + strcatbuff(buff,"Proxy-Authorization: Basic "); + strcatbuff(buff,autorisation); + strcatbuff(buff,H_CRLF); #if HDEBUG printf("Proxy-Authenticate, %s (code: %s)\n",user_pass,autorisation); #endif @@ -772,11 +934,11 @@ int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char (strncmp(adr, "https://", 8) == 0) /* or referer AND addresses are https */ ) ) { // PAS file:// - strcat(buff,"Referer: "); - strcat(buff,"http://"); - strcat(buff,jump_identification(referer_adr)); - strcat(buff,referer_fil); - strcat(buff,H_CRLF); + strcatbuff(buff,"Referer: "); + strcatbuff(buff,"http://"); + strcatbuff(buff,jump_identification(referer_adr)); + strcatbuff(buff,referer_fil); + strcatbuff(buff,H_CRLF); } } } @@ -786,7 +948,7 @@ int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char if (search_tag) { char clen[256]; sprintf(clen,"Content-length: %d"H_CRLF,(int)(strlen(unescape_http(search_tag+strlen(POSTTOK)+1)))); - strcat(buff,clen); + strcatbuff(buff,clen); } } @@ -802,40 +964,40 @@ int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char if (b) { max_cookies--; if (!cook) { - strcat(buff,"Cookie: "); - strcat(buff,"$Version=1; "); + strcatbuff(buff,"Cookie: "); + strcatbuff(buff,"$Version=1; "); cook=1; } else - strcat(buff,"; "); - strcat(buff,cookie_get(b,5)); - strcat(buff,"="); - strcat(buff,cookie_get(b,6)); - strcat(buff,"; $Path="); - strcat(buff,cookie_get(b,2)); + strcatbuff(buff,"; "); + strcatbuff(buff,cookie_get(b,5)); + strcatbuff(buff,"="); + strcatbuff(buff,cookie_get(b,6)); + strcatbuff(buff,"; $Path="); + strcatbuff(buff,cookie_get(b,2)); b=cookie_nextfield(b); } } while( (b) && (max_cookies>0) && ((int)strlen(buff)<max_size)); if (cook) { // on a envoyé un (ou plusieurs) cookie? - strcat(buff,H_CRLF); + strcatbuff(buff,H_CRLF); #if DEBUG_COOK printf("Header:\n%s\n",buff); #endif } } - // connection close? - //if (use_11) // Si on envoie une requète 1.1, préciser qu'on ne veut pas de keep-alive!! - strcat(buff,"Connection: close"H_CRLF); - // gérer le keep-alive (garder socket) - //strcat(buff,"Connection: Keep-Alive\n"); + if (retour->req.http11 && !retour->req.nokeepalive) { + strcatbuff(buff,"Connection: Keep-Alive"H_CRLF); + } else { + strcatbuff(buff,"Connection: close"H_CRLF); + } { char* real_adr=jump_identification(adr); //if ((use_11) || (retour->user_agent_send)) { // Pour le 1.1 on utilise un Host: if (!direct_url) { // pas ftp:// par exemple //if (!retour->req.proxy.active) { - strcat(buff,"Host: "); strcat(buff,real_adr); strcat(buff,H_CRLF); + strcatbuff(buff,"Host: "); strcatbuff(buff,real_adr); strcatbuff(buff,H_CRLF); //} } //} @@ -845,26 +1007,45 @@ int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char char s[256]; // HyperTextSeeker/"HTSVERSION sprintf(s,"User-Agent: %s"H_CRLF,retour->req.user_agent); - strcat(buff,s); + strcatbuff(buff,s); // pour les serveurs difficiles - strcat(buff,"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/svg+xml, */*"H_CRLF); + strcatbuff(buff,"Accept: " + "image/png, image/jpeg, image/pjpeg, image/x-xbitmap, image/svg+xml" /* Accepted */ + ", " + "image/gif;q=0.9" /* also accepted but with lower preference */ + ", " + "*/*;q=0.1" /* also accepted but with even lower preference */ + H_CRLF); if (strnotempty(retour->req.lang_iso)) { - strcat(buff,"Accept-Language: "); strcat(buff,retour->req.lang_iso); strcat(buff,H_CRLF); + strcatbuff(buff,"Accept-Language: "); strcatbuff(buff,retour->req.lang_iso); strcatbuff(buff,H_CRLF); } - strcat(buff,"Accept-Charset: iso-8859-1, *"H_CRLF); + strcatbuff(buff,"Accept-Charset: " + "iso-8859-1" /* we prefer ISO-8859-1 */ + ", " + "iso-8859-*;q=0.9" /* or ISO-8859-* */ + ", " + "utf-8;q=0.66" /* UTF8 is also accepted */ + ", " + "*;q=0.33" /* and any other charset */ + H_CRLF); if (retour->req.http11) { #if HTS_USEZLIB - if ((!retour->req.range_used) && (!retour->req.nocompression)) - strcat(buff,"Accept-Encoding: gzip, deflate, compress, identity"H_CRLF); + //strcatbuff(buff,"Accept-Encoding: gzip, deflate, compress, identity"H_CRLF); + if (gz_is_available && (!retour->req.range_used) && (!retour->req.nocompression)) + strcatbuff(buff,"Accept-Encoding: " + "gzip" /* gzip if the preffered encoding */ + ", " + "identity;q=0.9" + H_CRLF); else - strcat(buff,"Accept-Encoding: identity"H_CRLF); /* no compression */ + strcatbuff(buff,"Accept-Encoding: identity"H_CRLF); /* no compression */ #else - strcat(buff,"Accept-Encoding: identity"H_CRLF); /* no compression */ + strcatbuff(buff,"Accept-Encoding: identity"H_CRLF); /* no compression */ #endif } } else { - strcat(buff,"Accept: */*"H_CRLF); // le minimum + strcatbuff(buff,"Accept: */*"H_CRLF); // le minimum } /* Authentification */ @@ -878,40 +1059,40 @@ int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char if (!direct_url) { // pas ftp:// par exemple char user_pass[256]; user_pass[0]='\0'; - strncat(user_pass,astart,(int) (a - astart) - 1); - strcpy(user_pass,unescape_http(user_pass)); - code64(user_pass,autorisation); + strncatbuff(user_pass,astart,(int) (a - astart) - 1); + strcpybuff(user_pass,unescape_http(user_pass)); + code64((unsigned char*)user_pass,(int)strlen(user_pass),(unsigned char*)autorisation,0); if (strcmp(fil,"/robots.txt")) /* pas robots.txt */ bauth_add(cookie,astart,fil,autorisation); } } else if ( (a=bauth_check(cookie,real_adr,fil)) ) - strcpy(autorisation,a); + strcpybuff(autorisation,a); /* On a une autorisation a donner? */ if (strnotempty(autorisation)) { - strcat(buff,"Authorization: Basic "); - strcat(buff,autorisation); - strcat(buff,H_CRLF); + strcatbuff(buff,"Authorization: Basic "); + strcatbuff(buff,autorisation); + strcatbuff(buff,H_CRLF); } } } - //strcat(buff,"Accept-Language: en\n"); - //strcat(buff,"Accept-Charset: iso-8859-1,*,utf-8\n"); + //strcatbuff(buff,"Accept-Language: en\n"); + //strcatbuff(buff,"Accept-Charset: iso-8859-1,*,utf-8\n"); // CRLF de fin d'en tête - strcat(buff,H_CRLF); + strcatbuff(buff,H_CRLF); // données complémentaires? if (search_tag) if (mode==0) // GET! - strcat(buff,unescape_http(search_tag+strlen(POSTTOK)+1)); + strcatbuff(buff,unescape_http(search_tag+strlen(POSTTOK)+1)); } #if HDEBUG #endif if (_DEBUG_HEAD) { if (ioinfo) { - fprintf(ioinfo,"request for %s%s:\r\n",jump_identification(adr),fil); + fprintf(ioinfo,"[%d] request for %s%s:\r\n",retour->debugid,jump_identification(adr),fil); fprintfio(ioinfo,buff,"<<< "); fprintf(ioinfo,"\r\n"); fflush(ioinfo); @@ -919,13 +1100,25 @@ int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char } // Fin test pas postfile // + // Callback +#if HTS_ANALYSTE + if (hts_htmlcheck_sendhead != NULL) { + int test_head=hts_htmlcheck_sendhead(buff, adr, fil, referer_adr, referer_fil, retour); + if (test_head!=1) { + deletesoc_r(retour); + strcpybuff(retour->msg,"Header refused by external wrapper"); + retour->soc=INVALID_SOCKET; + } + } +#endif + // Envoi if (sendc(retour, buff)<0) { // ERREUR, socket rompue?... //if (sendc(retour->soc,buff) != strlen(buff)) { // ERREUR, socket rompue?... deletesoc_r(retour); // fermer tout de même // et tenter de reconnecter - strcpy(retour->msg,"Broken pipe"); + strcpybuff(retour->msg,"Write error"); retour->soc=INVALID_SOCKET; } @@ -955,44 +1148,46 @@ void treatfirstline(htsblk* retour,char* rcvd) { while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++; while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++; // épurer espaces if ((strlen(a) > 1) && (strlen(a) < 64) ) // message retour - strcpy(retour->msg,a); + strcpybuff(retour->msg,a); else infostatuscode(retour->msg,retour->statuscode); // type MIME par défaut2 - strcpy(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME); + strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME); } else { // pas de code! retour->statuscode=-1; - strcpy(retour->msg,"Unknown response structure"); + strcpybuff(retour->msg,"Unknown response structure"); } } else { // euhh?? retour->statuscode=-1; - strcpy(retour->msg,"Unknown response structure"); + strcpybuff(retour->msg,"Unknown response structure"); } } else { if (*a == '<') { /* This is dirty .. */ retour->statuscode=200; - strcpy(retour->msg, "Unknown, assuming junky server"); - strcpy(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME); + retour->keep_alive=0; + strcpybuff(retour->msg, "Unknown, assuming junky server"); + strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME); } else if (strnotempty(a)) { retour->statuscode=-1; - strcpy(retour->msg,"Unknown response structure, no HTTP/ response given"); + strcpybuff(retour->msg,"Unknown (not HTTP/xx) response structure"); } else { /* This is dirty .. */ retour->statuscode=200; - strcpy(retour->msg, "Unknown, assuming junky server"); - strcpy(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME); + retour->keep_alive=0; + strcpybuff(retour->msg, "Unknown, assuming junky server"); + strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME); } } } else { // vide! /* retour->statuscode=-1; - strcpy(retour->msg,"Empty reponse or internal error"); + strcpybuff(retour->msg,"Empty reponse or internal error"); */ /* This is dirty .. */ retour->statuscode=200; - strcpy(retour->msg, "Unknown, assuming junky server"); - strcpy(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME); + strcpybuff(retour->msg, "Unknown, assuming junky server"); + strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME); } } @@ -1005,13 +1200,16 @@ void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) { printf("ok, Content-length: détecté\n"); #endif sscanf(rcvd+p,LLintP,&(retour->totalsize)); + if (retour->totalsize == 0) { + retour->empty = 1; + } } else if ((p=strfield(rcvd,"Content-Disposition:"))!=0) { - while(*(rcvd+p)==' ') p++; // sauter espaces + while(is_realspace(*(rcvd+p))) p++; // sauter espaces if ((int) strlen(rcvd+p)<250) { // pas trop long? char tmp[256]; char *a=NULL,*b=NULL; - strcpy(tmp,rcvd+p); + strcpybuff(tmp,rcvd+p); a=strstr(tmp,"filename="); if (a) { a+=strlen("filename="); @@ -1029,7 +1227,7 @@ void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) { if (b) { *b='\0'; if ((int) strlen(a) < 200) { // pas trop long? - strcpy(retour->cdispo,a); + strcpybuff(retour->cdispo,a); } } } @@ -1037,36 +1235,40 @@ void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) { } } else if ((p=strfield(rcvd,"Last-Modified:"))!=0) { - while(*(rcvd+p)==' ') p++; // sauter espaces + while(is_realspace(*(rcvd+p))) p++; // sauter espaces if ((int) strlen(rcvd+p)<64) { // pas trop long? //struct tm* tm_time=convert_time_rfc822(rcvd+p); - strcpy(retour->lastmodified,rcvd+p); + strcpybuff(retour->lastmodified,rcvd+p); } } else if ((p=strfield(rcvd,"Date:"))!=0) { if (strnotempty(retour->lastmodified)==0) { /* pas encore de last-modified */ - while(*(rcvd+p)==' ') p++; // sauter espaces + while(is_realspace(*(rcvd+p))) p++; // sauter espaces if ((int) strlen(rcvd+p)<64) { // pas trop long? //struct tm* tm_time=convert_time_rfc822(rcvd+p); - strcpy(retour->lastmodified,rcvd+p); + strcpybuff(retour->lastmodified,rcvd+p); } } } else if ((p=strfield(rcvd,"Etag:"))!=0) { /* Etag */ if (retour) { - while(*(rcvd+p)==' ') p++; // sauter espaces + while(is_realspace(*(rcvd+p))) p++; // sauter espaces if ((int) strlen(rcvd+p)<64) // pas trop long? - strcpy(retour->etag,rcvd+p); + strcpybuff(retour->etag,rcvd+p); else // erreur.. ignorer retour->etag[0]='\0'; } } - else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) { // chunk! - retour->is_chunk=1; // chunked - //retour->http11=2; // chunked + // else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) { // chunk! + else if ((p=strfield(rcvd,"Transfer-Encoding:"))!=0) { // chunk! + while(is_realspace(*(rcvd+p))) p++; // sauter espaces + if (strfield(rcvd+p,"chunked")) { + retour->is_chunk=1; // chunked + //retour->http11=2; // chunked #if HDEBUG - printf("ok, Transfer-Encoding: détecté\n"); + printf("ok, Transfer-Encoding: détecté\n"); #endif + } } else if ((p=strfield(rcvd,"Content-type:"))!=0) { if (retour) { @@ -1074,13 +1276,37 @@ void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) { // éviter les text/html; charset=foo { char* a=strchr(rcvd+p,';'); - if (a) *a='\0'; + if (a) { // extended information + *a='\0'; + a++; + while(is_space(*a)) a++; + if (strfield(a, "charset")) { + a += 7; + while(is_space(*a)) a++; + if (*a == '=') { + a++; + while(is_space(*a)) a++; + if (*a == '\"') a++; + while(is_space(*a)) a++; + if (*a) { + char* chs = a; + while(*a && !is_space(*a) && *a != '\"' && *a != ';') a++; + *a = '\0'; + if (*chs) { + if (strlen(chs) < sizeof(retour->charset) - 2) { + strcpybuff(retour->charset, chs); + } + } + } + } + } + } } sscanf(rcvd+p,"%s",tempo); - if (strlen(tempo)<64) // pas trop long!! - strcpy(retour->contenttype,tempo); + if (strlen(tempo) < sizeof(retour->contenttype) - 2) // pas trop long!! + strcpybuff(retour->contenttype,tempo); else - strcpy(retour->contenttype,"application/octet-stream-unknown"); // erreur + strcpybuff(retour->contenttype,"application/octet-stream-unknown"); // erreur } } else if ((p=strfield(rcvd,"Content-Range:"))!=0) { @@ -1091,16 +1317,63 @@ void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) { } } } - else if ((p=strfield(rcvd,"Content-Encoding:"))!=0) { - if (retour) { - char tempo[1100]; - { - char* a=strchr(rcvd+p,';'); - if (a) *a='\0'; + else if ((p=strfield(rcvd,"Connection:"))!=0) { + char* a = rcvd + p; + while(is_space(*a)) a++; + if (*a) { + if (strfield(a, "Keep-Alive")) { + if (!retour->keep_alive) { + retour->keep_alive_max = 10; + retour->keep_alive_t = 15; + } + retour->keep_alive = 1; + } else { + retour->keep_alive = 0; } - sscanf(rcvd+p,"%s",tempo); + } + } + else if ((p=strfield(rcvd,"Keep-Alive:"))!=0) { + char* a = rcvd + p; + while(is_space(*a)) a++; + if (*a) { + char* p; + retour->keep_alive = 1; + retour->keep_alive_max = 10; + retour->keep_alive_t = 15; + if ((p=strstr(a, "timeout="))) { + p+=strlen("timeout="); + sscanf(p, "%d", &retour->keep_alive_t); + } + if ((p=strstr(a, "max="))) { + p+=strlen("max="); + sscanf(p, "%d", &retour->keep_alive_max); + } + if (retour->keep_alive_max <= 1 || retour->keep_alive_t < 3) { + retour->keep_alive = 0; + } + } + } + else if ((p=strfield(rcvd,"TE:"))!=0) { + char* a = rcvd + p; + while(is_space(*a)) a++; + if (*a) { + if (strfield(a, "trailers")) { + retour->keep_alive_trailers=1; + } + } + } + else if ((p=strfield(rcvd,"Content-Encoding:"))!=0) { + if (retour) { + char tempo[1100]; + char* a = rcvd + p; + while(is_space(*a)) a++; + { + char* a=strchr(rcvd+p,';'); + if (a) *a='\0'; + } + sscanf(a,"%s",tempo); if (strlen(tempo)<64) // pas trop long!! - strcpy(retour->contentencoding,tempo); + strcpybuff(retour->contentencoding,tempo); else retour->contentencoding[0]='\0'; // erreur #if HTS_USEZLIB @@ -1125,20 +1398,14 @@ void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) { else if ((p=strfield(rcvd,"Location:"))!=0) { if (retour) { if (retour->location) { - while(*(rcvd+p)==' ') p++; // sauter espaces + while(is_realspace(*(rcvd+p))) p++; // sauter espaces if ((int) strlen(rcvd+p)<HTS_URLMAXSIZE) // pas trop long? - strcpy(retour->location,rcvd+p); + strcpybuff(retour->location,rcvd+p); else // erreur.. ignorer retour->location[0]='\0'; } } } - else if ((p=strfield(rcvd,"Connection: Keep-Alive"))!=0) { - // non, pas de keep-alive! on déconnectera.. - } - else if ((p=strfield(rcvd,"Keep-Alive:"))!=0) { // params keep-alive - // rien à faire - } else if ( ((p=strfield(rcvd,"Set-Cookie:"))!=0) && (cookie) ) { // ohh un cookie char* a = rcvd+p; // pointeur char domain[256]; // domaine cookie (.netscape.com) @@ -1159,10 +1426,10 @@ void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) { // initialiser cookie lu actuellement if (adr) - strcpy(domain,jump_identification(adr)); // domaine - strcpy(path,"/"); // chemin (/) - strcpy(cook_name,""); // nom cookie (MYCOOK) - strcpy(cook_value,""); // valeur (ID=toto,S=1234) + strcpybuff(domain,jump_identification(adr)); // domaine + strcpybuff(path,"/"); // chemin (/) + strcpybuff(cook_name,""); // nom cookie (MYCOOK) + strcpybuff(cook_value,""); // valeur (ID=toto,S=1234) // boucler jusqu'au prochain cookie ou la fin do { char* start_loop=a; @@ -1184,16 +1451,16 @@ void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) { && (((int) (token_end - token_st))>0) && (((int) (value_end - value_st))>0) ) { name[0]='\0'; value[0]='\0'; - strncat(name,token_st,(int) (token_end - token_st)); - strncat(value,value_st,(int) (value_end - value_st)); + strncatbuff(name,token_st,(int) (token_end - token_st)); + strncatbuff(value,value_st,(int) (value_end - value_st)); #if DEBUG_COOK printf("detected cookie-av: name=\"%s\" value=\"%s\"\n",name,value); #endif if (strfield2(name,"domain")) { - strcpy(domain,value); + strcpybuff(domain,value); } else if (strfield2(name,"path")) { - strcpy(path,value); + strcpybuff(path,value); } else if (strfield2(name,"max-age")) { // ignoré.. @@ -1212,8 +1479,8 @@ void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) { } else { if (strnotempty(cook_name)==0) { // noter premier: nom et valeur cookie - strcpy(cook_name,name); - strcpy(cook_value,value); + strcpybuff(cook_name,name); + strcpybuff(cook_value,value); } else { // prochain cookie a=start_loop; // on devra recommencer à cette position next=1; // enregistrer @@ -1238,52 +1505,52 @@ void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) { // transforme le message statuscode en chaîne -void infostatuscode(char* msg,int statuscode) { +HTSEXT_API void infostatuscode(char* msg,int statuscode) { switch( statuscode) { // Erreurs HTTP, selon RFC - case 100: strcpy( msg,"Continue"); break; - case 101: strcpy( msg,"Switching Protocols"); break; - case 200: strcpy( msg,"OK"); break; - case 201: strcpy( msg,"Created"); break; - case 202: strcpy( msg,"Accepted"); break; - case 203: strcpy( msg,"Non-Authoritative Information"); break; - case 204: strcpy( msg,"No Content"); break; - case 205: strcpy( msg,"Reset Content"); break; - case 206: strcpy( msg,"Partial Content"); break; - case 300: strcpy( msg,"Multiple Choices"); break; - case 301: strcpy( msg,"Moved Permanently"); break; - case 302: strcpy( msg,"Moved Temporarily"); break; - case 303: strcpy( msg,"See Other"); break; - case 304: strcpy( msg,"Not Modified"); break; - case 305: strcpy( msg,"Use Proxy"); break; - case 306: strcpy( msg,"Undefined 306 error"); break; - case 307: strcpy( msg,"Temporary Redirect"); break; - case 400: strcpy( msg,"Bad Request"); break; - case 401: strcpy( msg,"Unauthorized"); break; - case 402: strcpy( msg,"Payment Required"); break; - case 403: strcpy( msg,"Forbidden"); break; - case 404: strcpy( msg,"Not Found"); break; - case 405: strcpy( msg,"Method Not Allowed"); break; - case 406: strcpy( msg,"Not Acceptable"); break; - case 407: strcpy( msg,"Proxy Authentication Required"); break; - case 408: strcpy( msg,"Request Time-out"); break; - case 409: strcpy( msg,"Conflict"); break; - case 410: strcpy( msg,"Gone"); break; - case 411: strcpy( msg,"Length Required"); break; - case 412: strcpy( msg,"Precondition Failed"); break; - case 413: strcpy( msg,"Request Entity Too Large"); break; - case 414: strcpy( msg,"Request-URI Too Large"); break; - case 415: strcpy( msg,"Unsupported Media Type"); break; - case 416: strcpy( msg,"Requested Range Not Satisfiable"); break; - case 417: strcpy( msg,"Expectation Failed"); break; - case 500: strcpy( msg,"Internal Server Error"); break; - case 501: strcpy( msg,"Not Implemented"); break; - case 502: strcpy( msg,"Bad Gateway"); break; - case 503: strcpy( msg,"Service Unavailable"); break; - case 504: strcpy( msg,"Gateway Time-out"); break; - case 505: strcpy( msg,"HTTP Version Not Supported"); break; + case 100: strcpybuff( msg,"Continue"); break; + case 101: strcpybuff( msg,"Switching Protocols"); break; + case 200: strcpybuff( msg,"OK"); break; + case 201: strcpybuff( msg,"Created"); break; + case 202: strcpybuff( msg,"Accepted"); break; + case 203: strcpybuff( msg,"Non-Authoritative Information"); break; + case 204: strcpybuff( msg,"No Content"); break; + case 205: strcpybuff( msg,"Reset Content"); break; + case 206: strcpybuff( msg,"Partial Content"); break; + case 300: strcpybuff( msg,"Multiple Choices"); break; + case 301: strcpybuff( msg,"Moved Permanently"); break; + case 302: strcpybuff( msg,"Moved Temporarily"); break; + case 303: strcpybuff( msg,"See Other"); break; + case 304: strcpybuff( msg,"Not Modified"); break; + case 305: strcpybuff( msg,"Use Proxy"); break; + case 306: strcpybuff( msg,"Undefined 306 error"); break; + case 307: strcpybuff( msg,"Temporary Redirect"); break; + case 400: strcpybuff( msg,"Bad Request"); break; + case 401: strcpybuff( msg,"Unauthorized"); break; + case 402: strcpybuff( msg,"Payment Required"); break; + case 403: strcpybuff( msg,"Forbidden"); break; + case 404: strcpybuff( msg,"Not Found"); break; + case 405: strcpybuff( msg,"Method Not Allowed"); break; + case 406: strcpybuff( msg,"Not Acceptable"); break; + case 407: strcpybuff( msg,"Proxy Authentication Required"); break; + case 408: strcpybuff( msg,"Request Time-out"); break; + case 409: strcpybuff( msg,"Conflict"); break; + case 410: strcpybuff( msg,"Gone"); break; + case 411: strcpybuff( msg,"Length Required"); break; + case 412: strcpybuff( msg,"Precondition Failed"); break; + case 413: strcpybuff( msg,"Request Entity Too Large"); break; + case 414: strcpybuff( msg,"Request-URI Too Large"); break; + case 415: strcpybuff( msg,"Unsupported Media Type"); break; + case 416: strcpybuff( msg,"Requested Range Not Satisfiable"); break; + case 417: strcpybuff( msg,"Expectation Failed"); break; + case 500: strcpybuff( msg,"Internal Server Error"); break; + case 501: strcpybuff( msg,"Not Implemented"); break; + case 502: strcpybuff( msg,"Bad Gateway"); break; + case 503: strcpybuff( msg,"Service Unavailable"); break; + case 504: strcpybuff( msg,"Gateway Time-out"); break; + case 505: strcpybuff( msg,"HTTP Version Not Supported"); break; // - default: if (strnotempty(msg)==0) strcpy( msg,"Unknown error"); break; + default: if (strnotempty(msg)==0) strcpybuff( msg,"Unknown error"); break; } } @@ -1376,6 +1643,25 @@ int check_readinput(htsblk* r) { return 0; } +// check if data is available +int check_readinput_t(T_SOC soc, int timeout) { + if (soc != INVALID_SOCKET) { + fd_set fds; // poll structures + struct timeval tv; // structure for select + FD_ZERO(&fds); + FD_SET(soc,&fds); + tv.tv_sec=timeout; + tv.tv_usec=0; + select(soc + 1,&fds,NULL,NULL,&tv); + if (FD_ISSET(soc,&fds)) + return 1; + else + return 0; + } else + return 0; +} + + // lecture d'un bloc sur une socket (ou un fichier!) // >=0 : nombre d'octets lus // <0 : fin ou erreur @@ -1462,9 +1748,9 @@ LLint http_xfread1(htsblk* r,int bufl) { // nouvelle taille if (nl > 0) { r->size+=nl; - if ((int) fwrite(buff,1,nl,r->out)!=nl) { + if ((INTsys)fwrite(buff,1,nl,r->out)!=nl) { r->statuscode=-1; - strcpy(r->msg,"Write error on disk"); + strcpybuff(r->msg,"Write error on disk"); nl=-1; } } @@ -1669,7 +1955,7 @@ htsblk http_test(char* adr,char* fil,char* loc) { } } else { retour.statuscode=-2; - strcpy(retour.msg,"Timeout While Testing"); + strcpybuff(retour.msg,"Timeout While Testing"); } @@ -1730,7 +2016,7 @@ int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) { } // adresse véritable (sans :xx) - strncat(iadr2,iadr,(int) (a - iadr)); + strncatbuff(iadr2,iadr,(int) (a - iadr)); // adresse sans le :xx hp = hts_gethostbyname(iadr2, &fullhostent_buffer); @@ -1755,7 +2041,7 @@ int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) { #endif if (retour) if (retour->msg) - strcpy(retour->msg,"Unable to get server's address"); + strcpybuff(retour->msg,"Unable to get server's address"); return INVALID_SOCKET; } // copie adresse @@ -1770,15 +2056,33 @@ int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) { DEBUG_W("socket\n"); #endif soc=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0); + if (retour != NULL) { + retour->debugid = HTS_STAT.stat_sockid++; + } #if HTS_WIDE_DEBUG DEBUG_W("socket done\n"); #endif if (soc==INVALID_SOCKET) { if (retour) if (retour->msg) - strcpy(retour->msg,"Unable to create a socket"); + strcpybuff(retour->msg,"Unable to create a socket"); return INVALID_SOCKET; // erreur création socket impossible } + + // bind this address + if (retour != NULL && retour->req.proxy.bindhost[0] != '\0') { + t_fullhostent bind_buffer; + hp = hts_gethostbyname(retour->req.proxy.bindhost, &bind_buffer); + if (hp == NULL || + bind(soc, (struct sockaddr *)hp->h_addr_list[0], hp->h_length) != 0) { + if (retour) + if (retour->msg) + strcpybuff(retour->msg,"Unable to bind the specificied server address"); + deletesoc(soc); + return INVALID_SOCKET; + } + } + // structure: connexion au domaine internet, port 80 (ou autre) SOCaddr_initport(server, port); #if HDEBUG @@ -1820,7 +2124,7 @@ int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) { #endif if (retour) if (retour->msg) - strcpy(retour->msg,"Unable to connect to the server"); + strcpybuff(retour->msg,"Unable to connect to the server"); /* Close the socket and notify the error!!! */ deletesoc(soc); return INVALID_SOCKET; @@ -1877,15 +2181,15 @@ int ident_url_absolute(char* url,char* adr,char* fil) { // 1. optional scheme ":" if ((pos=strfield(url,"file:"))) { // fichier local!! (pour les tests) //!! p+=3; - strcpy(adr,"file://"); + strcpybuff(adr,"file://"); } else if ((pos=strfield(url,"http:"))) { // HTTP //!!p+=3; } else if ((pos=strfield(url,"ftp:"))) { // FTP - strcpy(adr,"ftp://"); // FTP!! + strcpybuff(adr,"ftp://"); // FTP!! //!!p+=3; #if HTS_USEOPENSSL - } else if ((pos=strfield(url,"https:"))) { // HTTPS - strcpy(adr,"https://"); + } else if (SSL_is_available && (pos=strfield(url,"https:"))) { // HTTPS + strcpybuff(adr,"https://"); #endif } else if (scheme) { return -1; // erreur non reconnu @@ -1911,17 +2215,17 @@ int ident_url_absolute(char* url,char* adr,char* fil) { // chemin www... trop long!! if ( ( ((int) (q - p)) ) > HTS_URLMAXSIZE) { - //strcpy(retour.msg,"Path too long"); + //strcpybuff(retour.msg,"Path too long"); return -1; // erreur } // recopier adresse www.. - strncat(adr,p, ((int) (q - p)) ); + strncatbuff(adr,p, ((int) (q - p)) ); // *( adr+( ((int) q) - ((int) p) ) )=0; // faut arrêter la fumette! // recopier chemin /pub/.. if (q[0] != '/') // page par défaut (/) - strcat(fil,"/"); - strcat(fil,q); + strcatbuff(fil,"/"); + strcatbuff(fil,q); // SECURITE: // simplifier url pour les ../ fil_simplifie(fil); @@ -1931,8 +2235,13 @@ int ident_url_absolute(char* url,char* adr,char* fil) { char* a; p=url+pos; - - strcat(fil,p); // fichier local ; adr="#" + if (*p == '/' || *p == '\\') { /* file:///.. */ + strcatbuff(fil,p); // fichier local ; adr="#" + } else { + strcatbuff(fil,"//"); /* file://server/foo */ + strcatbuff(fil,p); + } + a=strchr(fil,'?'); if (a) *a='\0'; /* couper query (inutile pour file:// lors de la requête) */ @@ -1948,7 +2257,7 @@ int ident_url_absolute(char* url,char* adr,char* fil) { // nommer au besoin.. (non utilisé normalement) if (!strnotempty(fil)) - strcpy(fil,"default-index.html"); + strcpybuff(fil,"default-index.html"); // case insensitive pour adresse { @@ -1981,12 +2290,12 @@ void fil_simplifie(char* f) { tempo[0]='\0'; // if (!last) /* can't go upper.. */ - strcpy(tempo,"/"); + strcpybuff(tempo,"/"); else strncpy(tempo,f,last+1); tempo[last+1]='\0'; - strcat(tempo,f+i+4); - strcpy(f,tempo); // remplacer + strcatbuff(tempo,f+i+4); + strcpybuff(f,tempo); // remplacer i=-1; // recommencer last=0; } @@ -2004,20 +2313,19 @@ void fil_simplifie(char* f) { while ( (a=strstr(f,"./")) ) { char tempo[HTS_URLMAXSIZE*2]; tempo[0]='\0'; - strcpy(tempo,a+2); - strcpy(a,tempo); + strcpybuff(tempo,a+2); + strcpybuff(a,tempo); } // delete all remaining ../ (potential threat) while ( (a=strstr(f,"../")) ) { char tempo[HTS_URLMAXSIZE*2]; tempo[0]='\0'; - strcpy(tempo,a+3); - strcpy(a,tempo); + strcpybuff(tempo,a+3); + strcpybuff(a,tempo); } } - // fermer liaison fichier ou socket HTS_INLINE void deletehttp(htsblk* r) { #if HTS_DEBUG_CLOSESOCK @@ -2025,6 +2333,14 @@ HTS_INLINE void deletehttp(htsblk* r) { sprintf(info,"deletehttp: (htsblk*) %d\n",r); DEBUG_W2(info); #endif +#if HTS_USEOPENSSL + /* Free OpenSSL structures */ + if (SSL_is_available && r->ssl_con) { + SSL_shutdown(r->ssl_con); + SSL_free(r->ssl_con); + r->ssl_con=NULL; + } +#endif if (r->soc!=INVALID_SOCKET) { if (r->is_file) { if (r->fp) @@ -2038,6 +2354,16 @@ HTS_INLINE void deletehttp(htsblk* r) { } } +// free the addr buffer +// always returns 1 +HTS_INLINE int deleteaddr(htsblk* r) { + if (r->adr) { + freet(r->adr); + r->adr = NULL; + } + return 1; +} + // fermer une socket HTS_INLINE void deletesoc(T_SOC soc) { if (soc!=INVALID_SOCKET) { @@ -2067,7 +2393,7 @@ HTS_INLINE void deletesoc(T_SOC soc) { /* Will also clean other things */ HTS_INLINE void deletesoc_r(htsblk* r) { #if HTS_USEOPENSSL - if (r->ssl_con) { + if (SSL_is_available && r->ssl_con) { SSL_shutdown(r->ssl_con); // SSL_CTX_set_quiet_shutdown(r->ssl_con->ctx, 1); SSL_free(r->ssl_con); @@ -2084,7 +2410,7 @@ HTS_INLINE TStamp time_local(void) { } // number of millisec since 1970 -HTS_INLINE TStamp mtime_local(void) { +HTSEXT_API HTS_INLINE TStamp mtime_local(void) { #ifndef HTS_DO_NOT_USE_FTIME struct timeb B; ftime( &B ); @@ -2120,7 +2446,7 @@ void sec2str(char *st,TStamp t) { } // idem, plus court (chaine) -void qsec2str(char *st,TStamp t) { +HTSEXT_API void qsec2str(char *st,TStamp t) { int j,h,m,s; j=(int) (t/(3600*24)); @@ -2181,7 +2507,7 @@ struct tm* convert_time_rfc822(char* s) { if ((int) strlen(s) > 200) return NULL; - strcpy(str,s); + strcpybuff(str,s); hts_lowcase(str); /* éliminer :,- */ while( (a=strchr(str,'-')) ) *a=' '; @@ -2200,7 +2526,7 @@ struct tm* convert_time_rfc822(char* s) { tok[0]='\0'; if (first!=last) { char* pos; - strncat(tok,first,(int) (last - first)); + strncatbuff(tok,first,(int) (last - first)); /* analyser */ if ( (pos=strstr(months,tok)) ) { /* month always in letters */ result_mm=((int) (pos - months))/4; @@ -2274,36 +2600,44 @@ int set_filetime_rfc822(char* file,char* date) { // heure au format rfc (taille buffer 256o) HTS_INLINE void time_rfc822(char* s,struct tm * A) { + if (A == NULL) { + int localtime_returned_null=0; + assert(localtime_returned_null); + } strftime(s,256,"%a, %d %b %Y %H:%M:%S GMT",A); } // heure locale au format rfc (taille buffer 256o) HTS_INLINE void time_rfc822_local(char* s,struct tm * A) { + if (A == NULL) { + int localtime_returned_null=0; + assert(localtime_returned_null); + } strftime(s,256,"%a, %d %b %Y %H:%M:%S",A); } // conversion en b,Kb,Mb -char* int2bytes(LLint n) { +HTSEXT_API char* int2bytes(LLint n) { char** a=int2bytes2(n); char* buff; NOSTATIC_RESERVE(buff, char, 256); - strcpy(buff,a[0]); - strcat(buff,a[1]); + strcpybuff(buff,a[0]); + strcatbuff(buff,a[1]); return concat(buff,""); } // conversion en b/s,Kb/s,Mb/s -char* int2bytessec(long int n) { +HTSEXT_API char* int2bytessec(long int n) { char* buff; char** a=int2bytes2(n); NOSTATIC_RESERVE(buff, char, 256); - strcpy(buff,a[0]); - strcat(buff,a[1]); + strcpybuff(buff,a[0]); + strcatbuff(buff,a[1]); return concat(buff,"/s"); } -char* int2char(int n) { +HTSEXT_API char* int2char(int n) { char* buffer; NOSTATIC_RESERVE(buffer, char, 32); sprintf(buffer,"%d",n); @@ -2327,35 +2661,35 @@ typedef struct { char buff2[32]; char* buffadr[2]; } strc_int2bytes2; -char** int2bytes2(LLint n) { +HTSEXT_API char** int2bytes2(LLint n) { strc_int2bytes2* strc; NOSTATIC_RESERVE(strc, strc_int2bytes2, 1); if (n < ToLLintKiB) { sprintf(strc->buff1,"%d",(int)(LLint)n); - strcpy(strc->buff2,"B"); + strcpybuff(strc->buff2,"B"); } else if (n < ToLLintMiB) { sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/ToLLintKiB)),(int)((LLint)((n%ToLLintKiB)*100)/ToLLintKiB)); - strcpy(strc->buff2,"KiB"); + strcpybuff(strc->buff2,"KiB"); } #ifdef HTS_LONGLONG else if (n < ToLLintGiB) { sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB)))); - strcpy(strc->buff2,"MiB"); + strcpybuff(strc->buff2,"MiB"); } else if (n < ToLLintTiB) { sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintGiB))),(int)((LLint)(((n%(ToLLintGiB))*100)/(ToLLintGiB)))); - strcpy(strc->buff2,"GiB"); + strcpybuff(strc->buff2,"GiB"); } else if (n < ToLLintPiB) { sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintTiB))),(int)((LLint)(((n%(ToLLintTiB))*100)/(ToLLintTiB)))); - strcpy(strc->buff2,"TiB"); + strcpybuff(strc->buff2,"TiB"); } else { sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintPiB))),(int)((LLint)(((n%(ToLLintPiB))*100)/(ToLLintPiB)))); - strcpy(strc->buff2,"PiB"); + strcpybuff(strc->buff2,"PiB"); } #else else { sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB)))); - strcpy(strc->buff2,"MiB"); + strcpybuff(strc->buff2,"MiB"); } #endif strc->buffadr[0]=strc->buff1; @@ -2376,34 +2710,34 @@ int sig_ignore_flag( int setflag ) { // flag ignore // envoi de texte (en têtes généralement) sur la socket soc HTS_INLINE int sendc(htsblk* r, char* s) { - int n; + int n, ssz = (int)strlen(s); #if HTS_WIN #else sig_ignore_flag(1); #endif #if HDEBUG - write(0,s,strlen(s)); + write(0,s,ssz); #endif #if HTS_USEOPENSSL - if (r->ssl) { - n = SSL_write(r->ssl_con, s, strlen(s)); + if (SSL_is_available && r->ssl) { + n = SSL_write(r->ssl_con, s, ssz); } else #endif - n = send(r->soc,s,strlen(s),0); + n = send(r->soc,s,ssz,0); #if HTS_WIN #else sig_ignore_flag(0); #endif - return n; + return ( n == ssz ) ? n : -1; } // Remplace read -void finput(int fd,char* s,int max) { +int finput(int fd,char* s,int max) { char c; int j=0; do { @@ -2419,7 +2753,8 @@ void finput(int fd,char* s,int max) { } } } while((c!=0) && (j<max-1)); - s[j++]='\0'; + s[j]='\0'; + return j; } // Like linput, but in memory (optimized) @@ -2444,7 +2779,7 @@ int binput(char* buff,char* s,int max) { count--; // copy if (count > 0) { - strncat(s, buff, count); + strncatbuff(s, buff, count); } // and terminate with a null char s[count]='\0'; @@ -2470,6 +2805,34 @@ int linput(FILE* fp,char* s,int max) { s[j]='\0'; return j; } +int linputsoc(T_SOC soc, char* s, int max) { + int c; + int j=0; + do { + unsigned char ch; + if (recv(soc, &ch, 1, 0) == 1) { + c = ch; + } else { + c = EOF; + } + if (c!=EOF) { + switch(c) { + case 13: break; // sauter CR + case 10: c=-1; break; + case 9: case 12: break; // sauter ces caractères + default: s[j++]=(char) c; break; + } + } + } while((c!=-1) && (c!=EOF) && (j<(max-1))); + s[j]='\0'; + return j; +} +int linputsoc_t(T_SOC soc, char* s, int max, int timeout) { + if (check_readinput_t(soc, timeout)) { + return linputsoc(soc, s, max); + } + return -1; +} int linput_trim(FILE* fp,char* s,int max) { int rlen=0; char* ls=(char*) malloct(max+2); @@ -2660,7 +3023,7 @@ int ishtml(char* fil) { char fil_noquery[HTS_URLMAXSIZE*2]; fil_noquery[0]='\0'; a++; // pointer sur extension - strncat(fil_noquery,a,HTS_URLMAXSIZE); + strncatbuff(fil_noquery,a,HTS_URLMAXSIZE); a=strchr(fil_noquery,'?'); if (a) *a='\0'; @@ -2710,7 +3073,7 @@ HTS_INLINE int ishttperror(int err) { // retourne le pointeur ou le pointeur + offset si il existe dans la chaine un @ signifiant // une identification -char* jump_identification(char* source) { +HTSEXT_API char* jump_identification(char* source) { char *a,*trytofind; // rechercher dernier @ (car parfois email transmise dans adresse!) // mais sauter ftp:// éventuel @@ -2719,9 +3082,55 @@ char* jump_identification(char* source) { return (trytofind != NULL)?trytofind:a; } +HTSEXT_API char* jump_normalized(char* source) { + source = jump_identification(source); + if (strfield(source, "www") && source[3] != '\0') { + if (source[3] == '.') { // www.foo.com -> foo.com + source += 4; + } else { // www-4.foo.com -> foo.com + char* a = source + 3; + while(*a && ( isdigit(*a) || *a == '-') ) a++; + if (*a == '.') { + source = a + 1; + } + } + } + return source; +} + +HTSEXT_API char* fil_normalized(char* source, char* dest_) { + char* dest=dest_; + char lastc = 0; + int gotquery=0; + while(*source) { + if (*source == '?') + gotquery=1; + if ( + (!gotquery && lastc == '/' && *source == '/') // foo//bar -> foo/bar + ) { + } + else { + *dest++ = *source; + } + lastc = *source; + source++; + } + *dest++ = '\0'; + return dest_; +} + +#define endwith(a) ( (len >= (sizeof(a)-1)) ? ( strncmp(dest, a+len-(sizeof(a)-1), sizeof(a)-1) == 0 ) : 0 ); +HTSEXT_API char* adr_normalized(char* source, char* dest) { + /* not yet too aggressive (no com<->net<->org checkings) */ + strcpybuff(dest, jump_normalized(source)); + return dest; +} +#undef endwith + + // find port (:80) or NULL if not found // can handle IPV6 addresses -char* jump_toport(char* source) { +HTSEXT_API char* jump_toport(char* source) { char *a,*trytofind; a = jump_identification(source); trytofind = strrchr_limit(a, ']', strchr(source, '/')); // find last ] (http://[3ffe:b80:1234::1]:80/foo.html) @@ -2732,7 +3141,7 @@ char* jump_toport(char* source) { // strrchr, but not too far char* strrchr_limit(char* s, char c, char* limit) { if (limit == NULL) { - char* p = strchr(s, c); + char* p = strrchr(s, c); return p?(p+1):NULL; } else { char *a=NULL, *p; @@ -2765,17 +3174,18 @@ HTS_INLINE char* jump_protocol(char* source) { } // codage base 64 a vers b -void code64(char* a,char* b) { +void code64(unsigned char* a,int size_a,unsigned char* b,int crlf) { int i1=0,i2=0,i3=0,i4=0; - unsigned long store; + int loop=0; + unsigned long int store; int n; const char _hts_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - b[0]='\0'; - while(*a) { + while(size_a-- > 0) { // 24 bits - n=1; store=0; store |= ((*a++) & 0xff); - if (*a) { n=2; store <<= 8; store |= ((*a++) & 0xff); } - if (*a) { n=3; store <<= 8; store |= ((*a++) & 0xff); } + n=1; + store = *a++; + if (size_a-- > 0) { n=2; store <<= 8; store |= *a++; } + if (size_a-- > 0) { n=3; store <<= 8; store |= *a++; } if (n==3) { i4=store & 63; i3=(store>>6) & 63; @@ -2802,6 +3212,11 @@ void code64(char* a,char* b) { *b++ = _hts_base64[i4]; else *b++ = '='; + + if (crlf && ( ( loop += 3 ) % 60) == 0 ) { + *b++ = '\r'; + *b++ = '\n'; + } } *b++='\0'; } @@ -2809,7 +3224,7 @@ void code64(char* a,char* b) { // remplacer " par " etc.. // buffer MAX 1Ko #define strcmpbeg(a, b) strncmp(a, b, strlen(b)) -void unescape_amp(char* s) { +HTSEXT_API void unescape_amp(char* s) { while(*s) { if (*s=='&') { char* end=strchr(s,';'); @@ -3043,8 +3458,8 @@ void unescape_amp(char* s) { if (c) { char buff[HTS_URLMAXSIZE*2]; buff[0]=(char) c; - strcpy(buff+1,end+1); - strcpy(s,buff); + strcpybuff(buff+1,end+1); + strcpybuff(s,buff); } } } @@ -3054,7 +3469,7 @@ void unescape_amp(char* s) { // remplacer %20 par ' ', | par : etc.. // buffer MAX 1Ko -char* unescape_http(char* s) { +HTSEXT_API char* unescape_http(char* s) { char* tempo; int i,j=0; NOSTATIC_RESERVE(tempo, char, HTS_URLMAXSIZE*2); @@ -3078,7 +3493,7 @@ char* unescape_http(char* s) { } // unescape in URL/URI ONLY what has to be escaped, to form a standard URL/URI -char* unescape_http_unharm(char* s, int no_high) { +HTSEXT_API char* unescape_http_unharm(char* s, int no_high) { char* tempo; int i,j=0; NOSTATIC_RESERVE(tempo, char, HTS_URLMAXSIZE*2); @@ -3120,32 +3535,46 @@ char* unescape_http_unharm(char* s, int no_high) { // remplacer " par %xx etc.. // buffer MAX 1Ko -void escape_spc_url(char* s) { +HTSEXT_API void escape_spc_url(char* s) { x_escape_http(s,2); } // smith / john -> smith%20%2f%20john -void escape_in_url(char* s) { +HTSEXT_API void escape_in_url(char* s) { x_escape_http(s,1); } // smith / john -> smith%20/%20john -void escape_uri(char* s) { +HTSEXT_API void escape_uri(char* s) { x_escape_http(s,3); } -void escape_uri_utf(char* s) { +HTSEXT_API void escape_uri_utf(char* s) { x_escape_http(s,30); } -void escape_check_url(char* s) { +HTSEXT_API void escape_check_url(char* s) { x_escape_http(s,0); } // same as escape_check_url, but returns char* -char* escape_check_url_addr(char* s) { +HTSEXT_API char* escape_check_url_addr(char* s) { char* adr; escape_check_url(adr = concat(s,"")); return adr; } +// strip all control characters +HTSEXT_API void escape_remove_control(char* s) { + unsigned char* ss = (unsigned char*) s; + while(*ss) { + if (*ss < 32) { /* CONTROL characters go away! */ + char tmp[HTS_URLMAXSIZE*2]; + strcpybuff(tmp, ss+1); + strcpybuff(ss, tmp); + } else { + ss++; + } + } +} + -void x_escape_http(char* s,int mode) { +HTSEXT_API void x_escape_http(char* s,int mode) { while(*s) { int test=0; if (mode == 0) @@ -3155,7 +3584,8 @@ void x_escape_http(char* s,int mode) { || CHAR_DELIM(*s) || CHAR_UNWISE(*s) || CHAR_SPECIAL(*s) - || CHAR_XXAVOID(*s) ); + || CHAR_XXAVOID(*s) + || CHAR_MARK(*s)); } else if (mode==2) test=(strchr(" ",*s)!=0); // n'escaper que espace @@ -3171,12 +3601,12 @@ void x_escape_http(char* s,int mode) { } if (test) { - char buffer[HTS_URLMAXSIZE*2]; + char buffer[HTS_URLMAXSIZE*3]; int n; n=(int)(unsigned char) *s; - strcpy(buffer,s+1); + strcpybuff(buffer,s+1); sprintf(s,"%%%02x",n); - strcat(s,buffer); + strcatbuff(s,buffer); } s++; } @@ -3206,8 +3636,8 @@ char* concat(const char* a,const char* b) { concat_strc* strc; NOSTATIC_RESERVE(strc, concat_strc, 1); strc->rol=((strc->rol+1)%16); // roving pointer - strcpy(strc->buff[strc->rol],a); - if (b) strcat(strc->buff[strc->rol],b); + strcpybuff(strc->buff[strc->rol],a); + if (b) strcatbuff(strc->buff[strc->rol],b); return strc->buff[strc->rol]; } // conversion fichier / -> antislash @@ -3244,7 +3674,7 @@ char* convtolower(char* a) { concat_strc* strc; NOSTATIC_RESERVE(strc, concat_strc, 1); strc->rol=((strc->rol+1)%16); // roving pointer - strcpy(strc->buff[strc->rol],a); + strcpybuff(strc->buff[strc->rol],a); hts_lowcase(strc->buff[strc->rol]); // lower case return strc->buff[strc->rol]; } @@ -3308,7 +3738,7 @@ void guess_httptype(char *s,char *fil) { // flag: 1 si toujours renvoyer un type void get_httptype(char *s,char *fil,int flag) { if (ishtml(fil)==1) - strcpy(s,"text/html"); + strcpybuff(s,"text/html"); else { char *a=fil+strlen(fil)-1; while ( (*a!='.') && (*a!='/') && (a>fil)) a--; @@ -3319,7 +3749,7 @@ void get_httptype(char *s,char *fil,int flag) { while( (!ok) && (strnotempty(hts_mime[j][1])) ) { if (strfield2(hts_mime[j][1],a)) { if (hts_mime[j][0][0]!='*') { // Une correspondance existe - strcpy(s,hts_mime[j][0]); + strcpybuff(s,hts_mime[j][0]); ok=1; } } @@ -3328,7 +3758,7 @@ void get_httptype(char *s,char *fil,int flag) { if (!ok) if (flag) sprintf(s,"application/%s",a); } else { - if (flag) strcpy(s,"application/octet-stream"); + if (flag) strcpybuff(s,"application/octet-stream"); } } } @@ -3364,7 +3794,7 @@ int get_userhttptype(int setdefs,char *s,char *ext) { char* a; a=strchr(detect,'\n'); if (a) { - strncat(s,detect,(int) (a - detect)); + strncatbuff(s,detect,(int) (a - detect)); } } return 1; @@ -3383,7 +3813,7 @@ void give_mimext(char *s,char *st) { while( (!ok) && (strnotempty(hts_mime[j][1])) ) { if (strfield2(hts_mime[j][0],st)) { if (hts_mime[j][1][0]!='*') { // Une correspondance existe - strcpy(s,hts_mime[j][1]); + strcpybuff(s,hts_mime[j][1]); ok=1; } } @@ -3403,7 +3833,7 @@ void give_mimext(char *s,char *st) { if (a) { if ((int)strlen(a) >= 1) { if ((int)strlen(a) <= 4) { - strcpy(s,a); + strcpybuff(s,a); ok=1; } } @@ -3441,7 +3871,7 @@ char* get_ext(char *fil) { if (*a=='.') { fil_noquery[0]='\0'; a++; // pointer sur extension - strncat(fil_noquery,a,HTS_URLMAXSIZE); + strncatbuff(fil_noquery,a,HTS_URLMAXSIZE); a=strchr(fil_noquery,'?'); if (a) *a='\0'; @@ -3531,60 +3961,54 @@ void fprintfio(FILE* fp,char* buff,char* prefix) { /* Le fichier existe-t-il? (ou est-il accessible?) */ int fexist(char* s) { - FILE* fp; - if (strnotempty(s)==0) // nom vide: non trouvé - return 0; - fp=fopen(fconv(s),"rb"); - if (fp!=NULL) fclose(fp); - return (fp!=NULL); + struct stat st; + memset(&st, 0, sizeof(st)); + if (stat(s, &st) == 0) { + if (S_ISREG(st.st_mode)) { + return 1; + } + } + return 0; } /* Taille d'un fichier, -1 si n'existe pas */ /* fp->_cnt ne fonctionne pas sur toute les plate-formes :-(( */ /* Note: NOT YET READY FOR 64-bit */ -//LLint fsize(char* s) { -int fsize(char* s) { - /* -#if HTS_WIN - HANDLE hFile; - DWORD dwSizeHigh = 0; - DWORD dwSizeLow = 0; - hFile = CreateFile(s,0,0,NULL,OPEN_EXISTING,0,NULL); - if (hFile) { - dwSizeLow = GetFileSize (hFile, & dwSizeHigh) ; - CloseHandle(hFile); - if (dwSizeLow != 0xFFFFFFFF) - return (dwSizeLow & (dwSizeHigh<<32)); - else - return -1; - } else - return -1; -#else - */ +INTsys fsize(char* s) { FILE* fp; if (strnotempty(s)==0) // nom vide: erreur return -1; fp=fopen(fconv(s),"rb"); if (fp!=NULL) { - int i; + INTsys i; fseek(fp,0,SEEK_END); +#ifdef HTS_FSEEKO + i=ftello(fp); +#else i=ftell(fp); +#endif fclose(fp); return i; } else return -1; - /* -#endif - */ } -int fpsize(FILE* fp) { - int oldpos,size; +INTsys fpsize(FILE* fp) { + INTsys oldpos,size; if (!fp) return -1; +#ifdef HTS_FSEEKO + oldpos=ftello(fp); +#else oldpos=ftell(fp); +#endif fseek(fp,0,SEEK_END); +#ifdef HTS_FSEEKO + size=ftello(fp); + fseeko(fp,oldpos,SEEK_SET); +#else size=ftell(fp); fseek(fp,oldpos,SEEK_SET); +#endif return size; } @@ -3593,7 +4017,7 @@ typedef struct { char path[1024+4]; int init; } hts_rootdir_strc; -char* hts_rootdir(char* file) { +HTSEXT_API char* hts_rootdir(char* file) { static hts_rootdir_strc strc = {"", 0}; //NOSTATIC_RESERVE(strc, hts_rootdir_strc, 1); if (file) { @@ -3602,7 +4026,7 @@ char* hts_rootdir(char* file) { strc.init=1; if (strnotempty(file)) { char* a; - strcpy(strc.path,file); + strcpybuff(strc.path,file); while((a=strrchr(strc.path,'\\'))) *a='/'; if ((a=strrchr(strc.path,'/'))) { *(a+1)='\0'; @@ -3613,7 +4037,7 @@ char* hts_rootdir(char* file) { if( getcwd( strc.path, 1024 ) == NULL ) strc.path[0]='\0'; else - strcat(strc.path,"/"); + strcatbuff(strc.path,"/"); } } return NULL; @@ -3625,7 +4049,7 @@ char* hts_rootdir(char* file) { -hts_stat_struct HTS_STAT; +HTSEXT_API hts_stat_struct HTS_STAT; // // return number of downloadable bytes, depending on rate limiter // see engine_stats() routine, too @@ -3693,7 +4117,7 @@ HTS_INLINE int hts_read(htsblk* r,char* buff,int size) { DEBUG_W("read\n"); #endif if (r->fp) - retour=fread(buff,1,size,r->fp); + retour=(int)fread(buff,1,size,r->fp); else retour=-1; } else { @@ -3704,7 +4128,7 @@ HTS_INLINE int hts_read(htsblk* r,char* buff,int size) { #endif //HTS_TOTAL_RECV_CHECK(size); // Diminuer au besoin si trop de données reçues #if HTS_USEOPENSSL - if (r->ssl) { + if (SSL_is_available && r->ssl) { retour = SSL_read(r->ssl_con, buff, size); if (retour <= 0) { int err_code = SSL_get_error(r->ssl_con, retour); @@ -3745,6 +4169,21 @@ t_dnscache* _hts_cache(void) { NOSTATIC_RESERVE(cache, t_dnscache, 1); return cache; } +// free the cache +static void hts_cache_free_(t_dnscache* cache) { + if (cache != NULL) { + if (cache->n != NULL) { + hts_cache_free_(cache->n); + } + freet(cache); + } +} +void hts_cache_free(t_dnscache* cache) { + if (cache != NULL) { + hts_cache_free_(cache->n); + cache->n = NULL; + } +} // lock le cache dns pour tout opération d'ajout // plus prudent quand plusieurs threads peuvent écrire dedans.. @@ -3819,7 +4258,7 @@ int hts_dnstest(char* _iadr) { NOSTATIC_RESERVE(iadr, char, HTS_URLMAXSIZE*2); // sauter user:pass@ éventuel - strcpy(iadr,jump_identification(_iadr)); + strcpybuff(iadr,jump_identification(_iadr)); // couper éventuel : { char *a; @@ -3852,7 +4291,7 @@ int hts_dnstest(char* _iadr) { } -t_hostent* vxgethostbyname(char* hostname, void* v_buffer) { +HTSEXT_API t_hostent* vxgethostbyname(char* hostname, void* v_buffer) { t_fullhostent* buffer = (t_fullhostent*) v_buffer; /* Clear */ fullhostent_init(buffer); @@ -3869,8 +4308,8 @@ t_hostent* vxgethostbyname(char* hostname, void* v_buffer) { if ((hostname[0] == '[') && (hostname[strlen(hostname)-1] == ']')) { char tempo[HTS_URLMAXSIZE*2]; tempo[0]='\0'; - strncat(tempo, hostname+1, strlen(hostname)-2); - strcpy(hostname, tempo); + strncatbuff(tempo, hostname+1, strlen(hostname)-2); + strcpybuff(hostname, tempo); } { @@ -3935,7 +4374,7 @@ t_hostent* hts_gethostbyname(char* _iadr, void* v_buffer) { /* Clear */ fullhostent_init(buffer); - strcpy(iadr,jump_identification(_iadr)); + strcpybuff(iadr,jump_identification(_iadr)); // couper éventuel : { char *a; @@ -3993,7 +4432,7 @@ t_hostent* hts_gethostbyname(char* _iadr, void* v_buffer) { #endif cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache)); if (cache->n!=NULL) { - strcpy(cache->n->iadr,iadr); + strcpybuff(cache->n->iadr,iadr); if (hp!=NULL) { memcpy(cache->n->host_addr, hp->h_addr_list[0], hp->h_length); cache->n->host_length=hp->h_length; @@ -4028,102 +4467,161 @@ HTS_INLINE t_hostent* hts_gethostbyname(char* iadr, t_fullhostent* buffer) { // --- Tracage des mallocs() --- -#if HTS_TRACE_MALLOC -typedef struct _mlink { +#ifdef HTS_TRACE_MALLOC +//#define htsLocker(A, N) htsLocker(A, N) +#define htsLocker(A, N) do {} while(0) +static mlink trmalloc = {NULL,0,0,NULL}; +static int trmalloc_id=0; +static PTHREAD_LOCK_TYPE* mallocMutex = NULL; +static void hts_meminit(void) { + //if (mallocMutex == NULL) { + // mallocMutex = calloc(sizeof(*mallocMutex), 1); + // htsLocker(mallocMutex, -999); + //} +} +void* hts_malloc(size_t len) { void* adr; - int len; - int id; - struct _mlink* next; -} mlink; -mlink trmalloc = {NULL,0,0,NULL}; -int trmalloc_id=0; - -HTS_INLINE void* hts_malloc(size_t len,size_t len2) { + hts_meminit(); + htsLocker(mallocMutex, 1); + fassert(len > 0); + adr = hts_xmalloc(len, 0); + htsLocker(mallocMutex, 0); + return adr; +} +void* hts_calloc(size_t len,size_t len2) { + void* adr; + hts_meminit(); + fassert(len > 0); + fassert(len2 > 0); + htsLocker(mallocMutex, 1); + adr = hts_xmalloc(len, len2); + htsLocker(mallocMutex, 0); + memset(adr, 0, len * len2); + return adr; +} +void* hts_xmalloc(size_t len,size_t len2) { mlink* lnk = (mlink*) calloc(1,sizeof(mlink)); - void* r = NULL; + fassert(lnk != NULL); + fassert(len > 0); + fassert(len2 >= 0); if (lnk) { + void* r = NULL; + int size, bsize = sizeof(t_htsboundary); if (len2) - r = calloc(len,len2); + size = len * len2; else - r = malloc(len); + size = len; + size += ((bsize - (size % bsize)) % bsize); /* check alignement */ + r = malloc(size + bsize*2); + fassert(r != NULL); if (r) { - lnk->adr=r; - if (len2) - lnk->len=len*len2; - else - lnk->len=len; - lnk->id=trmalloc_id++; - lnk->next=trmalloc.next; - trmalloc.next=lnk; -#if MEMDEBUG - //printf("malloc: %d\n",r); -#endif - } else free(lnk); + * ( (t_htsboundary*) ((char*) r ) ) + = * ( (t_htsboundary*) ( (char*) r + size + bsize ) ) + = htsboundary; + ((char*) r) += bsize; /* boundary */ + lnk->adr = r; + lnk->len = size; + lnk->id = trmalloc_id++; + lnk->next = trmalloc.next; + trmalloc.next = lnk; + return r; + } else { + free(lnk); + } } - return r; + return NULL; } -HTS_INLINE void hts_free(void* adr) { +void hts_free(void* adr) { mlink* lnk = &trmalloc; + int bsize = sizeof(t_htsboundary); + fassert(adr != NULL); if (!adr) { -#if MEMDEBUG - printf("* unexpected free() error at %d\n",adr); -#endif return; } - do { - if (lnk->next->adr==adr) { + htsLocker(mallocMutex, 1); + while(lnk->next != NULL) { + if (lnk->next->adr == adr) { mlink* blk_free=lnk->next; -#if 1 + fassert(blk_free->id != -1); + fassert( * ( (t_htsboundary*) ( (char*) adr - bsize ) ) == htsboundary ); + fassert( * ( (t_htsboundary*) ( (char*) adr + blk_free->len ) ) == htsboundary ); lnk->next=lnk->next->next; free((void*) blk_free); -#else -#if MEMDEBUG - if (blk_free->id==-1) { - printf("* memory has already been freed: %d (id=%d)\n",blk_free->adr,blk_free->id); - } -#endif - blk_free->id=-1; -#endif - free(adr); -#if MEMDEBUG - //printf("free: %d (id=%d)\n",blk_free->adr,blk_free->id); -#endif + //blk_free->id=-1; + free((char*) adr - bsize); + htsLocker(mallocMutex, 0); return; } - lnk=lnk->next; - } while(lnk->next != NULL); -#if MEMDEBUG - printf("* unexpected free() error at %d\n",adr); -#endif + lnk = lnk->next; + fassert(lnk->next != NULL); + } free(adr); + htsLocker(mallocMutex, 0); } -HTS_INLINE void* hts_realloc(void* adr,size_t len) { +void* hts_realloc(void* adr,size_t len) { + int bsize = sizeof(t_htsboundary); + len += ((bsize - (len % bsize)) % bsize); /* check alignement */ + if (adr != NULL) { + mlink* lnk = &trmalloc; + htsLocker(mallocMutex, 1); + while(lnk->next != NULL) { + if (lnk->next->adr==adr) { + { + mlink* blk_free=lnk->next; + fassert(blk_free->id != -1); + fassert( * ( (t_htsboundary*) ( (char*) adr - bsize ) ) == htsboundary ); + fassert( * ( (t_htsboundary*) ( (char*) adr + blk_free->len ) ) == htsboundary ); + } + adr = realloc((char*) adr - bsize, len + bsize * 2); + fassert(adr != NULL); + lnk->next->adr = (char*) adr + bsize; + lnk->next->len = len; + * ( (t_htsboundary*) ( (char*) adr ) ) + = * ( (t_htsboundary*) ( (char*) adr + len + bsize) ) + = htsboundary; + htsLocker(mallocMutex, 0); + return (char*) adr + bsize; + } + lnk = lnk->next; + fassert(lnk->next != NULL); + } + htsLocker(mallocMutex, 0); + } + return hts_malloc(len); +} +mlink* hts_find(char* adr) { + char* stkframe = (char*) &stkframe; mlink* lnk = &trmalloc; - do { - if (lnk->next->adr==adr) { - adr = realloc(adr,len); - lnk->next->adr = adr; - lnk->next->len = len; -#if MEMDEBUG - //printf("realloc: %d (id=%d)\n",lnk->next->adr,lnk->next->id); -#endif - return adr; + int bsize = sizeof(t_htsboundary); + fassert(adr != NULL); + if (!adr) { + return NULL; + } + htsLocker(mallocMutex, 1); + while(lnk->next != NULL) { + if (adr >= lnk->next->adr && adr <= lnk->next->adr + lnk->next->len) { /* found */ + htsLocker(mallocMutex, 0); + return lnk->next; } - lnk=lnk->next; - } while(lnk->next != NULL); -#if MEMDEBUG - printf("* unexpected realloc() error at %d\n",adr); -#endif - return realloc(adr,len); + lnk = lnk->next; + } + htsLocker(mallocMutex, 0); + { + int depl = (int) (adr - stkframe); + if (depl < 0) depl = -depl; + //fassert(depl < 512000); /* near the stack frame.. doesn't look like malloc but stack variable */ + return NULL; + } } // check the malloct() and calloct() trace stack void hts_freeall(void) { + int bsize = sizeof(t_htsboundary); while(trmalloc.next) { #if MEMDEBUG printf("* block %d\t not released: at %d\t (%d\t bytes)\n",trmalloc.next->id,trmalloc.next->adr,trmalloc.next->len); #endif if (trmalloc.next->id != -1) { - freet(trmalloc.next->adr); + free((char*) trmalloc.next->adr - bsize); } } } @@ -4145,8 +4643,8 @@ void cut_path(char* fullpath,char* path,char* pname) { a=fullpath+strlen(fullpath)-2; while( (*a!='/') && ( a > fullpath)) a--; if (*a=='/') a++; - strcpy(pname,a); - strncat(path,fullpath,(int) (a - fullpath)); + strcpybuff(pname,a); + strncatbuff(path,fullpath,(int) (a - fullpath)); } } } @@ -4168,8 +4666,12 @@ int ftp_available(void) { -int hts_init(void) { +HTSEXT_API int hts_init(void) { static int hts_init_ok = 0; + + /* Ensure external modules are loaded */ + htspe_init(); + if (!hts_init_ok) { hts_init_ok = 1; // default wrappers @@ -4196,17 +4698,18 @@ int hts_init(void) { /* Initialize the OpensSSL library */ - if (!openssl_ctx) { + if (!openssl_ctx && SSL_is_available) { + if (SSL_load_error_strings) SSL_load_error_strings(); SSL_library_init(); - SSL_load_error_strings(); - ERR_load_crypto_strings(); - ERR_load_SSL_strings(); - SSLeay_add_ssl_algorithms(); + ///if (SSL_load_error_strings) SSL_load_error_strings(); + //if (ERR_load_crypto_strings) ERR_load_crypto_strings(); + // if (ERR_load_SSL_strings) ERR_load_SSL_strings(); ???!!! // OpenSSL_add_all_algorithms(); openssl_ctx = SSL_CTX_new(SSLv23_client_method()); if (!openssl_ctx) { fprintf(stderr, "fatal: unable to initialize TLS: SSL_CTX_new(SSLv23_client_method)\n"); - abort(); + abortLog("unable to initialize TLS: SSL_CTX_new(SSLv23_client_method)"); + assertf("unable to initialize TLS" == NULL); } } #endif @@ -4214,9 +4717,13 @@ int hts_init(void) { /* Init vars and thread-specific values */ hts_initvar(); + /* initialiser structcheck */ + // structcheck_init(1); + return 1; } -int hts_uninit(void) { +HTSEXT_API int hts_uninit(void) { + hts_cache_free(_hts_cache()); hts_freevar(); /* htswrap_free(); */ return 1; |