Indy TIdHTTP URI with login/password not working

让人想犯罪 __ 提交于 2019-12-03 22:28:04

# is an illegal character in a URL prior to the fragment portion of the URL, that is why it has to be encoded as %23 when used in other areas of the URL.

A username/password is not actually part of a real URL, that is why they get stripped off when TIdHTTP sends the URL to a server (monitor the traffic of any web browser and you will see the same thing happen).

To use HTTP authentication with TIdHTTP, you need to use the TIdHTTP.Request.Username and TIdHTTP.Request.Password properties instead (and you do not need to URL encode the values), eg:

IdHTTP1.Request.Username := 'user';
IdHTTP1.Request.Password := 'pass_with_#_sign';
IdHTTP1.Get('http://address:port/somespecificpath/');

If you pass a URL that has an encoded username/password in it, TIdHTTP will strip off the values and move them to the Request.Username and Request.Password properties for you, but they will remain in their original encoded format, eg:

IdHTTP1.Get('http://user:pass_with_%23_sign@address:port/somespecificpath/')
// this will set Request.Username to 'user',
// Request.Password to 'pass_with_%23_sign', and
// send a request for 'http://address:port/somespecificpath/'

If you are being given an encoded URL to start with, you can use the TIdURI class to manually decode it prior to then calling TIdHTTP.Get(), eg:

var
  RequestUrl: string;
  Uri: TIdURI;
begin
  RequestUrl := 'http://user:pass_with_%23_sign@address:port/somespecificpath/';
  ...
  Uri := TIdURI.Create(RequestURL);
  try
    IdHTTP1.Request.Username := TIdURI.URLDecode(Uri.UserName);
    IdHTTP1.Request.Password := TIdURI.URLDecode(Uri.Password);
    RequestURL := Uri.URI;
  finally
    Uri.Free;
  end;
  IdHTTP1.Get(RequestUrl);
  ...
end;

Update: either way, make sure you have appropriate IdAuthentication... units, or the IdAllAuthentications unit, in your uses clause to enable Indy's HTTP authentication classes for TIdHTTP to use.

I have solved the issue by sending two sequential Get requests. After observing the packet captures between a browser and Indy, I noticed browsers would always send one request without credentials, and then another identical request with credentials. So it only sends the credentials when it needs to. Indy was only sending one request, but if I send another request right afterward, I have success.

So, the request now looks like...

FWeb.Get(U);
FWeb.Get(U, R);

Of course it really should be in the order of "If the first request is unauthorized, then send another request with credentials".

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!