0
votes

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?

2
The browser will post the form data to the URI in the form action attribute. If it is not specified, the browser will post the form data to the URI of the document which contains the form. - mjn
@Mjn it seems to post to the document as i did find this. document.getElementById('submission').click(); But how do i call this from idhttp? Is this a javascript? as i see no function called click on the page source - Glen Morse
The form will not be "posted to the document". It will be sent to to the server, and the POST request will include the same URI where the HTML containing the form came from. - mjn
The click() is just the internal Javascript code which will simulate a click on the specified element. In this case it will simulate a click on the submit button of the the form. - mjn
Show how would i write the POST url to this site? - Glen Morse

2 Answers

2
votes

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;
1
votes

The POST must go to the same URL where you retrieved the HTML page from as the action attribute is empty.

Depending on the server, a successful login will send cookies back to the client which need to be included with the next requests.

Wether cookies are used or not can be found out if you analyze the browser/client communication with Firebug or a HTTP proxy tool like Fiddler.

If the server uses proxies, you need to add cookie support to your client code. Indy supports HTTP cookies transparently (TIdCookieManager).