Téléchargement par HTTP via Socket

Les instructions httpRequête et httpRécupereRésultat servent à récupérer un résultat en interrogeant une adresse URL. Pour avoir la jauge, l’utilisation de HTTPJauge est nécessaire mais est bizarrement indépendante au lieu d’être un CallBack. De même, il n’est pas possible de limiter le débit de téléchargement. Le code ci-dessous le permet et pilote la jauge directement et la vitesse.

Attention, ce code n’est pas prévu pour fonctionner sur des URL en https.

PROCEDURE TéléchargeHTTP(bContenu est un booléen,sFichierHTTP est une chaîne,sFichierDestination est une chaîne,bAvecJauge est un booléen,sPréfixeJauge est une chaîne,nTimeOut est un entier,nPort est un entier,sUser est une chaîne,sPass est une chaîne,sNomDuThread est une chaîne,LOCAL sProxy est une chaîne)
//bContenu : permet de télécharger le contenu du fichier (vrai) ou seulement l'entête (faux)
//sFichierHTTP : adresse HTTP du fichier sans http:// devant (ex : www.apple.com/fraise.png)
//sFichierDestination : chemin du fichier à créer (en local)
//bAvecJauge : affiche la progression dans la barre de message de la fenêtre appellante (à modifier si on veut faire pointer vers une autre jauge)
//sPréfixeJauge : texte à afficher avant le pourcentage (le tout s'affichera à droite de la jauge dans la barre de message de la fenêtre appelante)
//nTimeOut : durée du timeout (voir doc de la fonction SocketConnecte)
//nPort : port sur lequel faire la connexion HTTP (habituellement le 80)
//sUser : Nom d'utilisateur pour avoir accès en HTTP au fichier sFichierHTTP (voir fichier .htaccess du site)
//sPass : Mot de passe relié à l'utilisateur sUser
//sNomDuThread : nom du thread ayant appelé cette fonction (afin que cette fonction télécharge en tâche de fond)
//sProxy : adresse du proxy intermédiaire (UserProxy:PassProxy@AdresseProxy:PortProxy)
 
//gbAnnule : variable globale booléenne qui indique que le téléchargement doit être arrêté prématurément (vrai), sinon laisser à faux
//gsErreurHTTP : variable globale chaine qui récupère le message d'erreur
//gsAgentHTTP : variable globale chaine contenant l'agent HTTP (voir fonction HTTPRequête / agent utilisateur)
 
ThreadEnvoieSignal(sNomDuThread)
sMsg,sReq est une chaîne
sNomSocketHTTP est une chaine = "MonSocketHTTP"
 
sReqDirect est une chaîne = [
GET %1 HTTP/1.1
Host: %2
User-Agent: %3
Connection: keep-alive
]
 
sReqProxy est une chaîne = [
GET %1 HTTP/1.1
Host: %2
User-Agent: %3
Proxy-Connection: keep-alive
Cache-Control: max-age=0
Proxy-Authorization: Basic %4
]
 
nJaugeMax,f,nRecu,nSeconde,nRecuParSeconde,nCentieme,nDurée est un entier
sLigne,sEntête,sJauge,hDiff,sErr,sDomaine,sAcces est une chaîne
dhHCur,dhHInit sont des DateHeures
duDurée1 est une Durée
rDébit est un réel
 
QUAND EXCEPTION DANS
  sDomaine=ExtraitChaîne(sFichierHTTP,1,"/")
  SI sProxy>"" _ET_ Position(sProxy,"@")>0 ALORS 
    sAcces = Crypte(ExtraitChaîne(sProxy,1,"@"),"",crypteAnsi,encodeBASE64)
    sProxy = ExtraitChaîne(sProxy,2,"@") 
  FIN
 
  SI SocketConnecte(sNomSocketHTTP,(sProxy>"" ? Val(ExtraitChaîne(sProxy,2,":")) SINON nPort),(sProxy>"" ?ExtraitChaîne(sProxy,1,":") SINON sDomaine),nTimeOut)=Faux ALORS
    gsErreurHTTP="Erreur de connexion : "+ErreurInfo(errMessage)
  SINON
    SocketChangeModeTransmission(sNomSocketHTTP,SocketSansMarqueurFin)
    //gestion du proxy
    SI sProxy>"" ALORS
      sReq=ChaîneConstruit(sReqProxy,"http://"+sFichierHTTP,sDomaine,gsAgentHTTP,sAcces)
    SINON
      sReq=ChaîneConstruit(sReqDirect,Milieu(sFichierHTTP,Taille(sDomaine)+1),sDomaine,gsAgentHTTP)
    FIN
    //gestion de l'authentification au serveur lui-même
    SI sUser>"" ALORS sReq+=RC+"Authorization: Basic "+Crypte(sUser+":"+sPass,"",crypteAnsi,encodeBASE64)
    sReq+=RC+RC
 
    SI SocketEcrit(sNomSocketHTTP,sReq) ALORS
      nRecu=0;nRecuParSeconde=0
      //mémorise la date et heure pour afficher une jauge chaque seconde
      dhHInit=DateSys()+HeureSys();nSeconde=Val(Milieu(dhHInit,13,2));nCentieme=Val(Milieu(dhHInit,15,2))
      TANTQUE SocketExiste(sNomSocketHTTP)=Vrai
        sMsg = SocketLit(sNomSocketHTTP,Vrai)
        SI PAS sMsg = "" ALORS 
          SI nRecu=0 ALORS
            sEntête=ExtraitChaîne(sMsg,1,RC+RC);sMsg=ExtraitChaîne(sMsg,2,RC+RC)
            SI PAS (ExtraitChaîne(sEntête,1,RC)="HTTP/1.1 200 OK" OU ExtraitChaîne(sEntête,1,RC)="HTTP/1.0 200 OK") ALORS 
              gsErreurHTTP="Erreur donnée par le serveur HTTP ("+Milieu(ExtraitChaîne(sEntête,1,RC),10)+")"
              SORTIR
            FIN
            SI PAS bContenu ALORS
              gsErreurHTTP=sEntête
              SORTIR
            FIN
            //trouve la taille du fichier à télécharger pour initialiser la jauge
            POUR TOUTE CHAINE sLigne DE sEntête SEPAREE PAR RC
              SI Gauche(sLigne,15)="Content-Length:" ALORS nJaugeMax=Val(ExtraitChaîne(sLigne,2,":"))
            FIN
            fSupprime(sFichierDestination);f=fCrée(sFichierDestination)
            SI f=-1 ALORS 
              gsErreurHTTP="Impossible créer le fichier de destination : "+ErreurInfo(errMessage)
              SORTIR
            FIN
          SINON
            SI gbAnnule ALORS SORTIR
          FIN
          SI PAS f=-1 ALORS
            nRecu+=Taille(sMsg)
            fEcrit(f,sMsg)
 
            dhHCur=DateSys()+HeureSys();nRecuParSeconde+=Taille(sMsg)
            SI bAvecJauge _ET_ PAS nSeconde=Val(Milieu(dhHCur,13,2)) ALORS
              sJauge=NumériqueVersChaîne(Arrondi(nRecu/nJaugeMax*100,1),"3.1fs")+"%"  // reçu à "+TailleVersChaîne(nRecuParSeconde)+"/s"
              Jauge(nRecu,nJaugeMax,sPréfixeJauge+[" "]+sJauge)
              nRecuParSeconde=0
              dhHCur=DateSys()+HeureSys();nSeconde=Val(Milieu(dhHCur,13,2));nCentieme=Val(Milieu(dhHCur,15,2))
            FIN
            SI nRecu=nJaugeMax ALORS
              hDiff=DateHeureDifférence(dhHInit,dhHCur)
              SI bAvecJauge ALORS
                duDurée1 = ChaîneVersDurée(hDiff,duréeCentième) 
                nDurée=duDurée..Jour*86400+duDurée..Heure*3600+duDurée..Minute*60+duDurée..Seconde 
                rDébit=Arrondi(nJaugeMax/nDurée,2)
                Jauge(nRecu,nJaugeMax,sPréfixeJauge+[" "]+"100,0%")  // reçu à "+TailleVersChaîne(rDébit)+"/s en moyenne")
              FIN
              fFerme(f);SORTIR
            FIN
          FIN
        SINON 
          SORTIR
        FIN
      FIN
      SI f<>-1 ALORS fFerme(f)
 
      SI bContenu ALORS
        SI (fFichierExiste(sFichierDestination) _ET_ fTaille(sFichierDestination)=nJaugeMax) ALORS
          gsErreurHTTP=""
        SINON SI gsErreurHTTP ALORS
          gsErreurHTTP="Fichier vide ou incomplet."
        FIN
      FIN
    SINON
      gsErreurHTTP="Erreur durant le téléchargement HTTP : "+ErreurInfo(errMessage)
    FIN
    SocketFerme(sNomSocketHTTP)
  FIN
FAIRE
  SocketFerme(sNomSocketHTTP)
  gsErreurHTTP="Erreur durant le téléchargement HTTP : "+ExceptionInfo(errMessage)
FIN

Pour faire tourner le téléchargement en tâche de fond, il est conseillé (en tout cas la procédure est construite ainsi) de l’appeler dans un thread à part :

PROCEDURE sTéléchargeHTTP(sFichierHTTP est une chaîne,sFichierDestination est une chaîne="",bAvecJauge est un booléen=Faux,sPréfixeJauge est une chaîne="",nTimeOut est un entier = 5000,nPort est un entier = 80,sUser est une chaîne="", sPass est une chaîne="",sNomDuThread est une chaîne = threadPrincipal,sProxy est une chaîne = "")
sNomThread est une chaîne = "MonThreadHTTP"
gsErreurHTTP=""
ThreadExécute(sNomThread,threadNormal,TéléchargeHTTP,(sFichierDestination>""),sFichierHTTP,sFichierDestination,bAvecJauge,sPréfixeJauge,nTimeOut,nPort,sUser,sPass,sNomDuThread,sProxy);ThreadAttendSignal()
TANTQUE ThreadEtat(sNomThread)=threadEnCours
  SI gbAnnule ALORS ThreadArrête(sNomThread)
  Multitâche(-5)
FIN
RENVOYER gsErreurHTTP