I am trying to use XE7 to connect to an in-house REDCap server. REDCap has a detailed description of the API at https://education.arcus.chop.edu/redcap-api/ and a test server at https://bbmc.ouhsc.edu/redcap/api with a test token key. There is assistance at https://mran.microsoft.com/snapshot/2015-08-18/web/packages/REDCapR/vignettes/TroubleshootingApiCalls.html in R.
I can connect to the test site with Curl and PostMan. My problem is how to implement this in Delphi with SSL.
The Curl script from PostMan:
curl --location 'https://bbmc.ouhsc.edu/redcap/api/' \
--data-urlencode 'token=9A81268476645C4E5F03428B8AC3AA7B' \
--data-urlencode 'content=record' \
--data-urlencode 'action=export' \
--data-urlencode 'format=csv' \
--data-urlencode 'rawOrLabel=label'
After much searching, this is my Delphi code. What have I missed? IdLogFile1
is a component on the form.
function TForm1.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean;
begin
showmessage('at IOhandler');
Result := true; // always returns true
end;
procedure TForm1.idHTTP2BtnClick(Sender: TObject);
var post : string;
Params : TStringList;
idHTTP : TIdHTTP;
SSL1 : TIdSSLIOHandlerSocketOpenSSL;
status : integer;
response : TstringStream;
begin
params := TStringList.Create;
idHTTP := TIdHTTP.Create(nil);
SSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(idHTTP);
response := TstringStream.create;
SSL1.SSLOptions.Mode := sslmClient ;
SSL1.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2 ];// [ sslvSSLv3, sslvSSLv23,sslvSSLv2, sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
SSL1.SSLOptions.VerifyDepth := 0;
SSL1.OnVerifyPeer := IdSSLIOHandlerSocketOpenSSL1VerifyPeer;
SSL1.SSLOptions.VerifyMode := [ ];
idHTTP.IOHandler := SSL1;
memo1.Lines.clear;
idHTTP.ReadTimeout := 3000;
idHTTP.ConnectTimeout := 3000;
idHttp.Request.BasicAuthentication := false;
try
idHTTP.HandleRedirects := true;
idHTTP.Intercept := IdLogFile1;
IdLogFile1.Active := true;
IdHttp.Request.CustomHeaders.Clear;
IdHttp.Request.CustomHeaders.Values['token'] := '9A81268476645C4E5F03428B8AC3AA7B';
IdHttp.Request.CustomHeaders.Values['content'] := 'record';
IdHttp.Request.CustomHeaders.Values['action'] := 'export';
IdHttp.Request.CustomHeaders.Values['format'] := 'csv';
IdHttp.Request.CustomHeaders.Values['rawOrLabel'] := 'label';
IdHttp.Request.CustomHeaders.Values['verify_ssl'] := 'false';
IdHttp.Request.CustomHeaders.Values['ssl_verify'] := 'false'; //various verify options ?
IdHttp.Request.CustomHeaders.Values['ssl_verifypeer'] := 'false';
idHTTP.Request.ContentType := 'application/x-www-form-urlencoded';
IdHTTP.Request.Charset := 'utf-8';
idHTTP.HTTPOptions := [hoKeepOrigProtocol, hoForceEncodeParams];
idHTTP.Post('https://bbmc.ouhsc.edu/redcap/api/', params, response );
finally
memo1.Lines.add(' ');
memo1.lines.add(idHTTP.ResponseText);
memo1.Lines.add(' ');
status := idHTTP.ResponseCode;
memo1.Lines.Add('code: ' + inttostr(status));
idhttp.Disconnect;
end;
Params.Free;
SSL1.Free;
idHTTP.Free;
response.Free;
end;
You are setting up the TLS connection correctly (provided the appropriate OpenSSL DLLs are available where Indy can find them).
What you are not setting up correctly is your data parameters. Curl's --data-urlencode
command puts the data in the HTTP request body, not in the HTTP headers. So you need to put the data in the TStringList
that you are posting (TIdHTTP
will handle the url-encoding for you).
Try this instead:
procedure TForm1.idHTTP2BtnClick(Sender: TObject);
var
params : TStringList;
idHTTP : TIdHTTP;
idSSL : TIdSSLIOHandlerSocketOpenSSL;
status : integer;
response : string;
begin
params := TStringList.Create;
try
idHTTP := TIdHTTP.Create(nil);
try
idSSL := TIdSSLIOHandlerSocketOpenSSL.Create(idHTTP);
idSSL.SSLOptions.Mode := sslmClient ;
idSSL.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2 ];
idSSL.SSLOptions.VerifyDepth := 0;
idSSL.OnVerifyPeer := IdSSLIOHandlerSocketOpenSSL1VerifyPeer;
idSSL.SSLOptions.VerifyMode := [ ];
idHTTP.IOHandler := idSSL;
Memo1.Lines.Clear;
idHTTP.ReadTimeout := 3000;
idHTTP.ConnectTimeout := 3000;
idHTTP.Request.BasicAuthentication := false;
try
idHTTP.HandleRedirects := true;
idHTTP.Intercept := IdLogFile1;
IdLogFile1.Active := true;
params.Add('token=9A81268476645C4E5F03428B8AC3AA7B');
params.Add('content=record');
params.Add('action=export');
params.Add('format=csv');
params.Add('rawOrLabel=label');
idHTTP.Request.ContentType := 'application/x-www-form-urlencoded';
idHTTP.Request.Charset := 'utf-8';
idHTTP.HTTPOptions := [hoKeepOrigProtocol, hoForceEncodeParams];
response := idHTTP.Post('https://bbmc.ouhsc.edu/redcap/api/', params);
finally
Memo1.Lines.Add(' ');
Memo1.Lines.Add(idHTTP.ResponseText);
Memo1.Lines.Add(' ');
status := idHTTP.ResponseCode;
Memo1.Lines.Add('code: ' + IntToStr(status));
end;
finally
idHTTP.Free;
end;
finally
params.Free;
end;
end;