You are mismanaging the server's cookies. TIdURI.Create()
expects a full URL, and AddServerCookie()
requires a full URL so it can process Paths, differentiate between HTTP and HTTPS cookies, etc. But you are passing TIdURI
only a domain name by itself, which is not enough.
Why are you re-adding cookies back into the TIdCookieManager
when they already exist in the TIdCookieManager
? And why are you setting the CustomHeaders.Values['Cookie']
property manually? Do not do those things. All you need to do is assign the TIdCookieManager
to the TIdHTTP.CookieManager
property and make sure that the TIdHTTP.AllowCookies
property is set to True. That's it. TIdHTTP
and TIdCookieManager
will then do all of the hard work of receiving, managing, and sending cookies for you. As long as you use the same TIdCookieManager
object for multiple HTTP requests (even if you don't use the same TIdHTTP
object), then cookies will automatically persist from one request to the next as needed.
If you re-use the same TIdHTTP
object then you don't have to worry about creating a TIdCookieManager
at all, since TIdHTTP will create one internally if needed and it will be used for the lifetime of the TIdHTTP
object.
Try this instead:
unit Forms.MainForm;
interface
uses
Winapi.Windows, Winapi.Messages,
System.SysUtils, System.Variants, System.Classes,
Vcl.Forms, Vcl.Graphics, Vcl.Dialogs, Vcl.Controls, Vcl.ExtCtrls,
Vcl.StdCtrls,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP,
IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL,
GIFImg;
type
TMainForm = class(TForm)
mem: TMemo;
IdHttp: TIdHTTP;
IdSSLHandlerSocket: TIdSSLIOHandlerSocketOpenSSL;
panBottom: TPanel;
btnGo: TButton;
imgCaptcha: TImage;
edtKey: TEdit;
edtCode: TEdit;
lblInit: TLabel;
procedure FormShow(Sender: TObject);
procedure lblInitClick(Sender: TObject);
procedure btnGoClick(Sender: TObject);
private
viewState, eventValidate: string;
procedure GetHiddenFieldValues(html: string);
procedure p_Execute;
end;
var
MainForm: TMainForm;
const
HOST = 'http://www.nfe.fazenda.gov.br';
URLIMG = HOST+'/scripts/srf/intercepta/captcha.aspx?opt=image';
URLGET = HOST+'/portal/consulta.aspx?tipoConsulta=completa&tipoConteudo=XbSeqxE8pl8=';
URLPOST = HOST+'/portal/consultaCompleta.aspx?tipoConteudo=XbSeqxE8pl8=';
implementation
{$R *.dfm}
procedure TMainForm.FormShow(Sender: TObject);
begin
lblInitClick(Sender);
end;
procedure TMainForm.lblInitClick(Sender: TObject);
var
response: TMemoryStream;
gif: TGIFImage;
html: string;
begin
html := IdHttp.Get(URLGET);
mem.Text := html;
GetHiddenFieldValues(html);
gif := TGIFImage.Create;
try
response := TMemoryStream.Create;
try
IdHttp.Get(URLIMG, response);
response.Position := 0;
gif.LoadFromStream(response);
finally
response.Free;
end;
imgCaptcha.Picture.Assign(gif);
finally
gif.Free;
end;
end;
procedure TMainForm.btnGoClick(Sender: TObject);
begin
p_Execute;
end;
procedure TMainForm.GetHiddenFieldValues(html: string);
var
nIni, nLen: integer;
cVal: string;
const
TAG_VIEWSTATE = '<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="';
TAG_EVENTVALIDATION = '<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="';
begin
nIni := Pos(TAG_VIEWSTATE, html);
nLen := Length(TAG_VIEWSTATE);
cVal := Copy(html,nIni+nLen, Length(html));
cVal := Copy(cVal, 1, Pos('" />', cVal)-1);
viewState := cVal;
nIni := Pos(TAG_EVENTVALIDATION, html);
nLen := Length(TAG_EVENTVALIDATION);
cVal := Copy(html,nIni+nLen, Length(html));
cVal := Copy(cVal, 1, Pos('" />', cVal)-1);
eventValidate := cVal;
end;
procedure TMainForm.p_Execute;
var
params: TStringList;
begin
params := TStringList.Create;
try
params.Add('__VIEWSTATE=' + viewState);
params.Add('__EVENTVALIDATION=' + eventValidate);
params.Add('__EVENTTARGET=');
params.Add('__EVENTARGUMENT=');
params.Add('ctl00$txtPalavraChave=');
params.Add('ctl00$ContentPlaceHolder1$txtChaveAcessoCompleta=' + edtKey.Text);
params.Add('ctl00$ContentPlaceHolder1$txtCaptcha=' + edtCode.Text);
params.Add('ctl00$ContentPlaceHolder1$btnConsultar=Continuar');
params.Add('hiddenInputToUpdateATBuffer_CommonToolkitScripts=1');
mem.Text := IdHttp.Post(URLPOST, params);
finally
params.Free;
end;
end;
end.
Now, with that said, there are other problems:
1) You are posting your params
to http://www.nfe.fazenda.gov.br/portal/consultaCompleta.aspx?tipoConteudo=XbSeqxE8pl8=
, but when I go to the login URL with a web browser and look at the HTML, I see that it actually wants the form posted to http://www.nfe.fazenda.gov.br/consulta.aspx?tipoConsulta=completa&tipoConteudo=XbSeqxE8pl8=
instead. You are missing the tipoConsulta=completa
portion.
2) You are parsing out the actual __VIEWSTATE
and __EVENTVALIDATION
values from the HTML, but are sending blank __EVENTTARGET
and __EVENTARGUMENT
values. Those values are blank in the HTML, but they are actually filled in dynamically via client-side scripts.
3) there are other <input>
fields in the HTML that you are not posting.
A web browser posts every <input>
field that has a non-empty value
assigned to it, whether that value is assigned statically or dynamically. You need to do the same in your application. The HTTP server is likely to expect all of those values to be sent. Use a packet sniffer, such as Wireshark or Fiddler, to see what a web browser actually posts, and then replicate that same behavior in your code.