I need to program an application with Delphi that goes into this site and uses the form to get an .dat file.
http://www.bmfbovespa.com.br/BancoTitulosBTC/PosicoesEmAberto.aspx?Idioma=pt-br
Via browser I just click on the second "buscar" and get the file automatically.
This is what I got so far:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils, idHTTP, Classes, MSHTML, SHDocVw, Httpapp, System.Variants, idURI;
var
http: TIdHttp;
url: string;
code: integer;
parameters: TStringList;
Response: TStringStream;
Resultado: string;
MS: TMemoryStream;
begin
url := 'http://www.bmfbovespa.com.br/BancoTitulosBTC/PosicoesEmAberto.aspx?Idioma=pt-br';
http := TIdHTTP.Create(nil);
parameters := TStringList.Create;
Response := TStringStream.Create;
MS := TMemoryStream.Create;
try
try
Parameters.Add('__EVENTTARGET=');
Parameters.Add('__EVENTARGUMENT=');
Parameters.Add('__VIEWSTATE=/wEPDwUKMTI5NDMyNjQ4NA8WAh4QdGlwb1Bvc2ljYW9BdGl2bwspc1RpcG9Qb3NpY2Fv'+
'QXRpdm8sIEJvdmVzcGEuU2l0ZUJtZkJvdmVzcGEuQmFuY29UaXR1bG9zQlRDLldlYiwgVmVyc2lvbj0x'+
'LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwAFgJmDw8WCB4Ebm9kZQUk'+
'YjViNDhlNjYtZTMwMC00NTMzLTgwYzktMzI2NmM5ZDY2ODBiHgpQYXJlbnROb2RlBUsvcHQtYnIvc2Vy'+
'dmljb3MvZW1wcmVzdGltby1kZS1hdGl2b3MvZW1wcmVzdGltby1kZS1hdGl2b3MuYXNweD9JZGlvbWE9'+
'cHQtYnIeC0N1cnJlbnROb2RlBTMvYmFuY290aXR1bG9zYnRjL3Bvc2ljb2VzZW1hYmVydG8uYXNweD9'+
'JZGlvbWE9cHQtYnIeCkN1cnJlbnRVcmwFMy9CYW5jb1RpdHVsb3NCVEMvUG9zaWNvZXNFbUFiZXJ0by5'+
'hc3B4P0lkaW9tYT1wdC1icmQWAgIDD2QWAgIBD2QWCgIBD2QWCAIDDxYCHgdWaXNpYmxlaGQCDA8WBh4'+
'Hb25jbGljawUQdGhpcy52YWx1ZSA9ICcnOx4Gb25ibHVyBTFpZih0aGlzLnZhbHVlID09ICcnKSB7dGh'+
'pcy52YWx1ZT0gbm9tZVRleHRCdXNjYTt9HgpvbmtleXByZXNzBSRyZXR1cm4ga2V5UHJlc3NQZXNxdWl'+
'zYSh0aGlzLGV2ZW50KTtkAg0PDxYCHg1PbkNsaWVudENsaWNrBRxyZXR1cm4gVmVyaWZpY2FyQ2FtcG9'+
'CdXNjYSgpZGQCDg8WAh4EVGV4dAWXMzxkaXYgaWQ9J21lbnUnPjx1bCBpZD0nbWVudUhvcml6Jz48bGk'+
'gaWQ9J2FibWZib3Zlc3BhJz48YSBocmVmPScjJyBjbGFzcz0nYWJtZmJvdmVzcGEnIGlkPSdsaW5rQWJ'+
'tZic+PGltZyBzcmM9Jy9zaGFyZWQvY3NzL2ltZy90cmFuc3AuZ2lmJyAvPjwvYT48dWwgb25tb3VzZW9'+
'2ZXI9ImxpbmtBYm1mLmNsYXNzTmFtZT0nYWJtZmJvdmVzcGFob3Zlcic7IiBvbm1vdXNlb3V0PSJsaW'+
'5rQWJtZi5jbGFzc05hbWU9J2FibWZib3Zlc3BhJzsiPjxsaT48YSBocmVmPScvcHQtYnIvaW50cm9zL2'+
'ludHJvLXNvYnJlLWEtYm9sc2EuYXNweCcgdGFyZ2V0PScnPk8gcXVlIGEgQm9sc2EgZmF6PC9hPjwvbG'+
'k+PGxpPjxhIGhyZWY9Jy9wdC1ici9hLWJtZmJvdmVzcGEvdmlzaXRhcy1hLWJvbHNhL3Zpc2l0YXMtYS'+
'1ib2xzYS5hc3B4JyB0YXJnZXQ9Jyc+VmlzaXRlIGEgQm9sc2E8L2E+PC9saT48bGk+PGEgaHJlZj0nL3'+
'B0LWJyL2EtYm1mYm92ZXNwYS91bmlkYWRlcy91bmlkYWRlcy5hc3B4JyB0YXJnZXQ9Jyc+Tm9zc2FzIH'+
'VuaWRhZGVzPC9hPjwvbGk+PGxpPjxhIGhyZWY9Jy9wdC1ici9hLWJtZmJvdmVzcGEvc3VzdGVudGFiaW'+
'xpZGFkZS5hc3B4JyB0YXJnZXQ9Jyc+U3VzdGVudGFiaWxpZGFkZTwvYT48L2xpPjxsaT48YSBocmVmPS'+
'dodHRwOi8vd3d3Lmluc3RpdHV0b2JtZmJvdmVzcGEub3JnLmJyL3B0LWJyL2hvbWUuYXNwJyB0YXJnZX'+
'Q9J19ibGFuayc+SW5zdGl0dXRvIEJNJkZCT1ZFU1BBPC9hPjwvbGk+PGxpPjxhIGhyZWY9Jy9wdC1ici'+
'9hLWJtZmJvdmVzcGEvdHJhYmFsaGUtY29ub3Njby90cmFiYWxoZS1jb25vc2NvLmFzcHgnIHRhcmdldD'+
'0nJz5UcmFiYWxoZSBuYSBCb2xzYTwvYT48L2xpPjxsaT48YSBocmVmPScvc2FsYS1kZS1pbXByZW5zYS'+
'9zYWxhaW1wcmVuc2EuYXNweD9pZGlvbWE9cHQtYnInIHRhcmdldD0nJz5TYWxhIGRlIEltcHJlbnNhPC'+
'9hPjwvbGk+PC91bD48L2xpPjxsaSBpZD0nbWVyY2Fkbyc+PGEgaHJlZj0nIycgY2xhc3M9J21lcmNhZ'+
'G9zJyBpZD0nbGlua01lcmNhZG8nPjxpbWcgc3JjPScvc2hhcmVkL2Nzcy9pbWcvdHJhbnNwLmdpZicgL'+
'z48L2E+PHVsIG9ubW91c2VvdmVyPSJsaW5rTWVyY2Fkby5jbGFzc05hbWU9J21lcmNhZG9zaG92ZXInO'+
'yIgb25tb3VzZW91dD0ibGlua01lcmNhZG8uY2xhc3NOYW1lPSdtZXJjYWRvcyc7Ij48bGk+PGEgaHJlZ'+
'j0nL3B0LWJyL21lcmNhZG9zL2Fjb2VzLmFzcHgnIHRhcmdldD0nJz5Bw6fDtWVzIDwvYT48L2xpPjxsa'+
'T48YSBocmVmPScvcHQtYnIvbWVyY2Fkb3MvbWVyY2Fkb3JpYXMtZS1mdXR1cm9zLmFzcHgnIHRhcmdld'+
'D0nJz5NZXJjYWRvcmlhcyBlIEZ1dHVyb3M8L2E+PC9saT48bGk+PGEgaHJlZj0nL3B0LWJyL2ludHJvcy'+
'9pbnRyby1jYW1iaW8uYXNweCcgdGFyZ2V0PScnPkPDom1iaW88L2E+PC9saT48bGk+PGEgaHJlZj0nL3B'+
'0LWJyL2ludHJvcy9pbnRyby1hdGl2b3MuYXNweCcgdGFyZ2V0PScnPkF0aXZvczwvYT48L2xpPjxsaT'+
'48YSBocmVmPScvcHQtYnIvaW50cm9zL2ludHJvLWZ1bmRvcy5hc3B4JyB0YXJnZXQ9Jyc+RnVuZG9zIC'+
'8gRVRGczwvYT48L2xpPjxsaT48YSBocmVmPScvUmVuZGEtRml4YS9SZW5kYUZpeGEuYXNweCcgdGFyZ2'+
'V0PScnPlJlbmRhIEZpeGE8L2E+PC9saT48bGk+PGEgaHJlZj0nL3B0LWJyL2ludHJvcy9pbnRyby1vd'+
'XRyb3MtdGl0dWxvcy5hc3B4JyB0YXJnZXQ9Jyc+T3V0cm9zIFTDrXR1bG9zPC9hPjwvbGk+PC91bD48L'+
'2xpPjxsaSBpZD0nY2VudHJvZGVpbmZvcm1hY29lcyc+PGEgaHJlZj0nIycgY2xhc3M9J2NlbnRyb2Rla'+
'W5mb3JtYWNvZXMnIGlkPSdsaW5rQ2VudHJvJz48aW1nIHNyYz0nL3NoYXJlZC9jc3MvaW1nL3RyYW5zc'+
'C5naWYnIC8+PC9hPjx1bCBvbm1vdXNlb3Zlcj0ibGlua0NlbnRyby5jbGFzc05hbWU9J2NlbnRyb2Rla'+
'W5mb3JtYWNvZXNob3Zlcic7IiBvbm1vdXNlb3V0PSJsaW5rQ2VudHJvLmNsYXNzTmFtZT0nY2VudHJvZ'+
'GVpbmZvcm1hY29lcyc7Ij48bGk+PGEgaHJlZj0nL3B0LWJyL2VkdWNhY2lvbmFsL2N1cnNvcy9jdXJzb'+
'3MuYXNweCcgdGFyZ2V0PScnPkN1cnNvczwvYT48L2xpPjxsaT48YSBocmVmPScvcHQtYnIvZWR1Y2Fja'+
'W9uYWwvc2ltdWxhZG9yZXMvc2ltdWxhZG9yZXMuYXNweCcgdGFyZ2V0PScnPlNpbXVsYWRvcmVzPC9hP'+
'jwvbGk+PGxpPjxhIGhyZWY9Jy9wdC1ici9lZHVjYWNpb25hbC9vcmNhbWVudG8tcGVzc29hbC5hc3B4J'+
'yB0YXJnZXQ9Jyc+T3LDp2FtZW50byBwZXNzb2FsPC9hPjwvbGk+PGxpPjxhIGhyZWY9Jy9zaGFyZWQva'+
'WZyYW1lLmFzcHg/aWRpb21hPXB0LWJyJnVybD1odHRwOi8vd3d3LmJtZmJvdmVzcGEuY29tLmJyL3B0L'+
'WJyL2VkdWNhY2lvbmFsL2VkdWNhci9Gb3JtSW5zY3JpY2FvUGFsZXN0cmFBY2Vzc29JbnN0LmFzcCc'+
'gdGFyZ2V0PScnPlBhbGVz');
Parameters.Add('__EVENTVALIDATION=/wEWMAKU1bzjDAKatY+lDgLz2ISXCALR05XvBgKW'+
'jICHCwKn1oTUCwLzhvO8BQLzht/hDALzhsuGBALzhteEAQLzhsOpCALzhq/ODwLzhpvzBgLzhqfxAwL'+
'zhpOWCwLzhv+6AgLzhuvfCQLzhvfdBgLzhuOCDgLzhs+nBQLzhrvMDALzhsfKCQLzhrNvAvOGn5QIAv'+
'OGi7kPAvOGl7cMAvOGg9wDAvOG74ALAvOG26UCAvOG56MPAvOG08gGAvOGv+0NAo3a1W8CjNrVbwKP2'+
'tVvAo7a1W8CidrVbwKI2tVvAova1W8CitrVbwKV2tVvApTa1W8CpqKfswMCrqXL7AcChv7z9w4C4/vLv'+
'gUCo/HJ+QsCtLPk8g6HXv3ITGyMQJG6GJIiOc0sGh7cpg==');
Parameters.Add('ctl00$ucTopo$btnBusca=Busca');
Parameters.Add('ctl00$menuBOVESPASecundario=');
Parameters.Add('ctl00$contentPlaceHolderConteudo$tabPosicaoEmAberto={"State":{},"TabState":{"ctl00_contentPlaceHolderConteudo_tabPosicaoEmAberto_tabAcoes":{"Selected":true}}}');
Parameters.Add('ctl00$contentPlaceHolderConteudo$acoes$txtConsultaData$txtConsultaData=2014-07-22');
Parameters.Add('ctl00$contentPlaceHolderConteudo$acoes$txtConsultaData$txtConsultaData$dateInput=2014-07-22-00-00-00');
Parameters.Add('ctl00_contentPlaceHolderConteudo_acoes_txtConsultaData_txtConsultaData_calendar_SD=[]');
Parameters.Add('ctl00_contentPlaceHolderConteudo_acoes_txtConsultaData_txtConsultaData_calendar_AD=[[2014,5,22],[2014,7,22],[2014,7,22]]');
Parameters.Add('ctl00$contentPlaceHolderConteudo$acoes$txtConsultaEmpresa=');
Parameters.Add('ctl00$contentPlaceHolderConteudo$acoes$txtConsultaDataDownload$txtConsultaDataDownload=2014-07-02');
Parameters.Add('ctl00$contentPlaceHolderConteudo$acoes$txtConsultaDataDownload$txtConsultaDataDownload$dateInput=2014-07-02-00-00-00');
Parameters.Add('ctl00_contentPlaceHolderConteudo_acoes_txtConsultaDataDownload_txtConsultaDataDownload_calendar_SD=[]');
Parameters.Add('ctl00_contentPlaceHolderConteudo_acoes_txtConsultaDataDownload_txtConsultaDataDownload_calendar_AD=[[2014,5,22],[2014,7,22],[2014,7,22]]');
Parameters.Add('ctl00$contentPlaceHolderConteudo$acoes$btnBuscarArquivos=Buscar');
Parameters.Add('ctl00$contentPlaceHolderConteudo$mpgPaginas_Selected=0');
Parameters.Add('cboAgentesCorretorasNome=#');
Parameters.Add('cboAgentesCorretorasCodigo=#');
http.HandleRedirects := true;
http.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36';
http.AllowCookies := True;
http.Request.ContentType := 'application/x-www-form-urlencoded';
http.Post(url,Parameters,Response);
MS.SaveToFile('C:\teste.dat');
except
WriteLn(IntToStr(code));
finally
http.Free();
FreeAndNil(parameters);
FreeAndNil(response);
ReadLn;
end;
end.
I don't know how to get the file or even if I sending the right parameters.
Any suggetions?
Thanks in advance!
EDIT:
I fount out that the ViewState and the EventValidation parameters change from time to time, so now I got this:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils, idHTTP, Classes, MSHTML, SHDocVw, Httpapp, System.Variants, idURI;
function ExtractHiddenParameter(const ParameterName: string; const Request: string): string;
const
PrefixMask = 'input type="hidden" name="%s" id="%s" value="';
Suffix = '" />';
var
Prefix: string;
PrefixLength: Integer;
PrefixPosition: Integer;
SuffixPosition: Integer;
begin
Prefix := Format(PrefixMask, [ParameterName, ParameterName]);
PrefixPosition := Pos(Prefix, Request);
if PrefixPosition = 0 then
Result := ''
else
begin
PrefixLength := Length(Prefix);
Result := Copy(Request,
PrefixPosition + PrefixLength,
1 + Length(Request) - PrefixPosition - PrefixLength);
SuffixPosition := Pos(Suffix, Result);
if SuffixPosition = 0 then
Result := ''
else
Delete(Result, SuffixPosition, 1 + Length(Result) - SuffixPosition);
end;
end;
var
http: TIdHttp;
url: string;
getRequest: string;
code: integer;
parameters: TStringList;
Response: TStringStream;
Resultado: string;
sViewState: string;
sEventValidation: string;
MS: TMemoryStream;
begin
url := 'http://www.bmfbovespa.com.br/BancoTitulosBTC/PosicoesEmAberto.aspx?Idioma=pt-br';
http := TIdHTTP.Create(nil);
parameters := TStringList.Create;
Response := TStringStream.Create;
MS := TMemoryStream.Create;
try
try
http.ProxyParams.ProxyServer := 'proxy-scl';
http.ProxyParams.ProxyPort := 3128;
http.HandleRedirects := true;
http.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36';
http.AllowCookies := True;
getRequest := http.Get(url);
sViewState := ExtractHiddenParameter('__VIEWSTATE', getRequest);
sEventValidation := ExtractHiddenParameter('__EVENTVALIDATION', getRequest);
Parameters.Add('__EVENTTARGET=');
Parameters.Add('__EVENTARGUMENT=');
Parameters.Add('__VIEWSTATE='+sViewState);
Parameters.Add('__EVENTVALIDATION'+sEventValidation);
Parameters.Add('ctl00$ucTopo$btnBusca=Busca');
Parameters.Add('ctl00$menuBOVESPASecundario=');
Parameters.Add('ctl00$contentPlaceHolderConteudo$tabPosicaoEmAberto={"State":{},"TabState":{"ctl00_contentPlaceHolderConteudo_tabPosicaoEmAberto_tabAcoes":{"Selected":true}}}');
Parameters.Add('ctl00$contentPlaceHolderConteudo$acoes$txtConsultaData$txtConsultaData=2014-07-22');
Parameters.Add('ctl00$contentPlaceHolderConteudo$acoes$txtConsultaData$txtConsultaData$dateInput=2014-07-22-00-00-00');
Parameters.Add('ctl00_contentPlaceHolderConteudo_acoes_txtConsultaData_txtConsultaData_calendar_SD=[]');
Parameters.Add('ctl00_contentPlaceHolderConteudo_acoes_txtConsultaData_txtConsultaData_calendar_AD=[[2014,5,22],[2014,7,22],[2014,7,22]]');
Parameters.Add('ctl00$contentPlaceHolderConteudo$acoes$txtConsultaDataDownload$txtConsultaDataDownload=2014-07-02');
Parameters.Add('ctl00$contentPlaceHolderConteudo$acoes$txtConsultaDataDownload$txtConsultaDataDownload$dateInput=2014-07-02-00-00-00');
Parameters.Add('ctl00_contentPlaceHolderConteudo_acoes_txtConsultaDataDownload_txtConsultaDataDownload_calendar_SD=[]');
Parameters.Add('ctl00_contentPlaceHolderConteudo_acoes_txtConsultaDataDownload_txtConsultaDataDownload_calendar_AD=[[2014,5,22],[2014,7,22],[2014,7,22]]');
Parameters.Add('ctl00$contentPlaceHolderConteudo$acoes$btnBuscarArquivos=Buscar');
Parameters.Add('ctl00$contentPlaceHolderConteudo$mpgPaginas_Selected=0');
Parameters.Add('cboAgentesCorretorasNome=#');
Parameters.Add('cboAgentesCorretorasCodigo=#');
http.Head(url);
code := http.ResponseCode;
http.Request.ContentType := 'application/x-www-form-urlencoded';
http.Post(url,Parameters,Response);
MS.SaveToFile('C:\teste.dat');
except
on E: EIdHTTPProtocolException do
code := http.ResponseCode;
end;
WriteLn(IntToStr(code));
finally
http.Free();
FreeAndNil(parameters);
FreeAndNil(response);
ReadLn;
end;
end.
You were very close.
just change the line
MS.SaveToFile('C:\teste.dat');
into
Response.SaveToFile('C:\teste.dat');
you can remove the TMemoryStream from your code, it is not needed
Related
I have already tried code from StackOverflow, f.e. Download, pause and resume an download using Indy components.
But when I try to use IdHttp1.Disconnect() in order to pause download and then resume it, the download does not resume. The file is downloaded from zero. So, what should I do in order to add resume support to my Delphi app?
BTW: the server allows download resuming, because IDM can resume the download.
You have to check the size of the remote file, and the size of the local file (if exists).
If the size of the remote file is larger than the size of the local file, then you have to set the Ranges property of the Request property of TIdHTTP to the starting point (the local file size).
For example, if the remote file size is 100000 bytes, and the local file size is 80000 bytes, then you have to set http.Request.Ranges to start at 80000.
Here is a fully working code for you to use:
function FileSize(const FileName: string): Int64;
var
AttributeData: TWin32FileAttributeData;
begin
if GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, #AttributeData) then
begin
Int64Rec(Result).Lo := AttributeData.nFileSizeLow;
Int64Rec(Result).Hi := AttributeData.nFileSizeHigh;
end
else
Result := -1;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
http: TIdHTTP;
FS: TFileStream;
file_url: String;
file_path: String;
web_file_size: Integer;
local_file_size: Integer;
IhaveToDownload: Boolean;
begin
file_url := 'http://212.183.159.230/50MB.zip';
file_path := 'C:\50MB.zip';
IhaveToDownload := False;
FS := nil;
http := TIdHTTP.Create(nil);
try
//I will check if local file exists
if FileExists(file_path) then
begin
//I have to run http.Head() to get the ContentLength of the remote file.
http.Head(file_url);
//web_file_size now has the remote file size in bytes
web_file_size := http.Response.ContentLength;
//local_file_size now has the local file size in bytes
local_file_size := FileSize(file_path);
//check if remote file is bigger than local file (so I have to resume download)
if (web_file_size > local_file_size) and (http.Response.AcceptRanges = 'bytes') then
begin
//remote file is bigger than local file, so I will resume download.
http.Request.Ranges.Add.StartPos := local_file_size;
FS := TFileStream.Create(file_path, fmOpenReadWrite);
FS.Position := local_file_size;
IhaveToDownload := True;
end
else if web_file_size <> local_file_size then
begin
//remote file is not equal with local file, so I will restart download.
FS := TFileStream.Create(file_path, fmCreate);
IhaveToDownload := True;
end;
end
else
begin
//File does not exist locally. I will create a new local file
FS := TFileStream.Create(file_path, fmCreate);
IhaveToDownload := True;
end;
if IhaveToDownload then
http.Get(file_url, FS);
finally
FS.Free;
http.Free;
end;
end;
I want to make an http/2 request in go and got to a few issues there.
How to make proper http/2 requests in go?
Error: Get "https://webhook.site/aae1e0ab-3e48-49c8-8cd0-526e12ee4077": http2: unexpected ALPN protocol ""; want "h2" (Why? Other sites are working)
Code:
t := &http2.Transport{}
c := &http.Client{
Transport: t,
}
r, err := http.NewRequest("GET", "https://webhook.site/aae1e0ab-3e48-49c8-8cd0-526e12ee4077", nil)
if err != nil {
fmt.Println(err)
}
r.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.2 Safari/605.1.15")
r.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
resp, err := c.Do(r)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(body))
```
As was mentioned, that server doesn't support HTTP2:
PS C:\> curl.exe -I --http2-prior-knowledge https://webhook.site
curl: (16) Error in the HTTP2 framing layer
Contrast with one that does:
PS C:\> curl.exe -I --http2-prior-knowledge https://example.com
HTTP/2 200
https://curl.se/docs/manpage.html#--http2-prior-knowledge
I am struggling to know how to access the response to an Indy POST request. I post the data either as JSON or paramstring. My code when using JSON is as follows.
params := TStringList.Create;
try
params.Text :=
'{'
+ format ('"client_secret":"%s",', [FilesFrm.ClientSecret])
+ format ('"client_id":"%s",', [FilesFrm.ClientId])
+ '"grant_type":"authorization_code",'
+ '"redirect_uri":"http://localhost:8080",'
+ format ('"code":"%s"', [fCode])
+ '}';
idLogFile1.Active := true;
// Make sure it uses HTTP 1.1, not 1.0
IdHTTP1.HTTPOptions := IdHTTP1.HTTPOptions + [hoKeepOrigProtocol];
IdHTTP1.Request.ContentType := 'application/json';
IdHttp1.Request.Accept := 'application/vnd.hmrc.1.0+json';
try
result := IdHTTP1.Post (
'https://test-api.service.hmrc.gov.uk/oauth/token',
params);
except
on E: Exception do
memo1.lines.add (E.ClassName + ': ' + E.message);
end;
memo1.Lines.add (result);
memo1.Lines.add (idHTTP1.ResponseText);
finally
params.free;
end;
The result of printing out result and RepsonseText is just
EIdHTTPProtocolException: HTTP/1.1 400 Bad Request
HTTP/1.1 400 Bad Request
However, because I have a TidLogFile component attached to the TidHTTP, I can see what actually arrives, which is the following.
Recv 2/1/2019 7:56:07 AM: HTTP/1.1 400 Bad Request<EOL>
Content-Type: application/json<EOL>
Content-Length: 72<EOL>
Cache-Control: no-cache,no-store,etc, etc...
; Secure; HTTPOnly<EOL><EOL>
{"error":"invalid_request","error_description":"grant_type is required"}
Aside from the fact that grant_type appears to be in the original request data, I would like to be able to access the JSON response at the end, since "grant_type_is_required" is much more helpful than "Bad request", but I cannot find where it is.
I have subsequently found Response.ContentLength, which contains the value 72, and Response.ContentStream, which should in theory contain the 72 bytes of data, but produces access violations when I try to extract the data.
len := idHTTP1.Response.ContentLength;
memo1.Lines.Add(format ('Length = %d', [len]));
if assigned (idHTTP1.Response.ContentStream) then
begin
//idHTTP1.Response.ContentStream.Position := 0;
result := ReadStringFromStream (idHTTP1.Response.ContentStream, len);
end;
memo1.lines.add (result);
In addition to mjn42's answer, which is technically correct, TIdHTTP also has optional hoNoProtocolErrorException and hoWantProtocolErrorContent flags in its HTTPOptions property, which you can enable to avoid the EIdHTTPProtocolException being raised and to populate your result variable with error data, respectively:
params := TStringStream.Create(
'{'
+ format ('"client_secret":"%s",', [FilesFrm.ClientSecret])
+ format ('"client_id":"%s",', [FilesFrm.ClientId])
+ '"grant_type":"authorization_code",'
+ '"redirect_uri":"http://localhost:8080",'
+ format ('"code":"%s"', [fCode])
+ '}',
TEncoding.UTF8);
try
IdLogFile1.Active := true;
// Make sure it uses HTTP 1.1, not 1.0,
// and disable EIdHTTPProtocolException on errors
IdHTTP1.ProtocolVersion := pv1_1;
IdHTTP1.HTTPOptions := IdHTTP1.HTTPOptions + [hoKeepOrigProtocol, hoNoProtocolErrorException, hoWantProtocolErrorContent];
IdHTTP1.Request.ContentType := 'application/json';
IdHTTP1.Request.Accept := 'application/vnd.hmrc.1.0+json';
try
result := IdHTTP1.Post('https://test-api.service.hmrc.gov.uk/oauth/token', params);
except
on E: Exception do begin
Memo1.Lines.Add(E.ClassName + ': ' + E.message);
raise;
end;
end;
Memo1.Lines.Add(result);
finally
params.Free;
end;
Here is an example which shows how the HTTP body can be accessed.
The body can be accessed if you catch the EIdHTTPProtocolException exception.
on E: EIdHTTPProtocolException do
begin
WriteLn(E.Message);
WriteLn(E.ErrorMessage);
end;
Full example code:
program JSONPostExample;
{$APPTYPE CONSOLE}
uses
IdHTTP, IdGlobal, SysUtils, Classes;
var
HTTP: TIdHTTP;
RequestBody: TStream;
ResponseBody: string;
begin
HTTP := TIdHTTP.Create;
try
try
RequestBody := TStringStream.Create('{"日本語":42}',
TEncoding.UTF8);
try
HTTP.Request.Accept := 'application/json';
HTTP.Request.ContentType := 'application/json';
ResponseBody := HTTP.Post('https://httpbin.org/post',
RequestBody);
WriteLn(ResponseBody);
WriteLn(HTTP.ResponseText);
finally
RequestBody.Free;
end;
except
on E: EIdHTTPProtocolException do
begin
WriteLn(E.Message);
WriteLn(E.ErrorMessage);
end;
on E: Exception do
begin
WriteLn(E.Message);
end;
end;
finally
HTTP.Free;
end;
ReadLn;
ReportMemoryLeaksOnShutdown := True;
end.
Note that you must not use a TStringList for the POST body. That version of TIdHTTP.Post() formats the data according to the application/x-www-form-urlencoded media type, which is not appropriate for JSON and will corrupt it.
I'm trying to send a POST request at Firebase via HTTP, either in code or with the REST Debugger, but it returns an error:
HTTP/1.1 401 The request was missing an Authentification Key (FCM Token). Please, refer to section "Authentification" of the FCM documentation, at https=//firebase.google.com/docs
Using the Postman extension from Chrome, it works.
This is the code:
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
IdHTTP, IdIOHandler, IdIOHandlerStream,
IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL, IdSSLOpenSSLHeaders_Static,
FMX.Controls.Presentation, FMX.StdCtrls, FMX.ScrollBox, FMX.Memo,
IdGlobal, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
IdServerIOHandler, IdCoderMIME;
begin
try
IdIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
IdIOHandler.ReadTimeout := IdTimeoutInfinite;
IdIOHandler.ConnectTimeout := IdTimeoutInfinite;
IdHTTP := TIdHTTP.Create(nil);
try
idHttp.Request.Clear;
idHttp.Request.CustomHeaders.Clear;
idHttp.Request.ContentType := 'application/json';
idhttp.Request.Charset := 'UTF-8';
IdHTTP.IOHandler := IdIOHandler;
IdHTTP.ReadTimeout := IdTimeoutInfinite;
IdHTTP.Request.Connection := 'Keep-Alive';
IdIOHandler.SSLOptions.Method := sslvSSLv23;
IdHTTP.Request.Method := 'POST';
IdHTTP.Request.CustomHeaders.Values['Authorization:key'] := 'AAAAYsnMbsY:APA91bEjYZK-xxxxxxx......';
jsonString := '{"to" : "APA91bFJSdGW_yrX7p_TNKZ4k0OpdXTQM6xdd7BUsslk6zSvZlBmoAnfvyX-nBm4DYY-xxxxx......",' +
'"data" : {' +
'"Nick" : "Teste de Push",' +
'"body" : "Corpo do push",' +
'"Room" : "Apenas um teste"' +
'},}';
JsonToSend := TStringStream.Create(jsonString);
try
response := IdHTTP.Post('https://fcm.googleapis.com/fcm/send', JsonToSend);
response := response.Replace(Char(#10), '');
except
on E:EIdHTTPProtocolException do
memo1.Lines.Insert(0, e.ErrorMessage);
end;
memo1.Lines.Insert(0, response);
finally
IdHTTP.Free;
end;
finally
IdIOHandler.Free;
end;
end;
Your Delphi code is not assigning the Authentication request header correctly. You need to change this:
IdHTTP.Request.CustomHeaders.Values['Authorization:key'] := 'AAAAYsnMbsY:APA91bEjYZK-xxxxxxx......';
To this instead:
IdHTTP.Request.CustomHeaders.Values['Authorization'] := 'key=AAAAYsnMbsY:APA91bEjYZK-xxxxxxx......';
You should set the IdHTTP.Request.BasicAuthentication property to false as well.
Aside from that, since you are setting the Request.Charset property to UTF-8, you should construct the TStringStream to match:
JsonToSend := TStringStream.Create(jsonString, TEncoding.UTF8);
With that said, try the following code:
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
FMX.Controls.Presentation, FMX.StdCtrls, FMX.ScrollBox, FMX.Memo,
IdGlobal, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
IdHTTP, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL
{$IFDEF IOS}
, IdSSLOpenSSLHeaders_Static
{$ENDIF}
;
...
begin
IdHTTP := TIdHTTP.Create(nil);
try
IdIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
IdIOHandler.SSLOptions.Method := sslvSSLv23;
IdHTTP.IOHandler := IdIOHandler;
IdHTTP.Request.ContentType := 'application/json';
IdHTTP.Request.Charset := 'UTF-8';
IdHTTP.Request.CustomHeaders.Values['Authorization'] := 'key=AAAAYsnMbsY:APA91bEjYZK-xxxxxxx......';
jsonString := '{"to" : "APA91bFJSdGW_yrX7p_TNKZ4k0OpdXTQM6xdd7BUsslk6zSvZlBmoAnfvyX-nBm4DYY-xxxxx......",' +
'"data" : {' +
'"Nick" : "Teste de Push",' +
'"body" : "Corpo do push",' +
'"Room" : "Apenas um teste"' +
'},}';
JsonToSend := TStringStream.Create(jsonString, TEncoding.UTF8);
try
response := IdHTTP.Post('https://fcm.googleapis.com/fcm/send', JsonToSend);
response := response.Replace(#10, '');
except
on E: EIdHTTPProtocolException do
response := e.ErrorMessage;
end;
Memo1.Lines.Insert(0, response);
finally
IdHTTP.Free;
end;
end;
i am trying to implement the HTTP Client in my project, i cant login to my account,i get Forbidden!, with IdHTTP its working well, whats is missing or wrong in my code ?
NetHTTPClient1 properties:
Connectiontimeout = 30000
AllowCookies = True
HandleRedirects = True
UserAgent = Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36
NetHTTPRequest1 Properties :
Method String = POST
URL = https://www.instagram.com/accounts/web_create_ajax/attempt/
Code:
procedure TForm2.Button1Click(Sender: TObject);
var
Params : TStrings;
lHTTP: TIdHTTP;
IdSSL : TIdSSLIOHandlerSocketOpenSSL;
N: Integer;
Token,email,S: string;
Reply: TStringList;
Cookie: TIdCookie;
begin
lHTTP := TIdHTTP.Create(nil);
try
IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(lHTTP);
IdSSL.SSLOptions.Method := sslvTLSv1;
IdSSL.SSLOptions.Mode := sslmClient;
lHTTP.IOHandler := IdSSL;
lHTTP.ReadTimeout := 30000;
lHTTP.HandleRedirects := True;
lHTTP.Request.UserAgent := 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36';
lHTTP.Get('https://www.instagram.com', TStream(nil));
Cookie := lHTTP.CookieManager.CookieCollection.Cookie['csrftoken', 'www.instagram.com'];
if Cookie <> nil then
Token := Cookie.Value;
finally
end;
try
Params := TStringList.Create;
Params.Add('username=' +'myusername');
Params.Add('password=' + 'mypassword');
NetHTTPClient1.CustomHeaders['X-CSRFToken'] := Token;
NetHTTPClient1.CustomHeaders['X-Instagram-AJAX'] := '1';
NetHTTPClient1.CustomHeaders['X-Requested-With'] := 'XMLHttpRequest';
NetHTTPClient1.CustomHeaders['Referer'] := 'https://www.instagram.com/';
Memo1.Lines.Add(NetHTTPRequest1.Post('https://www.instagram.com/accounts/login/ajax/', Params).StatusText);
finally
end;
///login with IdHTTP///Wroks//
try
lHTTP.Request.CustomHeaders.Values['X-CSRFToken'] := Token;
lHTTP.Request.CustomHeaders.Values['X-Instagram-AJAX'] := '1';
lHTTP.Request.CustomHeaders.Values['X-Requested-With'] := 'XMLHttpRequest';
lHTTP.Request.Referer := 'https://www.instagram.com/';
lHTTP.Request.ContentType := 'application/x-www-form-urlencoded';
lHTTP.Request.UserAgent := 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36';
Reply := lHTTP.Post('https://www.instagram.com/accounts/login/ajax/', Params);
Memo1.Lines.Add(Reply);
end;
TNetHTTPClient is buggy with handleRedirect and post. https://quality.embarcadero.com/browse/RSP-14671
after when you login, you receive the cookie (the key in some way) and you must use theses cookies in all futur connexion.
"TNetHTTPClient is buggy with handleRedirect and post. "
This is already fix in version: 10.2 Tokyo Release 2