Jump to content
Zazhir

Error on call esternal api Delphi XE6

Recommended Posts

I'm trying to make a request of type Get, for a simple API, which performs the query of unique codes of companies. I tried several ways to make this request, but all of them lead me to the following error

 

error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version

or this one 

error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert protocol version

 

I upgraded from Indy component to the lateste version, current 10.6.20 and am using Delphi XE6.

Below is one of the functions I did, but that doesn't bring me anything in the request response, and gives me the erros bellow:

function TfrmAttAreaExterno.searchData02;
var
  URL, response: String;
  jsonStreamRetorno, jsonStreamEnvio: TStringStream;
  SSLIO: TIdSSLIOHandlerSocketOpenSSL;
  strm: TMemoryStream;
  Error: TStringList;
begin
  memo01.Clear();

  URL := 'https://www.receitaws.com.br/v1/cnpj/27865757000102';
  strm  := TMemoryStream.Create;

  try
    IdHTTP01.AllowCookies := True;
    IdHTTP01.HandleRedirects := True;
    IdHTTP01.ProxyParams.BasicAuthentication := False;
    IdHTTP01.ProxyParams.ProxyPort := 0;
    IdHTTP01.Request.Connection := 'Keep-Alive';
    IdHTTP01.Request.ContentLength := -1;
    IdHTTP01.Request.ContentType := 'application/x-www-form-urlencoded';
    IdHTTP01.Request.Accept := 'text/html, application/xhtml+xml, image/jxr, */*';
    IdHTTP01.Request.AcceptEncoding := 'gzip, deflate';
    IdHTTP01.Request.AcceptLanguage := 'pt-BR';
    IdHTTP01.Request.BasicAuthentication := False;
    IdHTTP01.Request.Host := 'img.discogs.com';
    IdHTTP01.Request.UserAgent :=
      'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like ' +
      'Gecko';

    SSLIO := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP01);
    SSLIO.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
    SSLIO.SSLOptions.Mode := sslmUnassigned;
    SSLIO.SSLOptions.VerifyMode := [sslvrfPeer, sslvrfFailIfNoPeerCert, sslvrfClientOnce];
    SSLIO.SSLOptions.VerifyDepth := 0;

    try
      idHttp01.IOHandler:= SSLIO;
      response := idHttp01.Get(URL);
      memo01.Text := response;

    except
      on E: Exception do
       begin
          ShowMessage(E.Message);
       end;
    end;

   except
     on E: Exception do
       begin
          ShowMessage(E.Message);
       end;
   end;
end;

Please, any help would be appreciated! I just run of the ideas to what might be causing this issue. Plus, I just run over all the internet, and tried every single solution that looks like was going to help me....  

 

Share this post


Link to post

If your current problem is just that you can not download a file, with the Windows API it works like shown:

program Project11;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Winapi.Windows, Winapi.WinInet,
  System.SysUtils;

const
  oneKB = DWORD(1024);

procedure ParseURL(const lpszUrl: string; var Host, Resource: string);
var
  lpszScheme      : array[0..Pred(INTERNET_MAX_SCHEME_LENGTH)] of Char;
  lpszHostName    : array[0..Pred(INTERNET_MAX_HOST_NAME_LENGTH)] of Char;
  lpszUserName    : array[0..Pred(INTERNET_MAX_USER_NAME_LENGTH)] of Char;
  lpszPassword    : array[0..Pred(INTERNET_MAX_PASSWORD_LENGTH)] of Char;
  lpszUrlPath     : array[0..Pred(INTERNET_MAX_PATH_LENGTH)] of Char;
  lpszExtraInfo   : array[0..Pred(oneKB)] of Char;
  lpUrlComponents : TURLComponents;
begin
  ZeroMemory(@lpszScheme,      SizeOf(lpszScheme));
  ZeroMemory(@lpszHostName,    SizeOf(lpszHostName));
  ZeroMemory(@lpszUserName,    SizeOf(lpszUserName));
  ZeroMemory(@lpszPassword,    SizeOf(lpszPassword));
  ZeroMemory(@lpszUrlPath,     SizeOf(lpszUrlPath));
  ZeroMemory(@lpszExtraInfo,   SizeOf(lpszExtraInfo));
  ZeroMemory(@lpUrlComponents, SizeOf(TURLComponents));
  lpUrlComponents.dwStructSize      := SizeOf(TURLComponents);
  lpUrlComponents.lpszScheme        := lpszScheme;
  lpUrlComponents.dwSchemeLength    := SizeOf(lpszScheme);
  lpUrlComponents.lpszHostName      := lpszHostName;
  lpUrlComponents.dwHostNameLength  := SizeOf(lpszHostName);
  lpUrlComponents.lpszUserName      := lpszUserName;
  lpUrlComponents.dwUserNameLength  := SizeOf(lpszUserName);
  lpUrlComponents.lpszPassword      := lpszPassword;
  lpUrlComponents.dwPasswordLength  := SizeOf(lpszPassword);
  lpUrlComponents.lpszUrlPath       := lpszUrlPath;
  lpUrlComponents.dwUrlPathLength   := SizeOf(lpszUrlPath);
  lpUrlComponents.lpszExtraInfo     := lpszExtraInfo;
  lpUrlComponents.dwExtraInfoLength := SizeOf(lpszExtraInfo);
  InternetCrackUrl(PChar(lpszUrl), Length(lpszUrl), ICU_DECODE or ICU_ESCAPE, lpUrlComponents);
  Host     := lpszHostName;
  Resource := lpszUrlPath;
end;

function GetWinInetError(ErrorCode:Cardinal): string;
const
   winetdll = 'wininet.dll';
var
  Len: Integer;
  Buffer: PChar;
begin
  Len := FormatMessage(
  FORMAT_MESSAGE_FROM_HMODULE or FORMAT_MESSAGE_FROM_SYSTEM or
  FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_IGNORE_INSERTS or  FORMAT_MESSAGE_ARGUMENT_ARRAY,
  Pointer(GetModuleHandle(winetdll)), ErrorCode, 0, @Buffer, SizeOf(Buffer), nil);
  try
    while (Len > 0) and {$IFDEF UNICODE}(CharInSet(Buffer[Len - 1], [#0..#32, '.'])) {$ELSE}(Buffer[Len - 1] in [#0..#32, '.']) {$ENDIF} do Dec(Len);
    SetString(Result, Buffer, Len);
  finally
    LocalFree(HLOCAL(Buffer));
  end;
end;

function GetRemoteFileSize(const AURL: string; const AShowError: Boolean; out AFileSize: Int64): Boolean;
const
  sUserAgent = 'Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101';
var
  hInet    : HINTERNET;
  hConnect : HINTERNET;
  hRequest : HINTERNET;
  lpdwBufferLength: DWORD;
  lpdwReserved    : DWORD;
  ServerName: string;
  Resource: string;
  ErrorCode : Cardinal;
  LFileSize: Int64;
begin
  ParseURL(AUrl, ServerName, Resource);
  Result := False;
  AFileSize := -1;
  hInet := InternetOpen(PChar(sUserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  if (hInet = nil) then
    begin
      ErrorCode := GetLastError;
      if AShowError then
        raise Exception.Create(Format('InternetOpen Error %d Description %s', [ErrorCode, GetWinInetError(ErrorCode)]));
    end;
  try
    hConnect := InternetConnect(hInet, PChar(ServerName), INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
    if ((hConnect = nil) and AShowError) then
      begin
        ErrorCode := GetLastError;
        raise Exception.Create(Format('InternetConnect Error %d Description %s', [ErrorCode, GetWinInetError(ErrorCode)]));
      end;
    try
      hRequest := HttpOpenRequest(hConnect, PChar('HEAD'), PChar(Resource), nil, nil, nil, 0, 0);
        if (hRequest <> nil) then
          begin
            try
              lpdwBufferLength := SizeOf(LFileSize);
              lpdwReserved := 0;
              if ((not HttpSendRequest(hRequest, nil, 0, nil, 0)) and AShowError) then
                begin
                  ErrorCode := GetLastError;
                  raise Exception.Create(Format('HttpOpenRequest Error %d Description %s', [ErrorCode, GetWinInetError(ErrorCode)]));
                end;
             if ((not HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH or HTTP_QUERY_FLAG_NUMBER, @LFileSize, lpdwBufferLength, lpdwReserved)) and AShowError) then
               begin
                  ErrorCode := GetLastError;
                  raise Exception.Create(Format('HttpQueryInfo Error %d Description %s', [ErrorCode, GetWinInetError(ErrorCode)]));
               end
               else
               begin
                 AFileSize := LFileSize;
                 Result := (AFileSize > 0);
               end;
            finally
              InternetCloseHandle(hRequest);
            end;
          end
          else
          if AShowError then
            begin
              ErrorCode := GetLastError;
              raise Exception.Create(Format('HttpOpenRequest Error %d Description %s', [ErrorCode, GetWinInetError(ErrorCode)]));
            end;
    finally
      InternetCloseHandle(hConnect);
    end;
  finally
    InternetCloseHandle(hInet);
  end;
end;

function Download(const AURL, AFileName: string): Boolean;
const
  BufferSize = oneKB;
var
  hSession, hURL: HInternet;
  Buffer: array[1..BufferSize] of Byte;
  BufferLen: DWORD;
  F: File;
  BytesLoaded, BytesTotal, BytesCalc: Int64;
begin
  Result := False;

  if (not GetRemoteFileSize(AURL, True, BytesTotal)) then
    Exit;

  hSession := InternetOpen('', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ;

  // Establish the secure connection
  InternetConnect (hSession, PChar(AURL), INTERNET_DEFAULT_HTTPS_PORT, PChar(''), PChar(''), INTERNET_SERVICE_HTTP, 0, 0);

  try
    hURL := InternetOpenURL(hSession, PChar(AURL), nil, 0, INTERNET_FLAG_RELOAD, 0);
    BytesLoaded := 0;
    try
      AssignFile(f, AFileName);
      Rewrite(f,1);
      try
        repeat
          InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen) ;
          BlockWrite(f, Buffer, BufferLen);
          if (BytesTotal > 0) then
            begin
              Inc(BytesLoaded, BufferLen);
              BytesCalc := (BytesLoaded * 100 div BytesTotal);
            end;
        until BufferLen = 0;
      finally
        CloseFile(f) ;
        Result := True;
      end;
    finally
      InternetCloseHandle(hURL);
    end
  finally
    InternetCloseHandle(hSession);
  end;
end;

begin
  try
    Download('https://www.receitaws.com.br/v1/cnpj/27865757000102', ExtractFilePath(ParamStr(0)) + 'file.json');
    { TODO -oUser -cConsole Main : Insert code here }
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

 

Share this post


Link to post
11 hours ago, KodeZwerg said:

If your current problem is just that you can not download a file, with the Windows API it works like shown:


program Project11;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Winapi.Windows, Winapi.WinInet,
  System.SysUtils;

const
  oneKB = DWORD(1024);

procedure ParseURL(const lpszUrl: string; var Host, Resource: string);
var
  lpszScheme      : array[0..Pred(INTERNET_MAX_SCHEME_LENGTH)] of Char;
  lpszHostName    : array[0..Pred(INTERNET_MAX_HOST_NAME_LENGTH)] of Char;
  lpszUserName    : array[0..Pred(INTERNET_MAX_USER_NAME_LENGTH)] of Char;
  lpszPassword    : array[0..Pred(INTERNET_MAX_PASSWORD_LENGTH)] of Char;
  lpszUrlPath     : array[0..Pred(INTERNET_MAX_PATH_LENGTH)] of Char;
  lpszExtraInfo   : array[0..Pred(oneKB)] of Char;
  lpUrlComponents : TURLComponents;
begin
  ZeroMemory(@lpszScheme,      SizeOf(lpszScheme));
  ZeroMemory(@lpszHostName,    SizeOf(lpszHostName));
  ZeroMemory(@lpszUserName,    SizeOf(lpszUserName));
  ZeroMemory(@lpszPassword,    SizeOf(lpszPassword));
  ZeroMemory(@lpszUrlPath,     SizeOf(lpszUrlPath));
  ZeroMemory(@lpszExtraInfo,   SizeOf(lpszExtraInfo));
  ZeroMemory(@lpUrlComponents, SizeOf(TURLComponents));
  lpUrlComponents.dwStructSize      := SizeOf(TURLComponents);
  lpUrlComponents.lpszScheme        := lpszScheme;
  lpUrlComponents.dwSchemeLength    := SizeOf(lpszScheme);
  lpUrlComponents.lpszHostName      := lpszHostName;
  lpUrlComponents.dwHostNameLength  := SizeOf(lpszHostName);
  lpUrlComponents.lpszUserName      := lpszUserName;
  lpUrlComponents.dwUserNameLength  := SizeOf(lpszUserName);
  lpUrlComponents.lpszPassword      := lpszPassword;
  lpUrlComponents.dwPasswordLength  := SizeOf(lpszPassword);
  lpUrlComponents.lpszUrlPath       := lpszUrlPath;
  lpUrlComponents.dwUrlPathLength   := SizeOf(lpszUrlPath);
  lpUrlComponents.lpszExtraInfo     := lpszExtraInfo;
  lpUrlComponents.dwExtraInfoLength := SizeOf(lpszExtraInfo);
  InternetCrackUrl(PChar(lpszUrl), Length(lpszUrl), ICU_DECODE or ICU_ESCAPE, lpUrlComponents);
  Host     := lpszHostName;
  Resource := lpszUrlPath;
end;

function GetWinInetError(ErrorCode:Cardinal): string;
const
   winetdll = 'wininet.dll';
var
  Len: Integer;
  Buffer: PChar;
begin
  Len := FormatMessage(
  FORMAT_MESSAGE_FROM_HMODULE or FORMAT_MESSAGE_FROM_SYSTEM or
  FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_IGNORE_INSERTS or  FORMAT_MESSAGE_ARGUMENT_ARRAY,
  Pointer(GetModuleHandle(winetdll)), ErrorCode, 0, @Buffer, SizeOf(Buffer), nil);
  try
    while (Len > 0) and {$IFDEF UNICODE}(CharInSet(Buffer[Len - 1], [#0..#32, '.'])) {$ELSE}(Buffer[Len - 1] in [#0..#32, '.']) {$ENDIF} do Dec(Len);
    SetString(Result, Buffer, Len);
  finally
    LocalFree(HLOCAL(Buffer));
  end;
end;

function GetRemoteFileSize(const AURL: string; const AShowError: Boolean; out AFileSize: Int64): Boolean;
const
  sUserAgent = 'Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101';
var
  hInet    : HINTERNET;
  hConnect : HINTERNET;
  hRequest : HINTERNET;
  lpdwBufferLength: DWORD;
  lpdwReserved    : DWORD;
  ServerName: string;
  Resource: string;
  ErrorCode : Cardinal;
  LFileSize: Int64;
begin
  ParseURL(AUrl, ServerName, Resource);
  Result := False;
  AFileSize := -1;
  hInet := InternetOpen(PChar(sUserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  if (hInet = nil) then
    begin
      ErrorCode := GetLastError;
      if AShowError then
        raise Exception.Create(Format('InternetOpen Error %d Description %s', [ErrorCode, GetWinInetError(ErrorCode)]));
    end;
  try
    hConnect := InternetConnect(hInet, PChar(ServerName), INTERNET_DEFAULT_HTTP_PORT, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
    if ((hConnect = nil) and AShowError) then
      begin
        ErrorCode := GetLastError;
        raise Exception.Create(Format('InternetConnect Error %d Description %s', [ErrorCode, GetWinInetError(ErrorCode)]));
      end;
    try
      hRequest := HttpOpenRequest(hConnect, PChar('HEAD'), PChar(Resource), nil, nil, nil, 0, 0);
        if (hRequest <> nil) then
          begin
            try
              lpdwBufferLength := SizeOf(LFileSize);
              lpdwReserved := 0;
              if ((not HttpSendRequest(hRequest, nil, 0, nil, 0)) and AShowError) then
                begin
                  ErrorCode := GetLastError;
                  raise Exception.Create(Format('HttpOpenRequest Error %d Description %s', [ErrorCode, GetWinInetError(ErrorCode)]));
                end;
             if ((not HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH or HTTP_QUERY_FLAG_NUMBER, @LFileSize, lpdwBufferLength, lpdwReserved)) and AShowError) then
               begin
                  ErrorCode := GetLastError;
                  raise Exception.Create(Format('HttpQueryInfo Error %d Description %s', [ErrorCode, GetWinInetError(ErrorCode)]));
               end
               else
               begin
                 AFileSize := LFileSize;
                 Result := (AFileSize > 0);
               end;
            finally
              InternetCloseHandle(hRequest);
            end;
          end
          else
          if AShowError then
            begin
              ErrorCode := GetLastError;
              raise Exception.Create(Format('HttpOpenRequest Error %d Description %s', [ErrorCode, GetWinInetError(ErrorCode)]));
            end;
    finally
      InternetCloseHandle(hConnect);
    end;
  finally
    InternetCloseHandle(hInet);
  end;
end;

function Download(const AURL, AFileName: string): Boolean;
const
  BufferSize = oneKB;
var
  hSession, hURL: HInternet;
  Buffer: array[1..BufferSize] of Byte;
  BufferLen: DWORD;
  F: File;
  BytesLoaded, BytesTotal, BytesCalc: Int64;
begin
  Result := False;

  if (not GetRemoteFileSize(AURL, True, BytesTotal)) then
    Exit;

  hSession := InternetOpen('', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ;

  // Establish the secure connection
  InternetConnect (hSession, PChar(AURL), INTERNET_DEFAULT_HTTPS_PORT, PChar(''), PChar(''), INTERNET_SERVICE_HTTP, 0, 0);

  try
    hURL := InternetOpenURL(hSession, PChar(AURL), nil, 0, INTERNET_FLAG_RELOAD, 0);
    BytesLoaded := 0;
    try
      AssignFile(f, AFileName);
      Rewrite(f,1);
      try
        repeat
          InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen) ;
          BlockWrite(f, Buffer, BufferLen);
          if (BytesTotal > 0) then
            begin
              Inc(BytesLoaded, BufferLen);
              BytesCalc := (BytesLoaded * 100 div BytesTotal);
            end;
        until BufferLen = 0;
      finally
        CloseFile(f) ;
        Result := True;
      end;
    finally
      InternetCloseHandle(hURL);
    end
  finally
    InternetCloseHandle(hSession);
  end;
end;

begin
  try
    Download('https://www.receitaws.com.br/v1/cnpj/27865757000102', ExtractFilePath(ParamStr(0)) + 'file.json');
    { TODO -oUser -cConsole Main : Insert code here }
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

 

I don't want to download it, i just want the response of the request that i send to the api

Share this post


Link to post

The thing is, the error occurs when i pass the method GET(). So I don't have anything to save, or not save, because a don't have a response coming from the request.

Share this post


Link to post
22 hours ago, Zazhir said:

I tried several ways to make this request, but all of them lead me to the following error


error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version

or this one 


error:1409442E:SSL routines:SSL3_READ_BYTES:tlsv1 alert protocol version

 

I was able to connect to your specified URL using a web browser with TLS 1.2, and it received a response just fine.  So you should be able to get a similar response using Indy with TLS 1.2, too.  Have you tried using a packet sniffer, like Wireshark, to look at the actual TLS handshake that TIdSSLIOHandlerSocketOpenSSL is sending, to make sure it is really attempting to use TLS 1.2, and not say TLS 1.0 instead?  Which version of the OpenSSL DLLs are you using, exactly?  Does Indy's IsOpenSSL_TLSv1_2_Available() function in the IdSSLOpenSSLHeaders unit return True or False when the error occurs?

22 hours ago, Zazhir said:

Below is one of the functions I did, but that doesn't bring me anything in the request response, and gives me the erros bellow:

Offhand, that code looks ok, as far as setting up the SSLIOHandler, though I do have a few comments (not related to the TLS error) about the rest of the code:

  • Why are you setting the Request.ContentType and Request.ContentLength properties when you are not sending any data to the server?
  • Why are you setting the Request.Accept property, instead of using the default?  Both values include '*/*', so you are not really gaining anything, especially since the server's response is JSON, which is not specified in either value, so caught by '*/*' anyway.
  • Why are you setting the Request.Host property to a different hostname than is specified in the URL?
  • Do not set the Request.AcceptEncoding manually, let TIdHTTP manage that for you. If you want to support compressed responses, you need to assign a compressor component to the TIdHTTP.Compressor property, in which case TIdHTTP will then set the Request.AcceptEncoding property based on the compressor's actual capabilities.
  • Thanks 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×