Search code examples
androiddelphihttprequestbasic-authenticationpascal

Incompatible types: 'System.TArray<System.Net.URLClient.TNameValuePair>' and 'TNameValuePair' when using basic authentication header


I've been trying to use the NetHTTPRequest & NetHTTPClient components in Delphi to issue a basic authentication request, but I've been having trouble with the NetHTTPRequest.Get method...

Basically, the method needs three parameters, namely URL(String), memory stream, and the header of the type TNetHeader.

I don't know why, but when I try to pass my newly created header, I get the error mentionned in the title, namely

Incompatible types: 'System.TArray<System.Net.URLClient.TNameValuePair>' and 'TNameValuePair'

I don't know if I have to cast, and If I have to, cast it to what?

Of course, If I don't pass on the basic auth header, the server just returns a 401 because it doesn't see any credentials or header to decode...

Here is the code :

procedure TForm1.Button1Click(Sender: TObject);
var
  HTTPResponseString: String;

begin
  if IsLoggedIn = False then
  begin
    if Edit2.Text = '' then
    begin
      ShowMessage('Password cannot be empty');
      exit;
    end;

    BasicAuth := username + ':' + Edit2.Text; // + '£';
    AuthentificationPacket := EncodeBase64(UTF8Bytes(utf8string(BasicAuth)));

    HTTPHeader := TNetHeader.Create('Authorization: Basic', AuthentificationPacket);

    try
      HTTPResponseLogin := NetHTTPRequest1.Get(HTTPLoginRequest, nil, HTTPHeader);

      ShowMessage(HTTPResponselogin.ContentAsString());
      IsLoggedIn := True;

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

    end;

    Button1.Text := 'LOG OFF';
  end
  else if IsLoggedIn then
  begin
    Edit1.Text := '';
    Edit2.Text := '';
    username := '';
    password := '';
    tagid := '';

    Button1.Enabled := False;
    Button1.Text := 'LOG IN';
    IsLoggedIn := False;

    Timer1.Enabled := False;
    IdleTimer := 0;

    Application.OnIdle := nil;
  end;

end;

The problematic line is of course, the NetHTTPRequest1.Get(HTTPLoginRequest, nil, HTTPHeader);

Where HTTPHeader is marked as incompatible...

Any help is appreciated!


Solution

  • Look at the declaration of TNetHTTPRequest.Get() more carefully:

    function Get(const AURL: string; const AResponseContent: TStream = nil; const AHeaders: TNetHeaders = nil): IHTTPResponse;
    

    The 3rd parameter takes a TNetHeaders(plural), but you are passing it a TNetHeader (singular) instead. It wants an array of name/value pairs.

    Also, Basic is not part of an Authorization header's name, it is part of its value instead.

    Try something more like this:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      BasicAuth, AuthentificationPacket: string;
      HTTPHeader: TNetHeader;
    begin
      if not IsLoggedIn then
      begin
        if Edit2.Text = '' then
        begin
          ShowMessage('Password cannot be empty');
          Exit;
        end;
    
        BasicAuth := username + ':' + Edit2.Text; // + '£';
        AuthentificationPacket := 'Basic ' + EncodeBase64(UTF8Bytes(UTF8String(BasicAuth)));
    
        HTTPHeader := TNetHeader.Create('Authorization', AuthentificationPacket);
    
        try
          ShowMessage(NetHTTPRequest1.Get(HTTPLoginRequest, nil, [HTTPHeader]).ContentAsString());
        except
          on E: Exception do begin
            ShowMessage(E.Message);
            Exit;
          end;
        end;
    
        IsLoggedIn := True;
        Button1.Text := 'LOG OFF';
      end
      else
      begin
        Edit1.Text := '';
        Edit2.Text := '';
        username := '';
        password := '';
        tagid := '';
    
        Button1.Enabled := False;
        Button1.Text := 'LOG IN';
        IsLoggedIn := False;
    
        Timer1.Enabled := False;
        IdleTimer := 0;
    
        Application.OnIdle := nil;
      end;
    end;
    

    Alternatively, you can use the TNetHTTPRequest.CustomHeaders property instead of the AHeaders parameter:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      BasicAuth: string;
    begin
      if not IsLoggedIn then
      begin
        if Edit2.Text = '' then
        begin
          ShowMessage('Password cannot be empty');
          Exit;
        end;
    
        BasicAuth := username + ':' + Edit2.Text; // + '£';
        NetHTTPRequest1.CustomHeaders['Authorization'] := 'Basic ' + EncodeBase64(UTF8Bytes(UTF8String(BasicAuth));
    
        try
          ShowMessage(NetHTTPRequest1.Get(HTTPLoginRequest).ContentAsString());
        except
          on E: Exception do begin
            ShowMessage(E.Message);
            Exit;
          end;
        end;
    
        IsLoggedIn := True;
        Button1.Text := 'LOG OFF';
      end
      else
      begin
        Edit1.Text := '';
        Edit2.Text := '';
        username := '';
        password := '';
        tagid := '';
    
        Button1.Enabled := False;
        Button1.Text := 'LOG IN';
        IsLoggedIn := False;
    
        Timer1.Enabled := False;
        IdleTimer := 0;
    
        Application.OnIdle := nil;
      end;
    end;