Search code examples
htmldelphidelphi-xe2indyindy10

Login to site using idhttp


I am trying to login to a website via delphi / indy. Currently all I have is a button (used to send a password / username) it calls this procedure.

procedure TForm5.Login(name: string; Pass: string);
var
UserID :string;
Password :string;
res :TStringStream;
details :Tstringlist;
multiformupload: TIdMultiPartFormDataStream;
begin
//create ini file to hold password / usesr name
        UserID:=name;
        Password:=pass;

        Res  := TStringStream.Create();
        MultiFormUpload := TIdMultiPartFormDataStream.Create;

        MultiFormUpload.AddFormField('user',UserID);
        MultiformUpload.AddFormField('pass',Password);
        idhttp1.Request.ContentType := '8bit';
        //idhttp1.Get('http://codeelf.com',res);
        idhttp1.Post('http://codeelf.com/games/the-grid-2/grid',Multiformupload,res);
        memo1.Lines.LoadFromStream(res);

        res.Free;
end;

When I look at the site code, i have this.

 <form id="gridForm" action="" method="post" onsubmit="return checkLoginForm()">
      <table align="left" border="0" cellspacing="2" cellpadding="2">
         <tr>
            <td align="left" id="my_username">Username:</td>
            <td align="right"><input type="text" id="user" name="user" maxlength="12" autocomplete="off" /></td>
         </tr>
         <tr>
            <td align="left" id="my_password">Password:</td>
            <td align="right"><input type="password" id="pass" name="pass" maxlength="20" /></td>
         </tr>
         <tr>
            <td colspan="2" align="right">
              &nbsp;</td>
         </tr>
         <tr>
            <td colspan="2" align="right">
               <input id="submission" type="submit" class="button" name="sublogin" value="Login" /></td>
         </tr>

So the submission button value is just login. Thus i dont know where to POST the data. How can i find this out? And once i do find out the url, I should just be able to add it to the idhttp1.Post correct?


Solution

  • There are a few problems with your code:

    1. you are not submitting everything that is in the login form. You must do so. That includes the value of the login button itself, since it has name and id values assigned. Some servers require that button value.

    2. you are setting the TIdHTTP.Request.ContentType to an invalid value. However, it happens that TIdHTTP.Post(TIdMultipartFormDataStream) ignores a user-provided ContentType and uses the TIdMultipartFormDataStream.RequestContentType property instead. So this does not affect your login, but it is still a bug in your code.

    3. you are ignoring the response's charset when loading the response data into the TMemo. You should use the overloaded version of TIdHTTP.Post() that returns String and assign that to the TMemo.Text property. Let TIdHTTP handle the charset decoding for you.

    4. you are leaking the TIdMultipartFormDataStream object.

    Try this:

    procedure TForm5.Login(name: string; Pass: string);
    var
      MultiFormUpload: TIdMultiPartFormDataStream;
    begin
      MultiFormUpload := TIdMultiPartFormDataStream.Create;
      try
        MultiFormUpload.AddFormField('user', name);
        MultiFormUpload.AddFormField('pass', pass);
        MultiFormUpload.AddFormField('sublogin', 'Login');
    
        //IdHTTP1.Get('http://codeelf.com');
        Memo1.Text := IdHTTP1.Post('http://codeelf.com/games/the-grid-2/grid', MultiFormUpload);
      finally
        MultiFormUpload.Free;
      end;
    end;
    

    That being said, some servers send cookies to the client when it requests the login page, and then those cookies need to be sent back as part of the login process. If posting to the login URL by itself does not work, try retrieving the login page first, then post your login credentials, and let TIdHTTP handle the cookies for you:

    procedure TForm5.Login(name: string; Pass: string);
    var
      MultiFormUpload: TIdMultiPartFormDataStream;
    begin
      MultiFormUpload := TIdMultiPartFormDataStream.Create;
      try
        MultiFormUpload.AddFormField('user', name);
        MultiFormUpload.AddFormField('pass', pass);
        MultiFormUpload.AddFormField('sublogin', 'Login');
    
        IdHTTP1.Get('http://codeelf.com/games/the-grid-2/grid', TStream(nil));
        Memo1.Text := IdHTTP1.Post('http://codeelf.com/games/the-grid-2/grid', MultiFormUpload);
      finally
        MultiFormUpload.Free;
      end;
    end;
    

    Update: there is another problem with your original code. The HTML login form does not ask for a multipart/form-data post to begin with, so TIdMultipartFormDataStream is the wrong class to use. Use a TStringList instead so TIdHTTP.Post() will send an application/x-www-form-urlencoded post instead:

    procedure TForm5.Login(name: string; Pass: string);
    var
      Params: TStringList;
    begin
      Params := TStringList.Create;
      try
        Params.Add('user='+name);
        Params.Add('pass='+pass);
        Params.Add('sublogin=Login');
    
        //IdHTTP1.Get('http://codeelf.com');
        Memo1.Text := IdHTTP1.Post('http://codeelf.com/games/the-grid-2/grid', Params);
      finally
        Params.Free;
      end;
    end;