IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Web & réseau Delphi Discussion :

TIdhttp (HTTP/1.1 403 Forbidden)


Sujet :

Web & réseau Delphi

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Mars 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Mars 2014
    Messages : 9
    Points : 1
    Points
    1
    Par défaut TIdhttp (HTTP/1.1 403 Forbidden)
    Bonjour,

    Je viens solliciter votre aide pour comprendre un phénomène que je rencontre.

    On utilise les composants Indy notamment pour récupérer des images depuis un serveur distant. Et ça fonctionne bien jusque là sauf pour un url donné (en Https).

    A la suite d'un test rapide sur un navigateur, l'url fonctionne correctement.

    Par contre, avec Postman, quand j’exécute plusieurs fois la même requête (GET method), le retour provient soit du serveur AkamaiGHost avec un message d'erreur 'HTTP/1.1 403 Forbidden. Access denied. You don't have permission on this server' soit du serveur AmazonS3 avec un statuscode 200 et l'image attendue.

    A noter que depuis l'application, le retour provient systématiquement du serveur AkamaiGHost et donc avec le message d'erreur cité ci-dessus (avec les composants Indy).

    J'ai donc voulu tester l'url avec les composants Rest Client et là c'est le serveur AmazonS3 qui répond avec un statuscode 200 et l'image souhaitée.

    Est-ce que quelqu'un a déjà rencontré ce problème ou peut m'aider à comprendre ce qui se passe ?
    Je vous remercie d'avance.
    Passion_Delphi

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 659
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 659
    Points : 25 440
    Points
    25 440
    Par défaut
    Tu as un bien un IOHandler SSL pour gérer le HTTPS et non du HTTP simple ?
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Mars 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Mars 2014
    Messages : 9
    Points : 1
    Points
    1
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Tu as un bien un IOHandler SSL pour gérer le HTTPS et non du HTTP simple ?
    Oui, on utilise TIdSSLIOHandlerSocketOpenSSL.

    Ci dessous le code de mes tests :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    var
      lStream: TMemoryStream;
    begin
      IdHttp1 := TIdHTTP.Create(nil);
      try
        IdSSLIOHandlerSocketOpenSSL1:= TIdSSLIOHandlerSocketOpenSSL.Create(IdHttp1);
        try
          IdSSLIOHandlerSocketOpenSSL1.SSLOptions.SSLVersions := [sslvTLSv1,sslvTLSv1_1,sslvTLSv1_2];
          IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Method      := sslvTLSv1_2;
          IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Mode        := sslmClient;
          // IdSSLIOHandlerSocketOpenSSL1.SSLOptions.VerifyMode  := [sslvrfClientOnce, sslvrfPeer];
          IdSSLIOHandlerSocketOpenSSL1.SSLOptions.VerifyDepth := 0;
          // IdSSLIOHandlerSocketOpenSSL1.OnVerifyPeer           := OnVerifyPeer;
          IdLogEvent1                                         := TIdLogEvent.Create(Self);
          try
            IdLogEvent1.ReplaceCRLF   := False;
            IdLogEvent1.LogTime       := False;
     
            IdLogEvent1.OnReceived    := OnReceivedData;
            IdLogEvent1.OnSent        := OnSentData;
            IdLogEvent1.OnStatus      := OnStatusEvent;
     
            IdHTTP1.Request.BasicAuthentication := False;
            IdHTTP1.Request.Accept    :='*/*';
            IdHTTP1.Request.AcceptEncoding:='gzip, deflate';
            IdHTTP1.Request.Connection:='Close';
            IdHTTP1.Request.UserAgent := 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0';
            IdHTTP1.Request.CharSet   := 'utf-8, *;q=0.8r';
            IdHTTP1.Request.AcceptLanguage := 'en-us,en;q=0.5';
            IdHTTP1.Request.CustomHeaders.AddValue('Clear-Site-Data','*');
     
            IdHttp1.AllowCookies      := True;
            IdHTTP1.HandleRedirects   := True;
            IdHTTP1.RedirectMaximum   := 35;
            IdHTTP1.ConnectTimeout    := 12000;
            IdHTTP1.ReadTimeout       := 12000;
            IdHTTP1.MaxAuthRetries    := 10;
            IdHTTP1.HTTPOptions       := [hoForceEncodeParams];
     
            IdHTTP1.IOHandler         := IdSSLIOHandlerSocketOpenSSL1;
            IdHTTP1.IOHandler.Intercept := IdLogEvent1;
     
            IdHTTP1.OnRedirect        := OnRedirect;
            IdHTTP1.OnProxyAuthorization:= OnProxyAuthorization;
            IdHTTP1.OnChunkReceived   := OnChunkReceived;
            IdHTTP1.OnConnected       := OnConnected;
            lStream                   := TMemoryStream.Create;
            try
              try
                IdLogEvent1.Active    := True;
                IdHTTP1.Get(URL, lStream);
                if IdHTTP1.ResponseCode in [200, 201] then
                begin
                  lStream.Position := 0;
                  Image1.Picture.LoadFromStream(lStream);
                  Image1.Stretch := True;
                  Image1.Repaint;
                end
                else
                begin
                  Memo1.Lines.Add('Echec :  '+ IdHttp1.ResponseText);
                end;
              except
                on e:exception do
                begin
                  Memo1.Lines.Add('Exception : '+ e.Message);
                end;
              end;
            finally
              FreeAndNil(lStream);
            end;
          finally
            IdLogEvent1.Active := False;
            FreeAndNil(IdLogEvent1);
          end;
        finally
          FreeAndNil(IdSSLIOHandlerSocketOpenSSL1);
        end;
      finally
        FreeAndNil(IdHTTP1);
      end;

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 659
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 659
    Points : 25 440
    Points
    25 440
    Par défaut



    Avec le TRestClient, la gestion du SSL est implicite (dans IPPeerCommon et IPPeerClient), cela se débrouille tout seul avec les certificats Windows, j'ai d'ailleurs du remplacer le TRestClient qui dépend du THTTPClient et dans D10, cela ne remonte pas toutes les possibilité de gestion de certificat comme l'erreur ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED retourné par les API Windows WinHTTP 5.0, la gestion du HTTPS est implicite (l'URL fourni l'indication de protocol)

    J'ai du remplacé TRESTClient\TRESTRequest par TIdHTTP\TIdHTTPRequest avec une gestion explicite HTTPS via OpenSSL ( libeay32.dll \ ssleay32.dll + TIdSSLIOHandlerSocketOpenSSL).
    Donc un code similaire au tient mais je suis loin de changer les options

    je me limite à ceci

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //------------------------------------------------------------------------------
    class procedure TRESTClientByIndy.ToggleHTTPS(ARequest: TIdHTTP; const AURL: string);
    begin
      ARequest.HandleRedirects := True;
     
      if StartsText('https://', AURL) then
      begin
        ARequest.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(Nil);
        TIdSSLIOHandlerSocketOpenSSL(ARequest.IOHandler).SSLOptions.Method := sslvSSLv23; // la valeur sslvSSLv23 laisse au server le choix du protocole, on ne s'en occupe pas
      end;
    end;
    utilisé dans

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //------------------------------------------------------------------------------
    class function TRESTClientByIndy.Get(const AURL, AResource: string; AParams: TClientMicroService.TRequester.TRequestParams; const AToken: string = ''; ATimeOut: Integer = -1): TJSONObject;
    var
      VIdHTTP: TIdHTTP;
      VResponse: string;
    begin
      VIdHTTP := TIdHTTP.Create(nil);
      try
        ToggleHTTPS(VIdHTTP, AURL);
     
        if AToken <> '' then
          VIdHTTP.Request.Authentication := THTTPBearerAuthentication.Create(AToken); // TIdHTTPRequest owns Authentication
     
        VResponse := ExecuteGet(VIdHTTP, AURL, AResource, AParams, [200]);
     
        Result := TJSONObject.ParseJSONValue(VResponse) as TJSONObject;
      finally
        VIdHTTP.IOHandler.Free();
        VIdHTTP.Free();
      end;
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 659
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 659
    Points : 25 440
    Points
    25 440
    Par défaut
    Et la même chose à base TRESTClient, je me suis fait une couche d'abstraction pour passer de l'un à l'autre suite au problème de HTTPS :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    //------------------------------------------------------------------------------
    class function TRESTClientByIPPeer.Get(const AURL, AResource: string; AParams: TClientMicroService.TRequester.TRequestParams = nil; const AToken: string = ''; ATimeOut: Integer = -1): TJSONObject;
     
      function AuthenticatorFactory(): TCustomAuthenticator;
      begin
        if AToken <> '' then
        begin
          Result := TOAuth2Authenticator.Create(nil);
          try
            TOAuth2Authenticator(Result).AccessToken := AToken;
            TOAuth2Authenticator(Result).TokenType := TOAuth2TokenType.ttBEARER;
          except
            FreeAndNil(Result);
            raise;
          end;
        end
        else
          Result := nil;
      end;
     
    var
      VClient: TRESTClient;
      VRequest: TRESTRequest;
      Param: TRequestParam;
    begin
      VClient := TRESTClient.Create(AURL);
      try
        VRequest := TRESTRequest.Create(VClient); // The Client owns the Request (will free it) and it will assign as Client property
        VRequest.Resource := AResource;
        VRequest.Method := TRESTRequestMethod.rmGET;
     
        if Assigned(AParams) then
          for Param in AParams do
            VRequest.AddParameter(Param.Name, Param.Value, TRESTRequestParameterKind.pkGETorPOST);
     
        VClient.Authenticator := AuthenticatorFactory();
        try
          Execute(VRequest, ATimeOut, [200]);
        finally
          VClient.Authenticator.Free();
          VClient.Authenticator := nil;
        end;
     
        Result := VRequest.Response.JSONValue.Clone() as TJSONObject;
      finally
        VClient.Free();
      end;
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  6. #6
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Mars 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Mars 2014
    Messages : 9
    Points : 1
    Points
    1
    Par défaut
    Oui, le code réel a moins d'options que ça mais j'en ai rajouté pour essayer de voir si ça allait changé quelque chose et je dois dire que non.

  7. #7
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Mars 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Mars 2014
    Messages : 9
    Points : 1
    Points
    1
    Par défaut
    Avec le TRestClient, la gestion du SSL est implicite (dans IPPeerCommon et IPPeerClient), cela se débrouille tout seul avec les certificats Windows, j'ai d'ailleurs du remplacer le TRestClient qui dépend du THTTPClient et dans D10, cela ne remonte pas toutes les possibilité de gestion de certificat comme l'erreur ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED retourné par les API Windows WinHTTP 5.0, la gestion du HTTPS est implicite (l'URL fourni l'indication de protocol)

    J'ai du remplacé TRESTClient\TRESTRequest par TIdHTTP\TIdHTTPRequest avec une gestion explicite HTTPS via OpenSSL ( libeay32.dll \ ssleay32.dll + TIdSSLIOHandlerSocketOpenSSL).
    Donc un code similaire au tient mais je suis loin de changer les options
    Donc si j'ai bien compris ce que tu dis, ce n'est pas forcément une bonne idée d'aller remplacer IdHTTP par du RestClient ?

  8. #8
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 659
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 659
    Points : 25 440
    Points
    25 440
    Par défaut
    Avec Indy, j'ai eu des soucis de DLL, lié à TIdSSLIOHandlerSocketOpenSSL
    Avec Indy, tu peux aussi utilisé TIdSSLIOHandlerSocketSChannel qui n'a pas de dépendance
    Avec TRESTClient, j'étais très satisfait mais récemment des serveurs configurés différemment m'ont poussé à un retour sur Indy

    Pas d'avantage à l'un ou l'autre, faut juste prendre celui qui fonctionne



    Sinon c'est pour télécharger un fichier, tu peux te passer de toute dépendance, ni TRESTClient, ni Indy, et c'est les API Windows qui gèrent le HTTPS

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
      procedure GetInternetFile(const AServerName: string; const AURL: string; AStream: TStream; const ExpectedContentType: string = '');
      type
        TAcceptTypes = packed array[0..1] of LPWSTR;
      const
        BufferSize = 1024;
        ACCEPT_TYPES: TAcceptTypes = (PChar('text/*'), nil); // PCTSTR rgpszAcceptTypes[] = {_T(“text/*”), NULL};
      var
        hSession, hHTTP, hReq : HINTERNET;
        Accept: TAcceptTypes;
        Buffer: array[1..BufferSize] of Byte;
        BufferLen: DWORD;
        sAppName: string;
      begin
        AStream.Size := 0;
        sAppName := ExtractFileName(Application.ExeName);
     
        Accept := ACCEPT_TYPES;
        if ExpectedContentType <> '' then
          Accept[0] := PChar(ExpectedContentType);
     
        // Winapi.WinInet !!!
        hSession := InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
        try
          hHTTP := InternetConnect(hSession, PChar(AServerName), INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 1);
          try
            hReq := HttpOpenRequest(hHTTP, PChar('GET'), PChar(AURL), nil, nil, @accept, 0, 1);
            try
              if HttpSendRequest(hReq, nil, 0, nil, 0) then
              begin
                BufferLen := 0;
                repeat
                  if InternetReadFile(hReq, @Buffer, BufferSize, BufferLen) then
                    AStream.WriteBuffer(Buffer, BufferLen);
     
                until BufferLen = 0;
              end
              else
                raise Exception.Create('HttpOpenRequest failed. ' + SysErrorMessage(GetLastError));
            finally
              InternetCloseHandle(hReq);
            end;
          finally
            InternetCloseHandle(hHTTP);
          end;
        finally
          InternetCloseHandle(hSession);
        end;
      end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  9. #9
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Mars 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Mars 2014
    Messages : 9
    Points : 1
    Points
    1
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Sinon c'est pour télécharger un fichier, tu peux te passer de toute dépendance, ni TRESTClient, ni Indy, et c'est les API Windows qui gèrent le HTTPS

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
      procedure GetInternetFile(const AServerName: string; const AURL: string; AStream: TStream; const ExpectedContentType: string = '');
      type
        TAcceptTypes = packed array[0..1] of LPWSTR;
      const
        BufferSize = 1024;
        ACCEPT_TYPES: TAcceptTypes = (PChar('text/*'), nil); // PCTSTR rgpszAcceptTypes[] = {_T(“text/*”), NULL};
      var
        hSession, hHTTP, hReq : HINTERNET;
        Accept: TAcceptTypes;
        Buffer: array[1..BufferSize] of Byte;
        BufferLen: DWORD;
        sAppName: string;
      begin
        AStream.Size := 0;
        sAppName := ExtractFileName(Application.ExeName);
     
        Accept := ACCEPT_TYPES;
        if ExpectedContentType <> '' then
          Accept[0] := PChar(ExpectedContentType);
     
        // Winapi.WinInet !!!
        hSession := InternetOpen(PChar(sAppName), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
        try
          hHTTP := InternetConnect(hSession, PChar(AServerName), INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 1);
          try
            hReq := HttpOpenRequest(hHTTP, PChar('GET'), PChar(AURL), nil, nil, @accept, 0, 1);
            try
              if HttpSendRequest(hReq, nil, 0, nil, 0) then
              begin
                BufferLen := 0;
                repeat
                  if InternetReadFile(hReq, @Buffer, BufferSize, BufferLen) then
                    AStream.WriteBuffer(Buffer, BufferLen);
     
                until BufferLen = 0;
              end
              else
                raise Exception.Create('HttpOpenRequest failed. ' + SysErrorMessage(GetLastError));
            finally
              InternetCloseHandle(hReq);
            end;
          finally
            InternetCloseHandle(hHTTP);
          end;
        finally
          InternetCloseHandle(hSession);
        end;
      end;
    D'accord, je vais essayer de tester avec ça.
    Merci beaucoup pour tes retours.

  10. #10
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Mars 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Mars 2014
    Messages : 9
    Points : 1
    Points
    1
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Avec Indy, j'ai eu des soucis de DLL, lié à TIdSSLIOHandlerSocketOpenSSL
    Avec Indy, tu peux aussi utilisé TIdSSLIOHandlerSocketSChannel qui n'a pas de dépendance
    Avec TRESTClient, j'étais très satisfait mais récemment des serveurs configurés différemment m'ont poussé à un retour sur Indy

    Pas d'avantage à l'un ou l'autre, faut juste prendre celui qui fonctionne
    En fait, j'ai aussi essayé TIdSSLIOHandlerSocketSChannel mais ça n'a pas changé grand chose à la situation.
    Ce qui est étrange c'est que je rencontre ce problème qu'avec un seul URL (en https) mais tout le reste fonctionne (en http ou https)

  11. #11
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 659
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 659
    Points : 25 440
    Points
    25 440
    Par défaut
    AmazonS3, je ne l'ai utilisé qu'en python couplé à une base MongoDB pour l'indexation, dans une sorte de GED
    En delphi, je n'ai aucune expérience de AmazonS3, en python, il y a tellement de lib pour tout, on devient vite un agglomérateur de lib qu'un programmeur.

    Finalement, les responsables archi nous ont dit de refaire le projet car c'était que des technologies non déployée sur les dockers (Amazon aussi et trop chère semble-t-il), j'ai tout refait en PostgreSQL avec une limitation de 50Mo qui sera couplé à une extension pour les fichiers plus gros ultérieurement.

    Faudrait voir en Delphi, si il n'existe pas un équivalent de boto3.s3 du python

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    import io
    import json
    import mimetypes
    import os
    from contextlib import nullcontext
    from pathlib import Path
     
    import boto3
    from boto3.s3.transfer import TransferConfig
    from botocore.exceptions import ClientError
     
    from src.common.components.file_system.fs_abstract_client import AbstractFileSystemClient, FileDescriptor, FileJSON, \
        FileInterfaced, FileIOClass, FullFileName, FileBytes
     
     
    class FileSystemClientByAmazonS3(AbstractFileSystemClient):
     
        def __init__(self, amazon_s3_client: "AmazonS3Client"):
            self.__amazon_s3_client = amazon_s3_client
     
        def create_path(self, file_descriptor: FileDescriptor):
            self.__amazon_s3_client.create_bucket(
                bucket=file_descriptor.root)
     
        def find_one(self, file_descriptor: FileDescriptor) -> FileDescriptor:
     
            prefix = FileDescriptor(file_descriptor.root, file_descriptor.directory,
                                    file_descriptor.filename.replace('.*', '.'))
     
            keys = self.__amazon_s3_client.list_objects_by_prefix_and_suffix(
                bucket=file_descriptor.root,
                prefix=self.__key_join(prefix))
            if keys.__len__() == 1:
                key = keys[0]
                return FileDescriptor(
                    file_descriptor.root,
                    file_descriptor.directory,
                    key[file_descriptor.directory.__len__() + 1:]
                )
     
            return None
     
        def file_exists(self, file_descriptor: FileDescriptor) -> bool:
            file_exists = self.__amazon_s3_client.object_exists(
                bucket=file_descriptor.root,
                key=self.__key_join(file_descriptor))
            return file_exists
     
        def read_json(self, file_descriptor: FileDescriptor, allow_not_exists: bool = False) -> FileJSON:
            key = self.__key_join(file_descriptor)
            file_exists, content = self.__amazon_s3_client.get_object_if_exists(
                bucket=file_descriptor.root,
                key=key)
            if not file_exists and not allow_not_exists:
                raise FileNotFoundError(key)
     
            return FileJSON(file_descriptor, content, file_exists)
     
        def put_json(self, file_json: FileJSON) -> FullFileName:
            content = json.dumps(file_json.content_json)
            key = self.__key_join(file_json.file_descriptor)
            self.__amazon_s3_client.write_object(
                bucket=file_json.file_descriptor.root,
                key=key,
                obj=content)
            return key
     
        def read_bytes(self, file_descriptor: FileDescriptor, allow_not_exists: bool = False) -> FileBytes:
            key = self.__key_join(file_descriptor)
            try:
                return FileBytes(
                    file_descriptor,
                    self.__amazon_s3_client.download_stream(
                        bucket=file_descriptor.root,
                        key=key),
                    True)
            except ClientError as e:
                if allow_not_exists:
                    return FileBytes(file_descriptor, b"", False)
                else:
                    raise FileNotFoundError(key)
     
        def put_bytes(self, file_bytes: FileBytes) -> FullFileName:
            key = self.__key_join(file_bytes.file_descriptor)
            self.__amazon_s3_client.upload_stream(
                bucket=file_bytes.file_descriptor.root,
                key=key,
                stream=file_bytes.content)
            return key
     
        def put_interfaced_file(self, file_interfaced: FileInterfaced) -> FullFileName:
            key = self.__key_join(file_interfaced.file_descriptor)
            self.__amazon_s3_client.upload_stream(
                bucket=file_interfaced.file_descriptor.root,
                key=key,
                stream=file_interfaced.as_readable().to_bytes())
            return key
     
        def remove(self, file_descriptor: FileDescriptor):
            self.__amazon_s3_client.delete_object(
                bucket=file_descriptor.root,
                key=self.__key_join(file_descriptor))
     
        def file_lock(self, file_descriptor: FileDescriptor):
            return nullcontext()
     
        @staticmethod
        def __key_join(file_descriptor: FileDescriptor):
            if file_descriptor.directory != "":
                return f'{file_descriptor.directory}/{file_descriptor.filename}'
            else:
                return file_descriptor.filename
     
        def is_same_file(self, file_descriptor_one: FileDescriptor, file_descriptor_two: FileDescriptor):
            if file_descriptor_one.root != '' and file_descriptor_two.root != '':
                if file_descriptor_one.root != file_descriptor_two.root:
                    return False
            fn1 = self.__key_join(file_descriptor_one)
            fn2 = self.__key_join(file_descriptor_two)
            return fn1 == fn2
     
     
    class AmazonS3Client:
        # add any mime type that is not automatically detected
        mimetypes.add_type('application/json', '.json')
     
        def __init__(self, s3_client=None,
                     aws_region: str = "", aws_endpoint: str = "",
                     aws_access_key_id: str = "", aws_access_key_secret: str = ""):
     
            self.config = TransferConfig(multipart_threshold=1024 * 5,
                                         max_concurrency=10,
                                         multipart_chunksize=1024 * 2,
                                         use_threads=True)
     
            # clients are generally thread-safe
            # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/clients.html#multithreading-or-multiprocessing-with-clients
            # Le debuggeur PyCharm ne supporte pas que l'on instancie un boto3.client dans un thread
            # il se bloque, il faut le stopper et il continue son execution, c'est douteux
            # Utilisez AmazonS3Client comme un objet global partagé
     
            if s3_client is not None:
                self.s3_client = s3_client
            else:
                self.s3_client = boto3.client("s3", region_name=aws_region,
                                              endpoint_url=aws_endpoint,
                                              aws_access_key_id=aws_access_key_id,
                                              aws_secret_access_key=aws_access_key_secret
                                              )
     
        def create_bucket(self, **kwargs):
            """
            Create a bucket. If the bucket does not exist, it creates it.
            Bucket name takes the bucket named parameter. If it exists, it is not created
            @param kwargs:
                bucket = is the bucket identifier
            """
            bucket = kwargs.get('bucket')
            try:
                if not self.bucket_exists(bucket=bucket):
                    self.s3_client.create_bucket(Bucket=bucket)
            except ClientError as ex:
                raise
     
        def write_metadata_to_bucket(self, **kwargs):
            # todo to check if we really need this for s3
            """
            Create a bucket. If the bucket does not exist, it creates it.
                Bucket name takes the bucket named parameter. If it exists, it is not created
                @param kwargs:
                    bucket = is the bucket identifier
            """
            bucket = kwargs.get('bucket')
            metadata = kwargs.get('metadata')
            try:
                if not self.bucket_exists(bucket=bucket):
                    self.s3_client.create_bucket(Bucket=bucket)
            except ClientError as ex:
                raise
     
        def write_object(self, **kwargs):
            """
            Uploads objects to bucket.
            @param kwargs:
                bucket = is the bucket identifier
                key = key index
                object
            """
            bucket = kwargs.get('bucket')
            key = kwargs.get('key')
            data = kwargs.get('obj')
            file_mime_type, _ = mimetypes.guess_type(key)
            if file_mime_type is None:
                file_mime_type = 'application/json'
            try:
                self.s3_client.put_object(Body=data,
                                          Bucket=bucket,
                                          Key=key,
                                          ContentType=file_mime_type)
            except ClientError as ex:
                raise
     
        def delete_object(self, **kwargs):
            bucket = kwargs.get('bucket')
            key = kwargs.get('key')
            try:
                self.s3_client.delete_object(Bucket=bucket, Key=key)
            except ClientError as ex:
                raise
     
        def create_objects(self, **kwargs):
            """
            Uploads objects to bucket. If the bucket does not exist, it creates it.
            Bucket name takes the bucket name. If it exists, it is not created
            @param kwargs:
                bucket = is the bucket identifier
                path = path to files (folder) ex: /data
            """
            bucket = kwargs.get('bucket')
            key = kwargs.get('key')
            path = kwargs.get('path')
            try:
                for subdir, dirs, files in os.walk(path):
                    for file in files:
                        full_path = os.path.join(subdir, file)
                        self.s3_client.upload_file(Filename=full_path, Bucket=bucket,
                                                   Key=f'{key}/{file}',
                                                   Config=self.config)
            except ClientError as ex:
                raise
     
        def upload_stream(self, bucket: str, key: str, stream):
            """
            Uploads objects to bucket. If the object does not exist, it creates it.
            @param stream the object to be uploaded
            @param bucket = is the bucket identifier (root bucket)
            @param key = is the key identifier aws s3
            """
            try:
                content = io.BytesIO(stream)
                self.s3_client.upload_fileobj(Fileobj=content, Bucket=bucket,
                                              Key=key,
                                              Config=self.config)
            except ClientError as ex:
                raise
     
        def delete_objects(self, **kwargs):
            tenant_id = kwargs.get('tenant_id')
            mail_id = kwargs.get('mail_id')
            if tenant_id and mail_id:
                file_list = self.list_objects(tenant_id=tenant_id, mail_id=mail_id, prefix="")
                try:
                    for file in file_list:
                        self.s3_client.delete_object(Bucket=tenant_id, Key=file)
                except ClientError as ex:
                    raise
     
        def download_objects(self, **kwargs):
            """
            This method downloads all the files contained in a mail_id folder
            @param kwargs:
            tenant_id = is the tenant_id identifier
            mail_id = is the folder containing all attachments for that email
            local_path = is the local path where the files will be stored
            """
            tenant_id = kwargs.get('tenant_id')
            mail_id = kwargs.get('mail_id')
            prefix = kwargs.get('prefix')
            local_path = kwargs.get('local_path')
            try:
                found_object_list = self.list_objects(tenant_id=tenant_id, mail_id=mail_id, prefix=prefix)
                if len(found_object_list):
                    for file in found_object_list:
                        file_path = Path(local_path, file)
                        file_path.parent.mkdir(parents=True, exist_ok=True)
                        self.s3_client.download_file(tenant_id, file,
                                                     str(file_path), Config=self.config)
            except ClientError as ex:
                raise
     
        def list_objects(self, **kwargs) -> list:
            """
            Uploads objects to bucket. If the bucket does not exist, it creates it.
            Bucket name takes the tenant_id name. If it exists, it is not created.
            S3 list_objects_v2 can list at max 1000 files in one go.
            Paginator is useful when you have more than 1000s of files in S3.
            @param kwargs:
                tenant_id = is the tenant_id identifier
                prefix = prefix to search for ex: 2023/02/12
            @return:
            List of files, with prefix
            """
            obj_list = []
            bucket_name = kwargs.get('bucket')
            prefix = kwargs.get('prefix')
            key = kwargs.get('key')
            try:
                if bucket_name:
                    paginator = self.s3_client.get_paginator("list_objects_v2")
                    response = paginator.paginate(Bucket=bucket_name, PaginationConfig={"PageSize": 1000}, Prefix=prefix)
                    for page in response:
                        files = page.get("Contents")
                        if files:
                            for file_obj in files:
                                if key and key in file_obj['Key']:
                                    obj_list.append(file_obj['Key'])
                                else:
                                    obj_list.append(file_obj['Key'])
                            return obj_list
                return obj_list
            except ClientError as ex:
                return []
     
        def object_exists(self, **kwargs):
            bucket = kwargs.get('bucket')
            key = kwargs.get('key')
            try:
                self.s3_client.get_object(Bucket=bucket, Key=key)
                return True
            except ClientError as e:
                if e.response['Error']['Code'] == 'NoSuchKey':
                    return False
                else:
                    raise
     
        def get_object_if_exists(self, **kwargs):
            bucket = kwargs.get('bucket')
            key = kwargs.get('key')
            file_mime_type, _ = mimetypes.guess_type(key)
            if file_mime_type is None:
                file_mime_type = 'application/json'
            try:
                obj = self.s3_client.get_object(Bucket=bucket, Key=key)
                if file_mime_type == 'application/json':
                    obj = json.loads(obj.get('Body').read().decode('utf-8'))
                    return True, obj
                return True, obj
            except ClientError as e:
                if e.response['Error']['Code'] == 'NoSuchKey':
                    # normal behaviour, we return false since the object was not found
                    return False, None
                else:
                    raise
     
        def download_stream(self, bucket: str, key: str) -> bytes:
            """
            Download objects to bucket
            :return: stream the object to be downloaded
            :param bucket: is the bucket identifier (root bucket)
            :param key: is the key identifier aws s3
            """
            try:
                content = io.BytesIO()
                self.s3_client.download_fileobj(Fileobj=content, Bucket=bucket, Key=key, Config=self.config)
                content.seek(0)
                stream: bytes = content.read()
                return stream
            except ClientError as ex:
                raise
     
        def read_object(self, **kwargs):
            """
            Reads objects from bucket.
            @param kwargs:
                bucket = is the bucket identifier
                key = key index
                object
            """
            bucket = kwargs.get('bucket')
            key = kwargs.get('key')
            try:
                obj = self.s3_client.get_object(Bucket=bucket, Key=key).get('Body').read().decode('utf-8')
                return json.loads(obj)
            except ClientError as ex:
                raise
     
        def bucket_exists(self, **kwargs) -> bool:
            bucket = kwargs.get('bucket')
            if bucket:
                for obj in self.s3_client.list_buckets().get('Buckets'):
                    if obj['Name'] == bucket:
                        return True
            return False
     
        def list_objects_by_prefix_and_suffix(self, **kwargs):
            """
                Generate the keys in an S3 bucket.
     
                :param bucket: Name of the S3 bucket.
                :param prefix: Only fetch keys that start with this prefix (optional).
                :param suffix: Only fetch keys that end with this suffix (optional).
            """
            bucket = kwargs.get('bucket')
            prefix = kwargs.get('prefix', '')
            suffix = kwargs.get('suffix', '')
            keys = []
            paginator = self.s3_client.get_paginator("list_objects_v2")
            response = paginator.paginate(Bucket=bucket, PaginationConfig={"PageSize": 1000}, Prefix=prefix)
            for page in response:
                objects = page.get("Contents")
                if objects:
                    for obj in objects:
                        key = obj['Key']
                        if key.startswith(prefix) and key.endswith(suffix):
                            keys.append(key)
            return keys

    et j'ai son équivalent local pour utiliser un simple serveur de fichier au lieu de S3

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
     
    import glob
    import json
    import os
    from typing import BinaryIO
     
    from filelock import FileLock
     
    from src.common.components.file_system.fs_abstract_client import AbstractFileSystemClient, FileDescriptor, FileJSON, \
        FileInterfaced, FullFileName, FileBytes
     
     
    class FileSystemClientByLocal(AbstractFileSystemClient):
     
        def create_path(self, file_descriptor: FileDescriptor):
            if not os.path.exists(file_descriptor.directory):
                os.makedirs(file_descriptor.directory)
     
        def find_one(self, file_descriptor: FileDescriptor) -> FileDescriptor:
            fn = os.path.join(file_descriptor.directory, file_descriptor.filename)
            for name in glob.glob(fn):
                return FileDescriptor(
                    file_descriptor.root,
                    file_descriptor.directory,
                    os.path.basename(name)
                )
            return None
     
        def file_exists(self, file_descriptor: FileDescriptor) -> bool:
            fn = os.path.join(file_descriptor.directory, file_descriptor.filename)
            return os.path.exists(fn)
     
        def read_json(self, file_descriptor: FileDescriptor, allow_not_exists: bool = False) -> FileJSON:
            mode = "rt"
            fn = os.path.join(file_descriptor.directory, file_descriptor.filename)
            if os.path.exists(fn) or not allow_not_exists:
                with open(fn, mode) as json_file:
                    content = json_file.read()
                return FileJSON(file_descriptor, json.loads(content), True)
            else:
                if allow_not_exists:
                    return FileJSON(file_descriptor, {}, False)
                else:
                    raise FileNotFoundError(fn)  # ne se produit jamais, on utilise l'exception naturelle du with open
     
        def put_json(self, file_json: FileJSON) -> FullFileName:
            mode = "wt" if file_json.file_exists else "xt"
            fn = os.path.join(file_json.file_descriptor.directory, file_json.file_descriptor.filename)
            content = json.dumps(file_json.content_json)
            with open(fn, mode) as json_file:
                json_file.seek(0)
                json_file.write(content)
            return fn
     
        def read_bytes(self, file_descriptor: FileDescriptor, allow_not_exists: bool = False) -> FileBytes:
            mode = "rb"
            fn = os.path.join(file_descriptor.directory, file_descriptor.filename)
            if os.path.exists(fn) or not allow_not_exists:
                binary_file: BinaryIO
                with open(fn, mode) as binary_file:
                    return FileBytes(file_descriptor, binary_file.read(), True)
            else:
                if allow_not_exists:
                    return FileBytes(file_descriptor, b"", False)
                else:
                    raise FileNotFoundError(fn)  # ne se produit jamais, on utilise l'exception naturelle du with open
     
        def put_bytes(self, file_bytes: FileBytes) -> FullFileName:
            mode = "wb" if file_bytes.file_exists else "xb"
            fn = os.path.join(file_bytes.file_descriptor.directory, file_bytes.file_descriptor.filename)
            binary_file: BinaryIO
            with open(fn, mode) as binary_file:
                binary_file.seek(0)
                binary_file.write(file_bytes.content)
            return fn
     
        def put_interfaced_file(self, file_interfaced: FileInterfaced) -> FullFileName:
            fn = os.path.join(file_interfaced.file_descriptor.directory, file_interfaced.file_descriptor.filename)
            file_interfaced.as_writable().save_to_file(fn)
            return fn
     
        def remove(self, file_descriptor: FileDescriptor):
            fn = os.path.join(file_descriptor.directory, file_descriptor.filename)
            os.remove(fn)
     
        def file_lock(self, file_descriptor: FileDescriptor):
            fn = os.path.join(file_descriptor.directory, file_descriptor.filename + ".lock")
            return FileLock(fn)
     
        def is_same_file(self, file_descriptor_one: FileDescriptor, file_descriptor_two: FileDescriptor):
            fn1 = os.path.join(file_descriptor_one.directory, file_descriptor_one.filename)
            fn2 = os.path.join(file_descriptor_two.directory, file_descriptor_two.filename)
            return os.path.samefile(fn1, fn2)

    les deux implémentent la même abstraction

    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    from abc import ABC, abstractmethod
     
    from src.common.core.file.interfaces.file_interface import \
        FileInterface, FileLoadable, FileWritable, FileReadable
    from src.common.core.file.interfaces.file_io import FileIOClass
     
    FilePath = str
    FileName = str
    FullFileName = str
     
     
    class FileDescriptor:
     
        def __init__(self, root: FilePath, directory: FilePath, filename: FileName):
            self.__root = root
            self.__directory = directory
            self.__filename = filename
     
        @property
        def root(self) -> FilePath:
            return self.__root
     
        @property
        def directory(self) -> FilePath:
            return self.__directory
     
        @property
        def filename(self) -> FileName:
            return self.__filename
     
     
    class FileAbstractContent:
     
        def __init__(self, file_descriptor: FileDescriptor, file_exists: bool):
            self.__file_descriptor = file_descriptor
            self.__file_exists = file_exists
     
        @property
        def file_descriptor(self) -> FileDescriptor:
            return self.__file_descriptor
     
        @property
        def file_exists(self) -> bool:
            return self.__file_exists
     
     
    class FileJSON(FileAbstractContent):
     
        def __init__(self, file_descriptor: FileDescriptor, content_json: dict, file_exists: bool = False):
            super().__init__(file_descriptor, file_exists)
            self.__content_json = content_json
     
        @property
        def content_json(self) -> dict:
            return self.__content_json
     
     
    class FileBytes(FileAbstractContent):
     
        def __init__(self, file_descriptor: FileDescriptor, content: bytes, file_exists: bool = False):
            super().__init__(file_descriptor, file_exists)
            self.__content = content
     
        @property
        def content(self) -> bytes:
            return self.__content
     
     
    class FileInterfaced(FileAbstractContent):
     
        def __init__(self, file_descriptor: FileDescriptor, interface_file: FileInterface, file_exists: bool = False):
            super().__init__(file_descriptor, file_exists)
            self.__interface_file = interface_file
     
        def as_loadable(self) -> FileLoadable:
            if isinstance(self.__interface_file, FileLoadable):
                return self.__interface_file
            else:
                raise Exception("File Interfaced can't be load !")  # todo Exception !!!
     
        def as_writable(self) -> FileWritable:
            if isinstance(self.__interface_file, FileWritable):
                return self.__interface_file
            else:
                raise Exception("File Interfaced can't be write !")  # todo Exception !!!
     
        def as_readable(self) -> FileReadable:
            if isinstance(self.__interface_file, FileReadable):
                return self.__interface_file
            else:
                raise Exception("File Interfaced can't be read !")  # todo Exception !!!
     
     
    class AbstractFileSystemClient(ABC):
     
        @abstractmethod
        def create_path(self, file_descriptor: FileDescriptor):
            raise NotImplementedError
     
        @abstractmethod
        def find_one(self, file_descriptor: FileDescriptor) -> FileDescriptor:
            raise NotImplementedError
     
        @abstractmethod
        def file_exists(self, file_descriptor: FileDescriptor) -> bool:
            raise NotImplementedError
     
        @abstractmethod
        def read_json(self, file_descriptor: FileDescriptor, allow_not_exists: bool = False) -> FileJSON:
            raise NotImplementedError
     
        @abstractmethod
        def put_json(self, file_json: FileJSON) -> FullFileName:
            raise NotImplementedError
     
        @abstractmethod
        def read_bytes(self, file_descriptor: FileDescriptor, allow_not_exists: bool = False) -> FileBytes:
            raise NotImplementedError
     
        @abstractmethod
        def put_bytes(self, file_bytes: FileBytes) -> FullFileName:
            raise NotImplementedError
     
        def read_interfaced_file(self, file_interfaced: FileInterfaced, allow_not_exists: bool = False):
            file_interfaced.as_loadable().from_bytes(
                self.read_bytes(file_interfaced.file_descriptor, allow_not_exists).content)
     
        @abstractmethod
        def put_interfaced_file(self, file_interfaced: FileInterfaced) -> FullFileName:
            raise NotImplementedError
     
        @abstractmethod
        def remove(self, file_descriptor: FileDescriptor):
            raise NotImplementedError
     
        def file_lock(self, file_descriptor: FileDescriptor):
            raise NotImplementedError
     
        @abstractmethod
        def is_same_file(self, file_descriptor_one: FileDescriptor, file_descriptor_two: FileDescriptor):
            raise NotImplementedError
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  12. #12
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Mars 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Mars 2014
    Messages : 9
    Points : 1
    Points
    1
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message

    Faudrait voir en Delphi, si il n'existe pas un équivalent de boto3.s3 du python
    Ok je vais regarder ça également.

    Et après quelques tests rapide avec Wininet, pour le moment je tombe systématiquement dans le message d'erreur 'HttpOpenRequest failed.' mais je vais continuer demain et te ferais un retour dès que possible.

    Bonne soirée et encore merci.

  13. #13
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 659
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 659
    Points : 25 440
    Points
    25 440
    Par défaut
    ça doit être un truc genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GetInternetFile('s3.us-west-2.amazonaws.com', '/examplebucket/puppy.jpg', StreamDejaCree, '*/*');
    Après, cela ne gère aucune sécurité, ni login, ni token ni rien donc ça doit pas fonctionner sur S3 quand j'y pense car il faut aws_access_key_id et aws_secret_access_key, en python, via boto3, j'ai toujours fourni les clés

    Tu sais que tu peux aussi installer un docker "localstack" pour faire tes tests
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  14. #14
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Mars 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Mars 2014
    Messages : 9
    Points : 1
    Points
    1
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GetInternetFile('s3.us-west-2.amazonaws.com', '/examplebucket/puppy.jpg', StreamDejaCree, '*/*');
    Avec cet exemple, effectivement, la requête est bien envoyée mais j'ai un code d'erreur 'InvalidBucketName' avec le message 'The specified bucket is not valid'

    Concernant le docker 'localstack', je vais essayer de regarder ça.

  15. #15
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 659
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 659
    Points : 25 440
    Points
    25 440
    Par défaut
    Citation Envoyé par passion_delphi Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    GetInternetFile('s3.us-west-2.amazonaws.com', '/examplebucket/puppy.jpg', StreamDejaCree, '*/*');
    Avec cet exemple, effectivement, la requête est bien envoyée mais j'ai un code d'erreur 'InvalidBucketName' avec le message 'The specified bucket is not valid'
    Evidemment, c'est un exemple, c'est ceux sur l'aide d'amazon, il te faut mettre le bon chemin même si sans les clés/secrets, j'imagine que cela ne fonctionne pas, puisqu'il semble clair qu'il y a un header "Authorization" a définir Signing and authenticating REST utilisant la clé comme identifiant et le secret pour produire la signature de la clé

    Dans ton code Indy, je n'avais vu aucune trace du header "Authorization", je suppose que tu as censuré le CustomHeaders (je vois BasicAuthentication à False, c'est que tu la remplaces par autre chose)
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  16. #16
    Nouveau Candidat au Club
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Mars 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Mars 2014
    Messages : 9
    Points : 1
    Points
    1
    Par défaut
    Oui je sais que c'était un exemple ce que tu as donné et j'ai bien remplacé ce qu'il faut et notamment l'URL.

    Sinon, effectivement, il n'y a pas d'authorization dans le code ... Et même après avoir contacté de l'entreprise de mon problème avec leur URL, on ne m'a pas parlé de ça

Discussions similaires

  1. WMS geoportail: Impossible d'accéder aux données (HTTP 403 Forbidden)
    Par agodfrin dans le forum IGN API Géoportail
    Réponses: 7
    Dernier message: 06/08/2014, 12h07
  2. [Sharepoint 2010]HTTP 403 : Forbidden.
    Par Avallack dans le forum Développement Sharepoint
    Réponses: 1
    Dernier message: 21/01/2014, 11h32
  3. http://api.ign.fr/geoportail/ 403 Forbidden
    Par hm7845 dans le forum IGN API Géoportail
    Réponses: 2
    Dernier message: 10/12/2013, 15h44
  4. Erreur HTTP 403 Forbidden (Interdit)
    Par Etienne maheu dans le forum Weblogic
    Réponses: 3
    Dernier message: 28/02/2013, 08h09
  5. HTTP/1.1 403 access forbidden
    Par Hepil dans le forum IIS
    Réponses: 4
    Dernier message: 04/05/2007, 15h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo