Help on idhttps

Hello guys

I developed a procedure where I could get the result from my idhttp,

but it doesn't even work with this simple line:

https://khanhomolog.skyinone.net/v2/api/users/

that should return me:

{"detail":"As credenciais de autenticação não foram fornecidas."}

what is wrong in my code?

procedureTForm1.RetornoHttpGet2(): String;

var
  S: TStringList;
  M: TStream;
begin
 S := TStringList.Create;
 M := TMemoryStream.Create;
 try
   S.Values['token']     := 'ace49f940a034ea4a35c8157d462744a';
   S.Values['nome']      := 'fabio';
   S.Values['sobrenome'] := 'marq';
   S.Values['email']     := 'meuemail.gg@ksac.com.br';
   S.Values['ativo']     := 'True';
   S.Values['username']  := 'denis';
   S.Values['password']  := '190679';
   S.Values['cli_uuid']  := 'xxxxxxxxxxxxxx';


    IdHTTP1.Request.Accept         := 'text/html, */*';
    IdHTTP1.Request.UserAgent      := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';
    IdHTTP1.Request.ContentType    := 'application/x-www-form-urlencoded';
    IdHTTP1.Request.AcceptCharSet  := 'ISO-8859-1,utf-8;q=0.7,*;q=0.7';
    IdHTTP1.Request.AcceptLanguage := 'pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4';
    IdHTTP1.HandleRedirects        := True;

   IdHTTP1.Post('https://khanhomolog.skyinone.net/v2/api/users/', S, M);
   Memo1.Lines.Add(Format('Response Code: %d', [IdHTTP1.ResponseCode]));
   Memo1.Lines.Add(Format('Response Text: %s', [IdHTTP1.ResponseText]));

   M.Position := 0;
   S.LoadFromStream(M);
   Memo1.Lines.AddStrings(S);
 finally
   S.Free;
   M.Free;
 end;
end;

Open in new window


Could you help me?
Thanks a lot
LVL 1
hidrauAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Sinisa VukSoftware architectCommented:
This is not so easy... Because you call https - you need to add ssl stuff to Indy connection... Second, I assume that that v2 api needs json format of data... not common string list.

There are few examples on Embarcadero forum/wikipage but for unknown reason about few days server is down....
1
hidrauAuthor Commented:
Sinisa, do you know if it is possible to do that without indy components? Do you have any idea?
0
Sinisa VukSoftware architectCommented:
Do you have any document about api (usage)?
One of the best libs is Delphi REST client API by fabriciocolombo....
It support json, you can choose to use Indy, win native wininet,winhttp,... as a transport....Look for example there...
0
CompTIA Security+

Learn the essential functions of CompTIA Security+, which establishes the core knowledge required of any cybersecurity role and leads professionals into intermediate-level cybersecurity jobs.

hidrauAuthor Commented:
hi Sinisa,

I did a simple example and drop an indy component named IdSSLIOHandlerSocketOpenSSL1

This component uses two lib:  libeay32.dll  and ssleay32.dll

It works fine when I compile it in my delphi XE7, but in the company that I work, the company has the delphi 2007 and it doesn't work.

It complains " could not load SSL library "

I haven't made any test with another components, only using Indy

regards
0
Sinisa VukSoftware architectCommented:
This is not a problem. You need older openssl dlls... Delphi 2007 uses Indy 9 and newer XE x uses Indy 10 - all works but with a little incompatibility...
0
hidrauAuthor Commented:
I noticed that in the file IdSSLOpenSSLHeaders.pas the the version of libeay32.dll must be 0.9.6a.
I download all the version from this site http://indy.fulgan.com/SSL/Archive/ and none of them worked :(

I made a comparation with IdSSLOpenSSLHeaders.pas that is installed in delphi XE7 and 2007, I could notice that there are many differences, although I updated the version indy from 2007 to indy 10 for another reasons, it doesn't work.

I need a way to get the latest version for indy, I noticed that was realeased indy 11 but I didn't find it. Do you have any idea about where could I find? Maybe this new version will solve the problem.

I only find the version 10 that in the site informs that is an old version:

http://www.indyproject.org/Sockets/Download/Files/Indy10.EN.aspx
0
Sinisa VukSoftware architectCommented:
I think latest version of Indy 10 is here... but available through svt too... and for that version you should go to here ....  and for that reason (how to find proper dll for Indy) I use that Rest client lib...
1

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
hidrauAuthor Commented:
Sinisa,

I got the result that I need with WinInet

take a look at the code:

uses WinInet;

function GetUrlContent(const Url: string): string;
var
  NetHandle: HINTERNET;
  UrlHandle: HINTERNET;
  Buffer: array[0..1024] of Char;
  BytesRead: dWord;
begin
  Result := '';
  NetHandle := InternetOpen('Delphi 5.x', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);

  if Assigned(NetHandle) then 
  begin
    UrlHandle := InternetOpenUrl(NetHandle, PChar(Url), nil, 0, INTERNET_FLAG_RELOAD, 0);

    if Assigned(UrlHandle) then
      { UrlHandle valid? Proceed with download }
    begin
      FillChar(Buffer, SizeOf(Buffer), 0);
      repeat
        Result := Result + Buffer;
        FillChar(Buffer, SizeOf(Buffer), 0);
        InternetReadFile(UrlHandle, @Buffer, SizeOf(Buffer), BytesRead);
      until BytesRead = 0;
      InternetCloseHandle(UrlHandle);
    end
    else
      { UrlHandle is not valid. Raise an exception. }
      raise Exception.CreateFmt('Cannot open URL %s', [Url]);

    InternetCloseHandle(NetHandle);
  end
  else
    { NetHandle is not valid. Raise an exception }
    raise Exception.Create('Unable to initialize Wininet');
end;

Open in new window


I just need to make some test and undestant whether I am not get some limitations.
0
Sinisa VukSoftware architectCommented:
This code is for downloading files/content from internet... do not have any authentication part (if you need it)...
But wininet is good - because windows handle https (ssl) transparently...
1
hidrauAuthor Commented:
Hummmm, that could be a problem " authentication " - I need to check it.

I also got another code much more interesting where I can determine the Get or Post method. The problem is being the function ParseUrl(AUrl) that delphis doesn't have and I need to solve it. Do you know that function?

function request(const AUrl, AData: AnsiString; blnSSL: Boolean = True): AnsiString;
var
  aBuffer     : Array[0..4096] of Char;
  Header      : TStringStream;
  BufStream   : TMemoryStream;
  sMethod     : AnsiString;
  BytesRead   : Cardinal;
  pSession    : HINTERNET;
  pConnection : HINTERNET;
  pRequest    : HINTERNET;
  parsedURL   : TStringArray;
  port        : Integer;
  flags       : DWord;
begin

  ParsedUrl := ParseUrl(AUrl);

  Result := '';

  pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);

  if Assigned(pSession) then
  try
    if blnSSL then
      Port := INTERNET_DEFAULT_HTTPS_PORT
    else
      Port := INTERNET_DEFAULT_HTTP_PORT;
    pConnection := InternetConnect(pSession, PChar( uri.Host {ParsedUrl[0]}), port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);

    if Assigned(pConnection) then
    try
      if (AData = '') then
        sMethod := 'GET'
      else
        sMethod := 'POST';

      if blnSSL then
        flags := INTERNET_FLAG_SECURE or INTERNET_FLAG_KEEP_CONNECTION
      else
        flags := INTERNET_SERVICE_HTTP;

      pRequest := HTTPOpenRequest(pConnection, PChar(sMethod), PChar(ParsedUrl[1]), nil, nil, nil, flags, 0);

      if Assigned(pRequest) then
      try
        Header := TStringStream.Create('');
        try
          with Header do
          begin
            WriteString('Host: ' + ParsedUrl[0] + sLineBreak);
            WriteString('User-Agent: Custom program 1.0'+SLineBreak);
            WriteString('Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'+SLineBreak);
            WriteString('Accept-Language: en-us,en;q=0.5' + SLineBreak);
            WriteString('Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7'+SLineBreak);
            WriteString('Keep-Alive: 300'+ SLineBreak);
            WriteString('Connection: keep-alive'+ SlineBreak+SLineBreak);
          end;

          HttpAddRequestHeaders(pRequest, PChar(Header.DataString), Length(Header.DataString), HTTP_ADDREQ_FLAG_ADD);

          if HTTPSendRequest(pRequest, nil, 0, Pointer(AData), Length(AData)) then
          begin
            BufStream := TMemoryStream.Create;
            try
              while InternetReadFile(pRequest, @aBuffer, SizeOf(aBuffer), BytesRead) do
              begin
                if (BytesRead = 0) then Break;
                BufStream.Write(aBuffer, BytesRead);
              end;

              aBuffer[0] := #0;
              BufStream.Write(aBuffer, 1);
              Result := PChar(BufStream.Memory);
            finally
              BufStream.Free;
            end;
          end;
        finally
          Header.Free;
        end;
      finally
        InternetCloseHandle(pRequest);
      end;
    finally
      InternetCloseHandle(pConnection);
    end;
  finally
    InternetCloseHandle(pSession);
  end;
end;

Open in new window

0
Sinisa VukSoftware architectCommented:
You can find it in extended Winhttp unit somewhere on github sources ... like in this project - find ACBr_WinHttp.pas source in there ...
0
hidrauAuthor Commented:
Hello Sinisa.

I checked the code and I could see that the code use only two parts of the parsedURL variable:

Here:

InternetConnect(pSession, PChar( ParsedUrl[0]), port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);

and

HTTPOpenRequest(pConnection, PChar(sMethod), PChar(ParsedUrl[1]), nil, nil, nil, flags, 0);


I am not sure if ParsedUrl[0] is the entire URL or part of if, and the second ParsedUrl[1] are the parameters.

this is my entire URL:

https://khanhomolog.skyinone.net/v2/api/users/?token=xxxxxxxssffdfdfdf8157d4620c3a&nome=denis&sobrenome=alexxxxx&email=alex.xxxxxx%40bol.com.br&ativo=true&username=alexs&password=74855&cli_uuid=aaa54a-31d2-4d2e-bab6-7c136cf75ded

Open in new window


do you have any idea what parts are from my URL?
I also tried to find that function for all project ACBR and nothing.  But I think I can solve understand well what part of url I should use.
0
Sinisa VukSoftware architectCommented:
You can use Indy (function) for that part... Look at my changes...
uses ...., IdURI;
...
function request(const AUrl, AData: AnsiString; blnSSL: Boolean = True): AnsiString;
var
  aBuffer     : Array[0..4096] of Char;
  Header      : TStringStream;
  BufStream   : TMemoryStream;
  sMethod     : AnsiString;
  BytesRead   : Cardinal;
  pSession    : HINTERNET;
  pConnection : HINTERNET;
  pRequest    : HINTERNET;
  //parsedURL   : TStringArray;
  port        : Integer;
  flags       : DWord;
  uri: TIdURI; //****added 
begin
  uri := TIdURI.Create(AUrl);

  Result := '';

  pSession := InternetOpen(nil, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);

  if Assigned(pSession) then
  try
    if uri.Protocol='https' then
      Port := INTERNET_DEFAULT_HTTPS_PORT
    else
      Port := INTERNET_DEFAULT_HTTP_PORT;
    pConnection := InternetConnect(pSession, PChar( uri.Host ), port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);

    if Assigned(pConnection) then
    try
      if (AData = '') then
        sMethod := 'GET'
      else
        sMethod := 'POST';

      if uri.Protocol='https' then
        flags := INTERNET_FLAG_SECURE or INTERNET_FLAG_KEEP_CONNECTION
      else
        flags := INTERNET_SERVICE_HTTP;

      pRequest := HTTPOpenRequest(pConnection, PChar(sMethod), PChar( uri.Document), nil, nil, nil, flags, 0);


....

Open in new window

1
hidrauAuthor Commented:
Hi Sinisa,

Thanks very much for your help.

I discovered that I will need to use get, post, patch, delete method and when I use the method post, I need to send the information part with URL and the parameters in Json :(

I think I have to come back to indy and try it to work anyway.  The version of my delphi is 2007.

I will install the indy that you told me to be the last version and try it.

But your help on the function gave a great light in my way.

All those stuffs and issue are new for me :(
0
hidrauAuthor Commented:
On the other hand, I think it is better to go to https://github.com/fabriciocolombo/delphi-rest-client-api   as you told me.

I am gonna take a look at it carefully  -

My only concern is that component doesn't work for the latest delphi version because the company will uptodate from Ddelphi 2007 to Delphi tokio soon.
0
Sinisa VukSoftware architectCommented:
I suggest delphi-rest-client lib. I use it in Delphi 6, Delphi 2007, and there is a state that works for XE3. Code is not complicated and with (possible) minor fixes should work on latest versions... Another fork of this component  - renamed it because Delphi from XE5 started to use same name for own similar lib. So you can use this one...
0
hidrauAuthor Commented:
Sinisa, with Indy that you passed me, worked fine.

I am gonna use it.
0
hidrauAuthor Commented:
Thanks a lot Sinisa
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.