home *** CD-ROM | disk | FTP | other *** search
- /* ------------------------------------------------------------ */
- /*
- HTTrack Website Copier, Offline Browser for Windows and Unix
- Copyright (C) Xavier Roche, Yann Philippot
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-
- Important notes:
-
- - We hereby ask people using this source NOT to use it in purpose of grabbing
- emails addresses, or collecting any other private information on persons.
- This would disgrace our work, and spoil the many hours we spent on it.
-
-
- This project has been developed by Xavier Roche and Yann Philippot,
- from the company Serianet at Caen, France (http://www.serianet.com)
-
- Please visit our Website: http://www.httrack.com
- */
-
-
- /* ------------------------------------------------------------ */
- /* File: httrack.c subroutines: */
- /* backing system (multiple socket download) */
- /* Author: Xavier Roche */
- /* ------------------------------------------------------------ */
-
- #include "htsback.h"
-
- /* specific definitions */
- #include "htsbase.h"
- #include "htsnet.h"
- #include "htsthread.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- /* END specific definitions */
-
- //#if HTS_WIN
- #include "htsftp.h"
- //#endif
-
- #if HTS_WIN
- #ifndef __cplusplus
- // DOS
- #include <process.h> /* _beginthread, _endthread */
- #endif
- #else
- #endif
-
- #undef test_flush
- #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
-
- // ---
- // routines de backing
- // retourne l'index d'un lien dans un tableau de backing
- int back_index(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
- register int i=0;
- register int index=-1;
- while( i<back_max ) {
- if (back[i].status>=0) // rΘception OU prΩt
- if (strfield2(back[i].url_adr,adr)) {
- if (strcmp(back[i].url_fil,fil)==0) {
- if (index==-1) /* first time we meet, store it */
- index=i;
- else if (strcmp(back[i].url_sav,sav)==0) { /* oops, check sav too */
- index=i;
- return index;
- }
- }
- }
- i++;
- }
- return index;
- }
-
- // nombre d'entrΘes libres dans le backing
- int back_available(lien_back* back,int back_max) {
- int i;
- int nb=0;
- for(i=0;i<back_max;i++)
- if (back[i].status==-1) /* libre */
- nb++;
- return nb;
- }
-
- // retourne estimation de la taille des html et fichiers stockΘs en mΘmoire
- LLint back_incache(lien_back* back,int back_max) {
- int i;
- LLint sum=0;
- for(i=0;i<back_max;i++)
- if (back[i].status!=-1)
- if (back[i].r.adr) // ne comptabilier que les blocs en mΘmoire
- sum+=max(back[i].r.size,back[i].r.totalsize);
- return sum;
- }
-
- // le lien a-t-il ΘtΘ mis en backing?
- HTS_INLINE int back_exist(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
- return (back_index(back,back_max,adr,fil,sav)>=0);
- }
-
- // nombre de sockets en tΓche de fond
- int back_nsoc(lien_back* back,int back_max) {
- int n=0;
- int i;
- for(i=0;i<back_max;i++)
- if (back[i].status>0) // rΘception uniquement
- n++;
-
- return n;
- }
-
- // effacer entrΘe
- int back_delete(lien_back* back,int p) {
- if (p>=0) { // on sait jamais..
- // VΘrificateur d'intΘgritΘ
- #if DEBUG_CHECKINT
- _CHECKINT(&back[p],"Appel back_delete")
- #endif
- #if HTS_DEBUG_CLOSESOCK
- char info[256];
- sprintf(info,"back_delete: #%d\n",p);
- DEBUG_W2(info);
- #endif
-
- // LibΘrer tous les sockets, handles, buffers..
- if (back[p].r.soc!=INVALID_SOCKET) {
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_delete: deletehttp\n");
- #endif
- deletehttp(&back[p].r);
- back[p].r.soc=INVALID_SOCKET;
- }
- if (back[p].r.adr!=NULL) { // reste un bloc α dΘsallouer
- freet(back[p].r.adr);
- back[p].r.adr=NULL;
- }
- if (back[p].chunk_adr!=NULL) { // reste un bloc α dΘsallouer
- freet(back[p].chunk_adr);
- back[p].chunk_adr=NULL;
- back[p].chunk_size=0;
- back[p].is_chunk=0;
- }
- if (back[p].r.is_file) { // fermer fichier entrΘe
- if (back[p].r.fp!=NULL) {
- fclose(back[p].r.fp);
- back[p].r.fp=NULL;
- }
- }
- if (back[p].r.is_write) { // ecriture directe
- if (back[p].r.out!=NULL) { // fermer fichier sortie
- fclose(back[p].r.out);
- back[p].r.out=NULL;
- }
-
- /* Θcrire date "remote" */
- if (strnotempty(back[p].url_sav)) // normalement existe si on a un fichier de sortie
- if (strnotempty(back[p].r.lastmodified)) // last-modified existe
- if (fexist(back[p].url_sav)) // ainsi que le fichier
- set_filetime_rfc822(back[p].url_sav,back[p].r.lastmodified);
-
- /* executer commande utilisateur aprΦs chargement du fichier */
- usercommand(0,NULL,back[p].url_sav);
- back[p].r.is_write=0;
- }
-
- // Tout nettoyer
- bzero((char *)(&back[p]),sizeof(lien_back));
- back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
-
- // Le plus important: libΘrer le champ
- back[p].status=-1;
- }
- return 0;
- }
-
- // ajouter un lien en backing
- int back_add(lien_back* back,int back_max,httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* referer_adr,char* referer_fil,int test) {
- int p=0;
-
- // vΘrifier cohΘrence de adr et fil (non vide!)
- if (strnotempty(adr)==0) {
- if ((opt->debug>1) && (opt->errlog!=NULL)) {
- fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: adr is empty for back_add"LF);
- }
- return -1; // erreur!
- }
- if (strnotempty(fil)==0) {
- if ((opt->debug>1) && (opt->errlog!=NULL)) {
- fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: fil is empty for back_add"LF);
- }
- return -1; // erreur!
- }
- // FIN vΘrifier cohΘrence de adr et fil (non vide!)
-
- // rechercher emplacement
- while((p<back_max) && back[p].status!=-1) p++;
- if (back[p].status==-1) { // ok on a de la place
- back[p].send_too[0]='\0'; // Θventuels paramΦtres supplΘmentaires α transmettre au serveur
-
- // ne sert α rien normalement
- if (back[p].r.soc!=INVALID_SOCKET) {
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_add: deletehttp\n");
- #endif
- deletehttp(&back[p].r);
- }
-
- // effacer r
- bzero((char*) &(back[p].r), sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
-
- // crΘer entrΘe
- strcpy(back[p].url_adr,adr);
- strcpy(back[p].url_fil,fil);
- strcpy(back[p].url_sav,save);
- // copier referer si besoin
- strcpy(back[p].referer_adr,"");
- strcpy(back[p].referer_fil,"");
- if ((referer_adr) && (referer_fil)) { // existe
- if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) { // non vide
- if (referer_adr[0]!='!') { // non dΘtruit
- if (strcmp(referer_adr,"file://")) { // PAS file://
- if (strcmp(referer_adr,"primary")) { // pas referer 1er lien
- strcpy(back[p].referer_adr,referer_adr);
- strcpy(back[p].referer_fil,referer_fil);
- }
- }
- }
- }
- }
- // sav ne sert α rien pour le moment
- back[p].r.size=0; // rien n'a encore ΘtΘ chargΘ
- back[p].r.soc=INVALID_SOCKET; // pas de socket
- back[p].r.adr=NULL; // pas de bloc de mΘmoire
- back[p].r.is_write=0; // α priori stockage en mΘmoire
- back[p].maxfile_html=opt->maxfile_html;
- back[p].maxfile_nonhtml=opt->maxfile_nonhtml;
- back[p].testmode=test; // mode test?
- if (!opt->http10) // option "forcer 1.0" dΘsactivΘe
- back[p].http11=1; // autoriser http/1.1
- back[p].head_request=0;
- if (strcmp(back[p].url_sav,BACK_ADD_TEST)==0) // HEAD
- back[p].head_request=1;
- else if (strcmp(back[p].url_sav,BACK_ADD_TEST2)==0) // test en GET
- back[p].head_request=2; // test en get
-
- // tester cache
- if ((strcmp(adr,"file://")) /* pas fichier */
- && ( (!test) || (cache->type==1) ) /* cache prioritaire, laisser passer en test! */
- && ( (strnotempty(save)) || (strcmp(fil,"/robots.txt")==0) ) ) { // si en test on ne doit pas utiliser le cache sinon telescopage avec le 302..
- //if ((!test) && (strcmp(adr,"file://"))
- //if ((!test) && (strncmp(adr,"ftp://",6)) && (strcmp(adr,"file://"))
- #if HTS_FAST_CACHE
- int hash_pos;
- int hash_pos_return=0;
- #else
- char* a=NULL;
- #endif
- #if HTS_FAST_CACHE
- if (cache->hash) {
- #else
- if (cache->use) {
- #endif
- char buff[HTS_URLMAXSIZE*4];
- #if HTS_FAST_CACHE
- strcpy(buff,adr); strcat(buff,fil);
- hash_pos_return=inthash_read((hash_chain**)cache->hash,cache->hash_size,buff,(long int*)&hash_pos);
- #else
- buff[0]='\0'; strcat(buff,"\n"); strcat(buff,adr); strcat(buff,"\n"); strcat(buff,fil); strcat(buff,"\n");
- a=strstr(cache->use,buff);
- #endif
-
- // Ok, notΘ en cache->. mais bien prΘsent dans le cache ou sur disque?
- #if HTS_FAST_CACHE
- if (hash_pos_return) {
- #else
- if (a) {
- #endif
- if (!test) { // non mode test
- #if HTS_FAST_CACHE
- int pos=hash_pos;
- #else
- int pos=-1;
- a+=strlen(buff);
- sscanf(a,"%d",&pos); // lire position
- #endif
- if (pos<0) { // pas de mise en cache data, vΘrifier existence
- if (fsize(antislash(save)) <= 0) { // fichier existe pas ou est vide!
- #if HTS_FAST_CACHE
- hash_pos_return=0;
- #else
- a=NULL;
- #endif
- // dΘvalider car non prΘsent sur disque dans structure originale!!!
- // sinon, le fichier est ok α priori, mais on renverra un if-modified-since pour
- // en Ωtre s√r
- if (opt->norecatch) { // tester norecatch
- if (!fexist(antislash(save))) { // fichier existe pas mais dΘclarΘ: on l'a effacΘ
- FILE* fp=fopen(antislash(save),"wb");
- if (fp) fclose(fp);
- if (opt->log!=NULL) {
- fspc(opt->log,"warning"); fprintf(opt->log,"File must have been erased by user, ignoring: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
- }
- }
- }
- }
- }
- }
- }
- //
- } else
- #if HTS_FAST_CACHE
- hash_pos_return=0;
- #else
- a=NULL;
- #endif
-
- // Existe pas en cache, ou bien pas de cache prΘsent
- #if HTS_FAST_CACHE
- if (hash_pos_return) { // OK existe en cache (et donnΘes aussi)!
- #else
- if (a!=NULL) { // OK existe en cache (et donnΘes aussi)!
- #endif
- if (cache->type==1) { // cache prioritaire (pas de test if-modified..)
- // dans ce cas on peut Θgalement lire des rΘponses cachΘes comme 404,302...
- // lire dans le cache
- if (!test)
- back[p].r=cache_read(opt,cache,adr,fil,save);
- else
- back[p].r=cache_read(opt,cache,adr,fil,NULL); // charger en tΩte uniquement du cache
- if (!back[p].r.location)
- back[p].r.location=back[p].location_buffer;
- else { /* recopier */
- strcpy(back[p].location_buffer,back[p].r.location);
- back[p].r.location=back[p].location_buffer;
- }
-
- /* Interdiction taille par le wizard? --> dΘtruire */
- if (back[p].r.statuscode != -1) { // pas d'erreur de lecture
- if (!back_checksize(opt,&back[p],0)) {
- back[p].status=0; // FINI
- back[p].r.statuscode=-1;
- if (!back[p].testmode)
- strcpy(back[p].r.msg,"Cached file skipped (too big)");
- else
- strcpy(back[p].r.msg,"Test: Cached file skipped (too big)");
- return 0;
- }
- }
-
- if (back[p].r.statuscode != -1) { // pas d'erreur de lecture
- if ((opt->debug>0) && (opt->log!=NULL)) {
- if (!test) {
- fspc(opt->log,"debug"); fprintf(opt->log,"File immediately loaded from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
- } else {
- fspc(opt->log,"debug"); fprintf(opt->log,"File immediately tested from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
- }
- }
- back[p].r.notmodified=1; // fichier non modifiΘ
- back[p].status=0; // OK prΩt
- //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
- return 0;
- } else { // erreur
- // effacer r
- bzero((char*) &(back[p].r), sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
- // et continuer (chercher le fichier)
- }
-
- } else if (cache->type==2) { // si en cache, demander de tester If-Modified-Since
- htsblk* r=cache_header(opt,cache,adr,fil);
-
- /* Interdiction taille par le wizard? */
- {
- LLint save_totalsize=back[p].r.totalsize;
- back[p].r.totalsize=r->totalsize;
- if (!back_checksize(opt,&back[p],1)) {
- r=NULL;
- //
- back[p].status=0; // FINI
- deletehttp(&back[p].r); back[p].r.soc=INVALID_SOCKET;
- if (!back[p].testmode)
- strcpy(back[p].r.msg,"File too big");
- else
- strcpy(back[p].r.msg,"Test: File too big");
- return 0;
- }
- back[p].r.totalsize=save_totalsize;
- }
-
- if (r) {
- if (r->statuscode==200) { // uniquement des 200 (OK)
- if (strnotempty(r->etag)) { // ETag (RFC2616)
- if (strnotempty(r->lastmodified))
- sprintf(back[p].send_too,"If-None-Match: %s\r\nIf-Modified-Since: %s\r\n",r->etag,r->lastmodified);
- else
- sprintf(back[p].send_too,"If-None-Match: %s\r\n",r->etag);
- }
- else if (strnotempty(r->lastmodified))
- sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",r->lastmodified);
- else if (strnotempty(cache->lastmodified))
- sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
- } else if (strnotempty(cache->lastmodified))
- sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
- }
- #if DEBUGCA
- printf("..is modified test %s\n",back[p].send_too);
- #endif
- }
- // Okay, pas trouvΘ dans le cache
- // Et si le fichier existe sur disque?
- // Pas dans le cache: fichier n'a pas ΘtΘ transfΘrΘ du tout, donc pas sur disque?
- } else {
- if (fexist(save)) { // fichier existe? aghl!
- LLint sz=fsize(save);
- // Bon, lα il est possible que le fichier ait ΘtΘ partiellement transfΘrΘ
- // (s'il l'avait ΘtΘ en totalitΘ il aurait ΘtΘ inscrit dans le cache ET existerait sur disque)
- // PAS de If-Modified-Since, on a pas connaissance des donnΘes α la date du cache
- // On demande juste les donnΘes restantes si le date est valide (206), tout sinon (200)
- if ((ishtml(save) != 1) && (ishtml(back[p].url_fil)!=1)) { // NON HTML (liens changΘs!!)
- if (sz>0) { // Fichier non vide? (question bΩte, sinon on transfert tout!)
- if (strnotempty(cache->lastmodified)) { /* pas de If-.. possible */
- /*if ( (!opt->http10) && (strnotempty(cache->lastmodified)) ) { */ /* ne pas forcer 1.0 */
- #if DEBUGCA
- printf("..if unmodified since %s size "LLintP"\n",cache->lastmodified,(LLint)sz);
- #endif
- if ((opt->debug>1) && (opt->log!=NULL)) {
- fspc(opt->log,"debug"); fprintf(opt->log,"File partially present ("LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
- }
-
- /* impossible - don't have etag or date
- if (strnotempty(back[p].r.etag)) { // ETag (RFC2616)
- sprintf(back[p].send_too,"If-None-Match: %s\r\n",back[p].r.etag);
- back[p].http11=1; // En tΩte 1.1
- } else if (strnotempty(back[p].r.lastmodified)) {
- sprintf(back[p].send_too,"If-Unmodified-Since: %s\r\n",back[p].r.lastmodified);
- back[p].http11=1; // En tΩte 1.1
- } else
- */
- if (strlen(cache->lastmodified)) {
- sprintf(back[p].send_too,
- "If-Unmodified-Since: %s\r\nRange: bytes="LLintP"-\r\n"
- ,cache->lastmodified,(LLint)sz);
- back[p].http11=1; // En tΩte 1.1
- back[p].range_req_size=sz;
- } else {
- if ((opt->debug>0) && (opt->errlog!=NULL)) {
- fspc(opt->log,"warning"); fprintf(opt->log,"Could not find timestamp for partially present file, restarting (lost "LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
- }
- }
-
- } else {
- if ((opt->debug>0) && (opt->errlog!=NULL)) {
- fspc(opt->errlog,"warning");
- /*
- if (opt->http10)
- fprintf(opt->errlog,"File partially present (%d bytes) retransfered due to HTTP/1.0 settings: %s%s"LF,sz,back[p].url_adr,back[p].url_fil);
- else
- */
- fprintf(opt->errlog,"File partially present ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil);
- test_flush;
- }
- /* Sinon requΩte normale... */
- back[p].http11=0;
- }
- } else if (opt->norecatch) { // tester norecatch
- filenote(save,NULL); // ne pas purger tout de mΩme
- back[p].status=0; // OK prΩt
- back[p].r.statuscode=-1; // erreur
- strcpy(back[p].r.msg,"Null-size file not recaught");
- return 0;
- }
- } else {
- if ((opt->debug>0) && (opt->errlog!=NULL)) {
- fspc(opt->errlog,"warning");
- fprintf(opt->errlog,"HTML file ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil);
- test_flush;
- }
- /* Sinon requΩte normale... */
- back[p].http11=0;
- }
- }
- }
- }
-
-
- {
- ///htsblk r; non directement dans la structure-rΘponse!
- T_SOC soc;
-
- // ouvrir liaison, envoyer requΦte
- // ne pas traiter ou recevoir l'en tΩte immΘdiatement
- bzero((char*) &(back[p].r), sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
- // recopier proxy
- bcopy((char*) &opt->proxy,(char*) &(back[p].r.req.proxy), sizeof(opt->proxy));
- // et user-agent
- strcpy(back[p].r.req.user_agent,opt->user_agent);
- back[p].r.req.user_agent_send=opt->user_agent_send;
- // et http11
- back[p].r.req.http11=back[p].http11;
-
- // mode ftp, court-circuit!
- if (strncmp(back[p].url_adr,"ftp://",6)==0) {
- if (back[p].testmode) {
- if ((opt->debug>1) && (opt->errlog!=NULL)) {
- fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: forbidden test with ftp link for back_add"LF);
- }
- return -1; // erreur pas de test permis
- }
- if (!(back[p].r.req.proxy.active && opt->ftp_proxy)) { // connexion directe, gΘrΘe en thread
- back[p].status=1000; // connexion ftp
- #if USE_BEGINTHREAD
- launch_ftp(&(back[p]));
- #else
- {
- char nid[32];
- sprintf(nid,"htsftp%d-in_progress.lock",p);
- strcpy(back[p].location_buffer,fconcat(opt->path_log,nid));
- }
- launch_ftp(&(back[p]),back[p].location_buffer,opt->exec);
- #endif
- return 0;
- }
- }
-
- #if HTS_XGETHOST
- #if HDEBUG
- printf("back_solve..\n");
- #endif
- back[p].status=101; // tentative de rΘsolution du nom de host
- soc=INVALID_SOCKET; // pas encore ouverte
- back_solve(&back[p]); // prΘparer
- if (host_wait(&back[p])) { // prΩt, par ex fichier ou dispo dans dns
- #if HDEBUG
- printf("ok, dns cache ready..\n");
- #endif
- soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
- if (soc==INVALID_SOCKET) {
- back[p].status=0; // fini, erreur
- }
- }
- //
- #else
- //
- #if CNXDEBUG
- printf("XFopen..\n");
- #endif
-
- if (strnotempty(back[p].send_too)) // envoyer un if-modified-since
- #if HTS_XCONN
- soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
- #else
- soc=http_xfopen(0,0,1,back[p].send_too,adr,fil,&(back[p].r));
- #endif
- else
- #if HTS_XCONN
- soc=http_xfopen(test,0,0,NULL,adr,fil,&(back[p].r));
- #else
- soc=http_xfopen(test,0,1,NULL,adr,fil,&(back[p].r));
- #endif
- #endif
- if (opt->timeout>0) { // gestion du opt->timeout
- back[p].timeout=opt->timeout;
- back[p].timeout_refresh=time_local();
- } else {
- back[p].timeout=-1; // pas de gestion (default)
- }
-
- if (opt->rateout>0) { // gestion d'un taux minimum de transfert tolΘrΘ
- back[p].rateout=opt->rateout;
- back[p].rateout_time=time_local();
- } else {
- back[p].rateout=-1; // pas de gestion (default)
- }
-
- // Note: on charge les code-page erreurs (erreur 404, etc) dans le cas o∙ cela est
- // rattrapable (exemple: 301,302 moved xxx -> refresh sur la page!)
- //if ((back[p].statuscode!=200) || (soc<0)) { // ERREUR HTTP/autre
-
- #if CNXDEBUG
- printf("Xfopen ok, poll..\n");
- #endif
-
- #if HTS_XGETHOST
- if (soc!=INVALID_SOCKET)
- if (back[p].status==101) { // pas d'erreur
- if (!back[p].r.is_file)
- back[p].status=100; // connexion en cours
- else
- back[p].status=1; // fichier
- }
-
- #else
- if (soc==INVALID_SOCKET) { // erreur socket
- back[p].status=0; // FINI
- //if (back[p].soc!=INVALID_SOCKET) deletehttp(back[p].soc);
- back[p].r.soc=INVALID_SOCKET;
- } else {
- if (!back[p].r.is_file)
- #if HTS_XCONN
- back[p].status=100; // connexion en cours
- #else
- back[p].status=99; // chargement en tΩte en cours
- #endif
- else
- back[p].status=1; // chargement fichier
- #if BDEBUG==1
- printf("..loading header\n");
- #endif
- }
- #endif
-
- }
-
-
- // note: si il y a erreur (404,etc) status=2 (terminΘ/Θchec) mais
- // le lien est considΘrΘ comme traitΘ
- //if (back[p].soc<0) // erreur
- // return -1;
-
- return 0;
- } else {
- if ((opt->debug>1) && (opt->errlog!=NULL)) {
- fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: no space left in stack for back_add"LF);
- }
- return -1; // plus de place
- }
- }
-
-
-
- #if HTS_XGETHOST
- #if USE_BEGINTHREAD
- // lancement multithread du robot
- PTHREAD_TYPE Hostlookup(void* iadr_p) {
- char iadr[256];
- t_dnscache* cache=_hts_cache(); // adresse du cache
- t_hostent* hp;
- int error_found=0;
-
- // recopier (aprΦs id:pass)
- #if DEBUGDNS
- printf("resolv in background: %s\n",jump_identification(iadr_p));
- #endif
- strcpy(iadr,jump_identification(iadr_p));
- // couper Θventuel :
- {
- char *a;
- if ( (a=strchr(iadr,':')) )
- *a='\0';
- }
- freet(iadr_p);
-
- // attendre que le cache dns soit prΩt
- while(_hts_lockdns(-1)); // attendre libΘration
- _hts_lockdns(1); // locker
- while(cache->n) {
- if (strcmp(cache->iadr,iadr)==0) {
- error_found=1;
- }
- cache=cache->n; // calculer queue
- }
- if (strcmp(cache->iadr,iadr)==0) {
- error_found=1;
- }
-
- if (!error_found) {
- // en gros copie de hts_gethostbyname sans le return
- cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
- if (cache->n!=NULL) {
- strcpy(cache->n->iadr,iadr);
- cache->n->host_length=0; /* pour le moment rien */
- cache->n->n=NULL;
- _hts_lockdns(0); // dΘlocker
-
- /* resolve */
- #if DEBUGDNS
- printf("gethostbyname() in progress for %s\n",iadr);
- #endif
- hp=gethostbyname(iadr); // rΘsolution IP
-
- /* okay, result */
- if (hp!=NULL) {
- bcopy(hp->h_addr,cache->n->host_addr,hp->h_length); // write first
- cache->n->host_length=hp->h_length; // then write this
- } else {
- cache->n->host_addr[0]='\0';
- cache->n->host_length=-1; // dΘclarer erreur dans le dns
- }
- } else
- _hts_lockdns(0); // dΘlocker
- } else {
- #if DEBUGDNS
- printf("aborting resolv for %s (found)\n",iadr);
- #endif
- _hts_lockdns(0); // dΘlocker
- }
- // fin de copie de hts_gethostbyname
-
- #if DEBUGDNS
- printf("quitting resolv for %s (result: %d)\n",iadr,(cache->n!=NULL)?cache->n->host_length:(-999));
- #endif
-
- return PTHREAD_RETURN; /* _endthread implied */
- }
- #endif
-
- // attendre que le host (ou celui du proxy) ait ΘtΘ rΘsolu
- // si c'est un fichier, la rΘsolution est immΘdiate
- // idem pour ftp://
- void back_solve(lien_back* back) {
- if ((strcmp(back->url_adr,"file://")) && (strncmp(back->url_adr,"ftp://",6))) {
- //## if (back->url_adr[0]!=lOCAL_CHAR) { // qq chose α prΘparer
- char* a;
- if (!(back->r.req.proxy.active))
- a=back->url_adr;
- else
- a=back->r.req.proxy.name;
- if (!hts_dnstest(a)) { // non encore testΘ!..
- // inscire en thread
- #if HTS_WIN
- // Windows
- #if USE_BEGINTHREAD
- {
- char* p = calloct(strlen(a)+2,1);
- if (p) {
- strcpy(p,a);
- _beginthread( Hostlookup , 0, p );
- }
- }
- #else
- /*t_hostent* h=*/
- /*hts_gethostbyname(a);*/ // calcul
- #endif
- #else
- #if USE_BEGINTHREAD
- char* p = calloct(strlen(a)+2,1);
- if (p) {
- strcpy(p,a);
- _beginthread( Hostlookup , 0, p );
- }
- #else
- // Sous Unix, le gethostbyname() est bloquant..
- /*t_hostent* h=*/
- /*hts_gethostbyname(a);*/ // calcul
- #endif
- #endif
- }
- }
- }
-
- // dΘtermine si le host a pu Ωtre rΘsolu
- int host_wait(lien_back* back) {
- if ((strcmp(back->url_adr,"file://")) && (strncmp(back->url_adr,"ftp://",6))) {
- //## if (back->url_adr[0]!=lOCAL_CHAR) {
- if (!(back->r.req.proxy.active)) {
- return (hts_dnstest(back->url_adr));
- } else {
- return (hts_dnstest(back->r.req.proxy.name));
- }
- } else return 1; // prΩt, fichier local
- }
- #endif
-
-
-
- // attente (gestion des buffers des sockets)
- void back_wait(lien_back* back,int back_max,httrackp* opt,cache_back* cache,double stat_timestart) {
- int i;
- T_SOC nfds=INVALID_SOCKET;
- fd_set fds,fds_c,fds_e; // fds pour lecture, connect (write), et erreur
- struct timeval tv;
- int do_wait=0;
- int gestion_timeout=0;
- int busy=0; // pas de donnΘes pour le moment
- #if HTS_ANALYSTE
- int max_loop=8; // nombre de boucles max α parcourir..
- int max_loop_chk=0;
- #else
- int max_loop=8; // nombre de boucles max α parcourir..
- #endif
-
-
- // recevoir tant qu'il y a des donnΘes (avec un maximum de max_loop boucles)
- do_wait=0;
- gestion_timeout=0;
- do {
- int max_c;
- busy=0;
-
- check_rate(stat_timestart,opt->maxrate); // vΘrifier taux de transfert
- // inscrire les sockets actuelles, et rechercher l'ID la plus ΘlevΘe
- FD_ZERO(&fds);
- FD_ZERO(&fds_c);
- FD_ZERO(&fds_e);
-
- max_c=1;
- for(i=0;i<back_max;i++) {
-
- // en cas de gestion du connect prΘemptif
- #if HTS_XCONN
- if (back[i].status==100) { // connexion
- do_wait=1;
-
- // noter socket write
- FD_SET(back[i].r.soc,&fds_c);
-
- // noter socket erreur
- FD_SET(back[i].r.soc,&fds_e);
-
- // calculer max
- if (max_c) {
- max_c=0;
- nfds=back[i].r.soc;
- } else if (back[i].r.soc>nfds) {
- // ID socket la plus ΘlevΘe
- nfds=back[i].r.soc;
- }
-
- } else
- #endif
- #if HTS_XGETHOST
- if (back[i].status==101) { // attente
- // rien α faire..
- } else
- #endif
- // poll pour la lecture sur les sockets
- if ((back[i].status>0) && (back[i].status<100)) { // en rΘception http
-
- #if BDEBUG==1
- //printf("....socket in progress: %d\n",back[i].r.soc);
- #endif
- // non local et non ftp
- if (strncmp(back[i].url_adr,"file://",7)) {
- //## if (back[i].url_adr[0]!=lOCAL_CHAR) {
-
- // vΘrification de sΘcuritΘ
- if ((back[i].r.soc!=INVALID_SOCKET) && (!back[i].r.is_file)) { // hey, you never know..
- do_wait=1;
-
- // noter socket read
- FD_SET(back[i].r.soc,&fds);
-
- // noter socket error
- FD_SET(back[i].r.soc,&fds_e);
-
- // calculer max
- if (max_c) {
- max_c=0;
- nfds=back[i].r.soc;
- } else if (back[i].r.soc>nfds) {
- // ID socket la plus ΘlevΘe
- nfds=back[i].r.soc;
- }
- }
- #if WIDE_DEBUG
- else {
- DEBUG_W("PANIC!!! Socket is invalid in a poll test!\n");
- }
- #endif
-
- }
-
- }
- }
- nfds++;
-
- if (do_wait) { // attendre
- // temps d'attente max: 2.5 seconde
- tv.tv_sec=HTS_SOCK_SEC;
- tv.tv_usec=HTS_SOCK_MS;
-
- #if BDEBUG==1
- printf("..select\n");
- #endif
-
- // poller les sockets-attention au noyau sous Unix..
- #if HTS_WIDE_DEBUG
- DEBUG_W("select\n");
- #endif
- select(nfds,&fds,&fds_c,&fds_e,&tv);
- #if HTS_WIDE_DEBUG
- DEBUG_W("select done\n");
- #endif
- }
-
- // recevoir les donnΘes arrivΘes
- for(i=0;i<back_max;i++) {
-
- if (back[i].status>0) {
- if ((back[i].r.soc!=INVALID_SOCKET) && (!back[i].r.is_file)) { // hey, you never know..
- int err;
- // erreur?
- err=FD_ISSET(back[i].r.soc,&fds_e);
- if (err) {
- if (back[i].r.soc!=INVALID_SOCKET) {
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait: deletehttp\n");
- #endif
- deletehttp(&back[i].r);
- }
- back[i].r.soc=INVALID_SOCKET;
- back[i].r.statuscode=-4;
- if (back[i].status==100)
- strcpy(back[i].r.msg,"Connect Error");
- else
- strcpy(back[i].r.msg,"Receive Error");
- back[i].status=0; // terminΘ
- }
- }
- }
-
- // ---- FLAG WRITE MIS A UN?: POUR LE CONNECT
- if (back[i].status==100) { // attendre connect
- int dispo=0;
- // vΘrifier l'existance de timeout-check
- if (!gestion_timeout)
- if (back[i].timeout>0)
- gestion_timeout=1;
-
- // connectΘ?
- dispo=FD_ISSET(back[i].r.soc,&fds_c);
- if (dispo) { // ok
- busy=1;
- #if BDEBUG==1
- printf("..connect ok on socket %d\n",back[i].r.soc);
- #endif
- /* limit nb. connections/seconds to avoid server overload */
- if (opt->maxconn>0) {
- Sleep(1000/opt->maxconn);
- }
-
- if (back[i].timeout>0) { // refresh timeout si besoin est
- back[i].timeout_refresh=time_local();
- }
- if (back[i].rateout>0) { // le taux de transfert de base sur le dΘbut de la connexion
- back[i].rateout_time=time_local();
- }
- // envoyer header
- //if (strcmp(back[i].url_sav,BACK_ADD_TEST)!=0) // vrai get
- if (!back[i].head_request)
- http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);
- else if (back[i].head_request==2) // test en GET!
- http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);
- else // test!
- http_sendhead(opt->cookie,1,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);
- back[i].status=99; // attendre en tΩte maintenant
- }
-
- // attente gethostbyname
- }
- #if HTS_XGETHOST
- else if (back[i].status==101) { // attendre gethostbyname
- #if DEBUGDNS
- //printf("status 101 for %s\n",back[i].url_adr);
- #endif
-
- if (!gestion_timeout)
- if (back[i].timeout>0)
- gestion_timeout=1;
-
- if (host_wait(&back[i])) { // prΩt
- back[i].status=100; // attente connexion
- if (back[i].timeout>0) { // refresh timeout si besoin est
- back[i].timeout_refresh=time_local();
- }
- if (back[i].rateout>0) { // le taux de transfert de base sur le dΘbut de la connexion
- back[i].rateout_time=time_local();
- }
-
- back[i].r.soc=http_xfopen(0,0,0,back[i].send_too,back[i].url_adr,back[i].url_fil,&(back[i].r));
- if (back[i].r.soc==INVALID_SOCKET) {
- back[i].status=0; // fini, erreur
- if (back[i].r.soc!=INVALID_SOCKET) {
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(2): deletehttp\n");
- #endif
- deletehttp(&back[i].r);
- }
- back[i].r.soc=INVALID_SOCKET;
- back[i].r.statuscode=-5;
- if (strnotempty(back[i].r.msg)==0)
- strcpy(back[i].r.msg,"Unable to establish host name");
- }
- }
-
-
- // ---- FLAG READ MIS A UN?: POUR LA RECEPTION
- }
- #endif
- #if USE_BEGINTHREAD
- // ..rien α faire, c'est magic les threads
- #else
- else if (back[i].status==1000) { // en rΘception ftp
- if (!fexist(back[i].location_buffer)) { // terminΘ
- FILE* fp;
- fp=fopen(fconcat(back[i].location_buffer,".ok"),"rb");
- if (fp) {
- int j=0;
- fscanf(fp,"%d ",&(back[i].r.statuscode));
- while(!feof(fp)) {
- int c = fgetc(fp);
- if (c!=EOF)
- back[i].r.msg[j++]=c;
- }
- back[i].r.msg[j++]='\0';
- fclose(fp);
- remove(fconcat(back[i].location_buffer,".ok"));
- strcpy(fconcat(back[i].location_buffer,".ok"),"");
- } else {
- strcpy(back[i].r.msg,"Unknown ftp result, check if file is ok");
- back[i].r.statuscode=-1;
- }
- back[i].status=0;
- }
- }
- #endif
- else if ((back[i].status>0) && (back[i].status<1000)) { // en rΘception http
- int dispo=0;
-
- // vΘrifier l'existance de timeout-check
- if (!gestion_timeout)
- if (back[i].timeout>0)
- gestion_timeout=1;
-
- // donnΘes dispo?
- //## if (back[i].url_adr[0]!=lOCAL_CHAR)
- if (strcmp(back[i].url_adr,"file://"))
- dispo=FD_ISSET(back[i].r.soc,&fds);
- else dispo=1;
-
- if (dispo) { // donnΘes dispo
- LLint retour_fread;
- busy=1; // on rΘcupΦre encore
- #if BDEBUG==1
- printf("..data available on socket %d\n",back[i].r.soc);
- #endif
-
-
- #if HTS_SKIP_FULL_RANGE
- // range_req_size : we have request for a partial file
- // with a 'Range: NNN-'
- // and received a complete file (200), with 'Content-length: NNN'
- // it might be possible that we had the complete file
- // this is the case in *most* cases
- if (back[i].r.is_write==0) { // mode mΘmoire
- if (back[i].r.adr==NULL) { // rien n'a ΘtΘ Θcrit
- if (!back[i].testmode) { // pas mode test
- if (strnotempty(back[i].url_sav)) {
- if (strcmp(back[i].url_fil,"/robots.txt")) {
- if (back[i].r.statuscode==200) { // 'OK'
- if (!is_hypertext_mime(back[i].r.contenttype)) { // pas HTML
-
- if (back[i].r.statuscode==200) { // "OK"
- if (back[i].range_req_size>0) { // but Range: requested
- if (back[i].range_req_size == back[i].r.totalsize) { // And same size
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(skip_range): deletehttp\n");
- #endif
- deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
- back[i].status=0; // READY
- back[i].r.size=back[i].r.totalsize;
- filenote(back[i].url_sav,NULL);
- // back[i].r.statuscode=304; // NOT MODIFIED
- if ((opt->debug>1) && (opt->log!=NULL)) {
- fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete, breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
- }
- }
- }
- }
-
- }
- }
- }
- }
- }
- }
- }
- #endif
-
- #if HTS_DIRECTDISK
- // Court-circuit:
- // Peut-on stocker le fichier directement sur disque?
- // Ahh que ca serait vachement mieux et que ahh que la mΘmoire vous dit merci!
- if (back[i].status) {
- if (back[i].r.is_write==0) { // mode mΘmoire
- if (back[i].r.adr==NULL) { // rien n'a ΘtΘ Θcrit
- if (!back[i].testmode) { // pas mode test
- if (strnotempty(back[i].url_sav)) {
- if (strcmp(back[i].url_fil,"/robots.txt")) {
- if (back[i].r.statuscode==200) { // 'OK'
- if (!is_hypertext_mime(back[i].r.contenttype)) { // pas HTML
- if (opt->getmode&2) { // on peut ecrire des non html
- back[i].r.is_write=1; // Θcrire
- back[i].r.out=filecreate(back[i].url_sav);
- #if HDEBUG
- printf("direct-disk: %s\n",back[i].url_sav);
- #endif
- if ((opt->debug>1) && (opt->log!=NULL)) {
- fspc(opt->log,"debug"); fprintf(opt->log,"File received from net to disk: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
- }
-
- if (back[i].r.out==NULL) {
- back[i].r.is_write=0; // erreur, abandonner
- #if HDEBUG
- printf("..error!\n");
- #endif
- }
- #if HTS_WIN==0
- else chmod(back[i].url_sav,HTS_ACCESS_FILE);
- #endif
- } else { // on coupe tout!
- if ((opt->debug>1) && (opt->log!=NULL)) {
- fspc(opt->log,"debug"); fprintf(opt->log,"File cancelled (non HTML): %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
- }
- back[i].status=0; // terminΘ
- if (!back[i].testmode)
- back[i].r.statuscode=-10; // EUHH CANCEL
- else
- back[i].r.statuscode=-10; // "TEST OK"
- if (back[i].r.soc!=INVALID_SOCKET) {
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(3): deletehttp\n");
- #endif
- deletehttp(&back[i].r);
- }
- back[i].r.soc=INVALID_SOCKET;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- #endif
-
- // rΘception de donnΘes depuis socket ou fichier
- if (back[i].status) {
- if (back[i].status==99) // recevoir caractΦre par caractΦre
- retour_fread=http_xfread1(&(back[i].r),0);
- else if (back[i].status==98) { // recevoir longueur chunk en hexa caractΦre par caractΦre
- // backuper pour lire dans le buffer chunk
- htsblk r;
- bcopy((char*) &(back[i].r), (char*) &r, sizeof(htsblk));
- back[i].r.is_write=0; // mΘmoire
- back[i].r.adr=back[i].chunk_adr; // adresse
- back[i].r.size=back[i].chunk_size; // taille taille chunk
- back[i].r.totalsize=-1; // total inconnu
- back[i].r.out=NULL;
- back[i].r.is_file=0;
- //
- retour_fread=http_xfread1(&(back[i].r),0);
- // modifier et restaurer
- back[i].chunk_adr=back[i].r.adr; // adresse
- back[i].chunk_size=back[i].r.size; // taille taille chunk
- bcopy((char*) &r, (char*) &(back[i].r), sizeof(htsblk)); // restaurer vΘritable r
- }
- else if (back[i].is_chunk) { // attention chunk, limiter taille α lire
- #if CHUNKDEBUG==1
- printf("read %d bytes\n",(int)min(back[i].r.totalsize-back[i].r.size,TAILLE_BUFFER));
- #endif
- retour_fread=http_xfread1(&(back[i].r),(int)min(back[i].r.totalsize-back[i].r.size,TAILLE_BUFFER));
- } else
- retour_fread=http_fread1(&(back[i].r));
- } else
- retour_fread=-1; // interruption ou annulation interne (peut ne pas Ωtre une erreur)
-
- // Si rΘception chunk, tester si on est pas α la fin!
- if (back[i].status==1) {
- if (back[i].is_chunk) { // attendre prochain chunk
- if (back[i].r.size==back[i].r.totalsize) { // fin chunk!
- //printf("chunk end at %d\n",back[i].r.size);
- back[i].status=98; // prochain chunk
- if (back[i].chunk_adr!=NULL) { freet(back[i].chunk_adr); back[i].chunk_adr=NULL; } back[i].chunk_size=0;
- retour_fread=0; // pas d'erreur
- #if CHUNKDEBUG==1
- printf("waiting for next chunk header (soc %d)..\n",back[i].r.soc);
- #endif
- }
- }
- }
-
- if (retour_fread==-1) { // erreur rΘception
- back[i].status=0; // terminΘ
- if (back[i].r.soc!=INVALID_SOCKET) {
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(4): deletehttp\n");
- #endif
- deletehttp(&back[i].r);
- }
- back[i].r.soc=INVALID_SOCKET;
- #if CHUNKDEBUG==1
- if (back[i].is_chunk)
- printf("must be the last chunk for %s (connection closed) - %d/%d\n",back[i].url_fil,back[i].r.size,back[i].r.totalsize);
- #endif
- //if ((back[i].r.statuscode==-1) && (strnotempty(back[i].r.msg)==0)) {
- if ((back[i].r.statuscode<0) && (strnotempty(back[i].r.msg)==0)) {
- #if HDEBUG
- printf("error interruped: %s\n",back[i].r.adr);
- #endif
- if (back[i].r.size>0)
- strcat(back[i].r.msg,"Interrupted transfer");
- else
- strcat(back[i].r.msg,"No data (connection closed)");
- back[i].r.statuscode=-4;
- }
-
- if (back[i].r.totalsize>0) { // tester totalsize
- //if ((back[i].r.totalsize>0) && (back[i].status==99)) { // tester totalsize
- if (back[i].r.totalsize!=back[i].r.size) { // pas la mΩme!
- if (!opt->tolerant) {
- //#if HTS_CL_IS_FATAL
- if (back[i].r.adr) freet(back[i].r.adr); back[i].r.adr=NULL;
- if (back[i].r.size<back[i].r.totalsize)
- back[i].r.statuscode=-4; // recatch
- sprintf(back[i].r.msg,"Incorrect length ("LLintP" Bytes, "LLintP" expected)",back[i].r.size,back[i].r.totalsize);
- } else {
- //#else
- // Un warning suffira..
- if (cache->errlog!=NULL) {
- fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,back[i].r.size,back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
- }
- //#endif
- }
- }
- }
- #if BDEBUG==1
- printf("transfer ok\n");
- #endif
- } else { // pas d'erreur de rΘception
- if (back[i].timeout>0) { // refresh timeout si besoin est
- back[i].timeout_refresh=time_local();
- }
-
- // Traitement des en tΩtes chunks ou en tΩtes
- if (back[i].status==98) { // rΘception taille chunk en hexa ( aprΦs les en tΩtes, peut ne pas
- if (back[i].chunk_size>=2) {
- int chunk_size=-1;
- // Ωtre prΘsent)
- if (back[i].chunk_adr[back[i].chunk_size-1]==10) { // LF, fin ligne chunk
- char chunk_data[64];
- if (back[i].chunk_size<32) { // pas trop gros
- back[i].chunk_adr[ back[i].chunk_size-1]='\0'; // octet nul
- strcpy(chunk_data,""); // hex number
- strcat(chunk_data,back[i].chunk_adr);
- #if CHUNKDEBUG==1
- printf("chunk received and read: %s\n",chunk_data);
- #endif
- if (back[i].r.totalsize<0)
- back[i].r.totalsize=0; // initialiser α 0
- if (sscanf(chunk_data,"%x",&chunk_size) == 1) {
- back[i].r.totalsize+=chunk_size; // noter taille
- back[i].r.adr=(char*) realloct(back[i].r.adr,(INTsys) back[i].r.totalsize + 1);
- if (!back[i].r.adr) {
- if (cache->errlog!=NULL) {
- fprintf(cache->errlog,"Error: Not enough memory ("LLintP") for %s%s"LF,back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
- }
- }
- #if CHUNKDEBUG==1
- printf("chunk length: %d - next total "LLintP":\n",chunk_size,back[i].r.totalsize);
- #endif
- } else
- if (cache->errlog!=NULL) {
- fprintf(cache->errlog,"Warning: Illegal chunk (%s) for %s%s"LF,back[i].chunk_adr,back[i].url_adr,back[i].url_fil);
- }
- } else {
- if (cache->errlog!=NULL) {
- fprintf(cache->errlog,"Warning: Chunk too big ("LLintP") for %s%s"LF,back[i].chunk_size,back[i].url_adr,back[i].url_fil);
- }
- }
-
- // ok, continuer sur le body
-
- // si chunk non nul continuer (ou commencer)
- if (chunk_size>0) {
- back[i].status=1; // continuer body
- #if CHUNKDEBUG==1
- printf("waiting for body (chunk)\n");
- #endif
- } else { // chunk nul, c'est la fin
- #if CHUNKDEBUG==1
- printf("chunk end, total: %d\n",back[i].r.size);
- #endif
- back[i].status=0; // fin
- if (back[i].r.soc!=INVALID_SOCKET) {
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(5): deletehttp\n");
- #endif
- deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
-
- /* Tester totalsize en fin de chunk */
- if ((back[i].r.totalsize>0)) { // tester totalsize
- if (back[i].r.totalsize!=back[i].r.size) { // pas la mΩme!
- #if HTS_CL_IS_FATAL
- if (back[i].r.adr) { freet(back[i].r.adr); back[i].r.adr=NULL; }
- back[i].r.statuscode=-1;
- strcpy(back[i].r.msg,"Incorrect length");
- #else
- // Un warning suffira..
- if (cache->errlog!=NULL) {
- fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,back[i].r.size,back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
- }
- #endif
- }
- }
-
-
- }
- }
-
- // effacer buffer (chunk en tete)
- if (back[i].chunk_adr!=NULL) {
- freet(back[i].chunk_adr);
- back[i].chunk_adr=NULL;
- back[i].chunk_size=0;
- }
-
- } // chunk LF?
- } // taille buffer chunk>2
- //
- } else if (back[i].status==99) { // en tΩtes (avant le chunk si il est prΘsent)
- //
- if (back[i].r.size>=2) {
- if ((back[i].r.adr[back[i].r.size-1]==10) && (back[i].r.adr[back[i].r.size-2]==10)) {
- char rcvd[2048];
- int ptr=0;
-
- #if BDEBUG==1
- printf("..ok, header received\n");
- #endif
-
- // ----------------------------------------
- // traiter en-tΩte!
- // status-line α rΘcupΘrer
- ptr+=binput(back[i].r.adr+ptr,rcvd,2000);
- if (strnotempty(rcvd)==0)
- ptr+=binput(back[i].r.adr+ptr,rcvd,2000); // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
-
- // traiter status-line
- treatfirstline(&back[i].r,rcvd);
-
- #if HDEBUG
- printf("(Buffer) Status-Code=%d\n",back[i].r.statuscode);
- #endif
- if (_DEBUG_HEAD) {
- if (ioinfo) {
- fprintf(ioinfo,"\r\nresponse for %s%s:\r\n",back[i].url_adr,back[i].url_fil);
- fprintf(ioinfo,"(Buffer) Status-Code=%d\r\n",back[i].r.statuscode);
- fflush(ioinfo);
- } // en-tΩte
- }
-
- // header // ** !attention! HTTP/0.9 non supportΘ
- do {
- ptr+=binput(back[i].r.adr+ptr,rcvd,2000);
- #if HDEBUG
- printf("(buffer)>%s\n",rcvd);
- #endif
- if (_DEBUG_HEAD) {
- if (ioinfo) {
- fprintf(ioinfo,"(buffer)>%s\r\n",rcvd);
- fflush(ioinfo);
- }
- }
-
- if (strnotempty(rcvd))
- treathead(opt->cookie,back[i].url_adr,back[i].url_fil,&back[i].r,rcvd); // traiter
-
- // parfois les serveurs buggΘs renvoient un content-range avec un 200
- if (back[i].r.statuscode==200) // 'OK'
- if (strfield(rcvd,"content-range:")) // Avec un content-range: relisez les RFC..
- back[i].r.statuscode=206; // FORCER A 206 !!!!!
-
- } while(strnotempty(rcvd));
- // ----------------------------------------
-
- // libΘrer mΘmoire -- aprΦs! --
- if (back[i].r.adr!=NULL) { freet(back[i].r.adr); back[i].r.adr=NULL; }
-
- /* Interdiction taille par le wizard? */
- if (back[i].r.soc!=INVALID_SOCKET) {
- if (!back_checksize(opt,&back[i],1)) {
- back[i].status=0; // FINI
- deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
- if (!back[i].testmode)
- strcpy(back[i].r.msg,"File too big");
- else
- strcpy(back[i].r.msg,"Test: File too big");
- }
- }
-
- /* sinon, continuer */
- if (back[i].r.soc!=INVALID_SOCKET) { // ok rΘcupΘrer body?
- // head: terminΘ
- if (back[i].head_request) {
- if ((opt->debug>1) && (opt->log!=NULL)) {
- fspc(opt->log,"debug"); fprintf(opt->log,"Tested file: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
- }
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(head request): deletehttp\n");
- #endif
- // Couper connexion
- deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
- back[i].status=0; // terminΘ
- }
- // traiter une Θventuelle erreur 304 (cache α jour utilisable)
- else if (back[i].r.statuscode==304) { // document α jour dans le cache
- // lire dans le cache
- // ** NOTE: pas de vΘrif de la taille ici!!
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(file is not modified): deletehttp\n");
- #endif
- deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
- back[i].r=cache_read(opt,cache,back[i].url_adr,back[i].url_fil,back[i].url_sav);
- if (!back[i].r.location)
- back[i].r.location=back[i].location_buffer;
- else { /* recopier */
- strcpy(back[i].location_buffer,back[i].r.location);
- back[i].r.location=back[i].location_buffer;
- }
- if (back[i].r.statuscode!=-1) { // pas d'erreur de lecture
- back[i].status=0; // OK prΩt
- back[i].r.notmodified=1; // NON modifiΘ!
- if ((opt->debug>0) && (opt->log!=NULL)) {
- fspc(opt->log,"debug"); fprintf(opt->log,"File loaded after test from cache: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
- }
- #if DEBUGCA
- printf("..document α jour aprΦs requΦte: %s%s\n",back[i].url_adr,back[i].url_fil);
- #endif
-
- //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
- } else { // erreur
- back[i].status=0; // terminΘ
- //printf("erreur cache\n");
-
- }
-
- } else if ((back[i].r.statuscode==301) ||
- (back[i].r.statuscode==302) ||
- (back[i].r.statuscode==412)) { // Ne pas prendre le html, erreurs connues et gΘrΘes
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(301,302,412..): deletehttp\n");
- #endif
- // Couper connexion
- deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
- back[i].status=0; // terminΘ
-
- } else { // il faut aller le chercher
-
- // effacer buffer (requΦte)
- if (back[i].r.adr!=NULL) {
- freet(back[i].r.adr);
- back[i].r.adr=NULL;
- }
- back[i].r.size=0;
-
- // traiter 206 (partial content)
- // xxc SI CHUNK VERIFIER QUE CA MARCHE??
- if (back[i].r.statuscode==206) { // on nous envoie un morceau (la fin) coz une partie sur disque!
- LLint sz=fsize(back[i].url_sav);
- #if HDEBUG
- printf("partial content: "LLintP" on disk..\n",(LLint)sz);
- #endif
- if (sz>=0) {
- if (!is_hypertext_mime(back[i].r.contenttype)) { // pas HTML
- if (opt->getmode&2) { // on peut ecrire des non html **sinon ben euhh sera interceptΘ plus loin, donc rap sur ce qui va sortir**
- filenote(back[i].url_sav,NULL); // noter fichier comme connu
- back[i].r.out=fopen(fconv(back[i].url_sav),"ab"); // append
- if (back[i].r.out) {
- back[i].r.is_write=1; // Θcrire
- back[i].r.size=sz; // dΘja Θcrit
- back[i].r.statuscode=200; // Forcer 'OK'
- if (back[i].r.totalsize>0)
- back[i].r.totalsize+=sz; // plus en fait
- fseek(back[i].r.out,0,SEEK_END); // α la fin
- #if HDEBUG
- printf("continue interrupted file\n");
- #endif
- } else { // On est dans la m**
- back[i].status=0; // terminΘ (voir plus loin)
- strcpy(back[i].r.msg,"Can not open partial file");
- }
- }
- } else { // mΘmoire
- FILE* fp=fopen(fconv(back[i].url_sav),"rb");
- if (fp) {
- LLint alloc_mem=sz + 1;
- if (back[i].r.totalsize>0)
- alloc_mem+=back[i].r.totalsize; // AJOUTER RESTANT!
- if ( (back[i].r.adr=(char*) malloct((INTsys) alloc_mem)) ) {
- back[i].r.size=sz;
- if (back[i].r.totalsize>0)
- back[i].r.totalsize+=sz; // plus en fait
- if (((int) fread(back[i].r.adr,1,(INTsys)sz,fp)) != sz) {
- back[i].status=0; // terminΘ (voir plus loin)
- strcpy(back[i].r.msg,"Can not read partial file");
- } else {
- back[i].r.statuscode=200; // Forcer 'OK'
- #if HDEBUG
- printf("continue in mem interrupted file\n");
- #endif
- }
- } else {
- back[i].status=0; // terminΘ (voir plus loin)
- strcpy(back[i].r.msg,"No memory for partial file");
- }
- } else { // Argh..
- back[i].status=0; // terminΘ (voir plus loin)
- strcpy(back[i].r.msg,"Can not open partial file");
- }
- }
- } else { // Non trouvΘ??
- back[i].status=0; // terminΘ (voir plus loin)
- strcpy(back[i].r.msg,"Can not find partial file");
- }
- // Erreur?
- if (back[i].status==0) {
- if (back[i].r.soc!=INVALID_SOCKET) {
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(206 solve problems): deletehttp\n");
- #endif
- deletehttp(&back[i].r);
- }
- back[i].r.soc=INVALID_SOCKET;
- //back[i].r.statuscode=206; ????????
- back[i].r.statuscode=-5;
- if (strnotempty(back[i].r.msg))
- strcpy(back[i].r.msg,"Error attempting to solve status 206 (partial file)");
- }
- }
-
- if (back[i].status!=0) { // non terminΘ (erreur)
- if (!back[i].testmode) { // fichier normal
-
- if (!back[i].r.is_chunk) { // pas de chunk
- //if (back[i].r.http11!=2) { // pas de chunk
- back[i].is_chunk=0;
- back[i].status=1; // start body
- } else {
- #if CHUNKDEBUG==1
- printf("chunk encoding detected %s..\n",back[i].url_fil);
- #endif
- back[i].is_chunk=1;
- back[i].chunk_adr=NULL;
- back[i].chunk_size=0;
- back[i].status=98; // start body wait chunk
- }
- if (back[i].rateout>0) {
- back[i].rateout_time=time_local(); // refresh pour transfer rate
- }
- #if HDEBUG
- printf("(buffer) start body!\n");
- #endif
- } else { // mode test, ne pas passer en 1!!
- back[i].status=0; // READY
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(test ok): deletehttp\n");
- #endif
- deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
- if (back[i].r.statuscode==200) {
- strcpy(back[i].r.msg,"Test: OK");
- back[i].r.statuscode=-10; // test rΘussi
- }
- else { // test a ΘchouΘ, on ne change rien sauf que l'erreur est α titre indicatif
- char tempo[1000];
- strcpy(tempo,back[i].r.msg);
- strcpy(back[i].r.msg,"Test: ");
- strcat(back[i].r.msg,tempo);
- }
-
- }
- }
-
- }
-
-
-
- }
-
- } // si LF
- } // r.size>2
- } // si == 99
-
- } // si pas d'erreurs
- #if BDEBUG==1
- printf("bytes overall: %d\n",back[i].r.size);
- #endif
- } // donnΘes dispo
-
- // en cas d'erreur cl, supprimer Θventuel fichier sur disque
- #if HTS_REMOVE_BAD_FILES
- if (back[i].status<0) {
- if (!back[i].testmode) { // pas en test
- remove(back[i].url_sav); // Θliminer fichier (endommagΘ)
- //printf("&& %s\n",back[i].url_sav);
- }
- }
- #endif
-
- /* funny log for commandline users */
- if (!opt->quiet) { // petite animation
- if (opt->verbosedisplay) {
- if (back[i].status==0) {
- if (back[i].r.statuscode==200)
- printf("* %s%s ("LLintP" bytes) - OK\33[K\r",back[i].url_adr,back[i].url_fil,back[i].r.size);
- else
- printf("* %s%s ("LLintP" bytes) - %d\33[K\r",back[i].url_adr,back[i].url_fil,back[i].r.size,back[i].r.statuscode);
- fflush(stdout);
- }
- }
- }
-
-
- } // status>0
- } // for
-
- // vΘrifier timeouts
- if (gestion_timeout) {
- double act;
- act=time_local(); // temps en secondes
- for(i=0;i<back_max;i++) {
- if (back[i].status>0) { // rΘception/connexion/..
- if (back[i].timeout>0) {
- //printf("time check %d\n",((int) (act-back[i].timeout_refresh))-back[i].timeout);
- if (((int) (act-back[i].timeout_refresh))>=back[i].timeout) {
- if (back[i].r.soc!=INVALID_SOCKET) {
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(timeout): deletehttp\n");
- #endif
- deletehttp(&back[i].r);
- }
- back[i].r.soc=INVALID_SOCKET;
- back[i].r.statuscode=-2;
- if (back[i].status==100)
- strcpy(back[i].r.msg,"Connect Time Out");
- else if (back[i].status==101)
- strcpy(back[i].r.msg,"DNS Time Out");
- else
- strcpy(back[i].r.msg,"Receive Time Out");
- back[i].status=0; // terminΘ
- } else if ((back[i].rateout>0) && (back[i].status<99)) {
- if (((int) (act-back[i].rateout_time))>=HTS_WATCHRATE) { // checker au bout de 15s
- if ( (int) ((back[i].r.size)/(act-back[i].rateout_time)) < back[i].rateout ) { // trop lent
- back[i].status=0; // terminΘ
- if (back[i].r.soc!=INVALID_SOCKET) {
- #if HTS_DEBUG_CLOSESOCK
- DEBUG_W("back_wait(rateout): deletehttp\n");
- #endif
- deletehttp(&back[i].r);
- }
- back[i].r.soc=INVALID_SOCKET;
- back[i].r.statuscode=-3;
- strcpy(back[i].r.msg,"Transfer Rate Too Low");
- }
- }
- }
- }
- }
- }
- }
- max_loop--;
- #if HTS_ANALYSTE==2
- max_loop_chk++;
- #endif
- } while((busy) && (max_loop>0));
- #if HTS_ANALYSTE==2
- if (!busy) {
- if (max_loop_chk>=1) {
- Sleep(10); // un tite pause pour Θviter les lag..
- }
- }
- #endif
- }
-
- int back_checksize(httrackp* opt,lien_back* eback,int check_only_totalsize) {
- LLint size_to_test;
- if (check_only_totalsize)
- size_to_test=eback->r.totalsize;
- else
- size_to_test=max(eback->r.totalsize,eback->r.size);
- if (size_to_test>=0) {
-
- /* Interdiction taille par le wizard? */
- if (hts_testlinksize(opt,eback->url_adr,eback->url_fil,(eback->r.totalsize+1023)/1024)==-1) {
- return 0; /* interdit */
- }
-
- /* vΘrifier taille classique (heml et non html) */
- if ((istoobig(size_to_test,eback->maxfile_html,eback->maxfile_nonhtml,eback->r.contenttype))) {
- return 0; /* interdit */
- }
- }
- return 1;
- }
-
-
- // octets transfΘrΘs + add
- LLint back_transfered(LLint nb,lien_back* back,int back_max) {
- int i;
- // ajouter octets en instance
- for(i=0;i<back_max;i++)
- if ((back[i].status>0) && (back[i].status<99))
- nb+=back[i].r.size;
- return nb;
- }
-
- // infos backing
- // j: 1 afficher sockets 2 afficher autres 3 tout afficher
- void back_info(lien_back* back,int i,int j,FILE* fp) {
- if (back[i].status>=0) {
- char s[256];
- s[0]='\0';
- back_infostr(back,i,j,s);
- strcat(s,LF);
- fprintf(fp,"%s",s);
- }
- }
-
- // infos backing
- // j: 1 afficher sockets 2 afficher autres 3 tout afficher
- void back_infostr(lien_back* back,int i,int j,char* s) {
- if (back[i].status>=0) {
- int aff=0;
- if (j & 1) {
- if (back[i].status==100) {
- strcat(s,"CONNECT ");
- } else if (back[i].status==99) {
- strcat(s,"INFOS ");
- aff=1;
- } else if (back[i].status==98) {
- strcat(s,"INFOSC"); // infos chunk
- aff=1;
- }
- else if (back[i].status>0) {
- #if HTS_ANALYSTE==2
- strcat(s,"WAIT ");
- #else
- strcat(s,"RECEIVE ");
- #endif
- aff=1;
- }
- }
- if (j & 2) {
- if (back[i].status==0) {
- switch (back[i].r.statuscode) {
- case 200:
- strcat(s,"READY ");
- aff=1;
- break;
- #if HTS_ANALYSTE==2
- default:
- strcat(s,"ERROR ");
- break;
- #else
- case -1:
- strcat(s,"ERROR ");
- aff=1;
- break;
- case -2:
- strcat(s,"TIMEOUT ");
- aff=1;
- break;
- case -3:
- strcat(s,"TOOSLOW ");
- aff=1;
- break;
- case 400:
- strcat(s,"BADREQUEST ");
- aff=1;
- break;
- case 401: case 403:
- strcat(s,"FORBIDDEN ");
- aff=1;
- break;
- case 404:
- strcat(s,"NOT FOUND ");
- aff=1;
- break;
- case 500:
- strcat(s,"SERVERROR ");
- aff=1;
- break;
- default:
- {
- char s2[256];
- sprintf(s2,"ERROR(%d)",back[i].r.statuscode);
- strcat(s,s2);
- }
- aff=1;
- #endif
- }
- }
- }
-
- if (aff) {
- {
- char s2[256];
- sprintf(s2,"\"%s",back[i].url_adr); strcat(s,s2);
-
- if (back[i].url_fil[0]!='/') strcat(s,"/");
- sprintf(s2,"%s\" ",back[i].url_fil); strcat(s,s2);
- sprintf(s,LLintP" "LLintP" ",back[i].r.size,back[i].r.totalsize); strcat(s,s2);
- }
- }
- }
- }
-
- // -- backing --
-
- #undef test_flush
-