We have an issue with this on our Xero API integration. The RestRequest.Execute is causing us an error for no reason. But when we are running it as a stand-alone application (localhost exe) it is working perfectly. But converting it to a Webbroker ISAPI DLL and running on our domain thru IIS, we cannot get passed the first RESTRequest.Execute line. Currently using Delphi 10.4 & REST Components as a Webbroker with ISAPI.
function TXero2.GetAccessToken(Authorization, sAuthCode, ReDirectURI: AnsiString): AnsiString;
begin
TRY
ResetRESTComponentsToDefaults;
RESTClient.UserAgent := XeroUserAgent;
RESTRequest.Client := RESTClient;
RESTClient.BaseURL := XeroAPIIdentityURL;
RESTClient.ContentType := 'application/x-www-form-urlencoded';
RESTClient.Params.AddItem('Authorization', Authorization, TRESTRequestParameterkind.pkHTTPHEADER, [TRESTRequestParameterOption.poDoNotEncode]);
RESTRequest.Resource := 'connect/token';
RESTRequest.Params.AddItem('grant_type', 'authorization_code', TRESTRequestParameterKind.pkREQUESTBODY);
RESTRequest.Params.AddItem('code', sAuthCode, TRESTRequestParameterKind.pkREQUESTBODY);
RESTRequest.Params.AddItem('redirect_uri', ReDirectURI, TRESTRequestParameterKind.pkREQUESTBODY);
RESTRequest.Method := TRESTRequestMethod.rmPOST;
RESTRequest.Execute; //error occurs here
result := Restresponse.Content;
EXCEPT
on e: Exception do
Codesite.Send(ClassName + '.GetAccessToken: ' + e.Message);
END;
end;
This is really just a straight forward command and works fine when stand-alone. Anyone experiencing the same issue?
I'm trying to post on a web service via TIdHTTP (Indy) using Delphi 5, and whenever i call the post method, it returns an "Error connecting with SSL error" exception.
This is the code i'm trying to run
FHandle := TIdSSLIOHandlerSocket.Create(nil);
FHandle.SSLOptions.Method := sslvTLSv1;
IdHttp.IOHandler := FHandle;
IdHttp.HandleRedirects := True;
IdHTTP.Request.CustomHeaders.Add('Content-Type: application/json');
IdHttp.Request.ContentType := 'application/json';
Load();
vAux := TMemoryStream.Create();
try
WriteStringToStream(vAux, edJson.Text);
vAux.Position := 0;
vRet := IdHTTP.Post(edHost.Text, vAux);
finally
vAux.Free();
end;
It seems that no matter what i change in CustomHeaders or any other property, the same error happens.
I try changing de SSLOption.Method to all the available ones, but i can't get it to work.
Any suggestion for me to try?
I figured it out what the problem was. It was a certificate file that was faulty on the CertFile property from TIdSSLIOHandlerSocket component and i didn't even realized it was there. After pointing out to the right certificate file everything worked out smoothly. Thank you guys for the insights!
I have successfully sent email using GMail's SMTP server with the code below. I'm using Delphi 2006 and the latest version of Indy (10.6.2) and latest fulgan ssl libraries. The problem is that I had to turn down the GMail security settings as explained in the Google link. With the default high settings I get a cryptic error something like this: "https://accounts.google.com/ContinueSignIn?[...] Please log in via your web browser and then try again. Learn more at https://support.google.com/mail/bin/answer.py?answer=78754 [...] - gsmtp". How can I adjust the code below to use GMail's high security settings?
IdSMTP1.host:='smtp.gmail.com';
IdSMTP1.username:='[deleted]#gmail.com';
IdSMTP1.Password:='[deleted]';
IdSMTP1.port:=587;
IdSMTP1.UseTLS:=utUseExplicitTLS;
IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Mode := sslmClient;
IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Method:= sslvTLSv1;
IdSSLIOHandlerSocketOpenSSL1.SSLOptions.VerifyDepth := 2;
IdSSLIOHandlerSocketOpenSSL1.SSLOptions.VerifyMode := [];
IdSSLIOHandlerSocketOpenSSL1.Host := IdSMTP1.Host;
IdSSLIOHandlerSocketOpenSSL1.Port := IdSMTP1.Port;
IdMessage1.From.address := '[deleted]#gmail.com';
IdMessage1.CClist.EMailAddresses:= edit1.Text;
IdMessage1.Subject:= 'Subject is here';
IdMessage1.Body.Clear;
Idmessage1.Body.Add('Body is here');
IdSMTP1.Connect;
try
try
idSMTP1.Send(IdMessage1);
except on E:Exception do
Memo1.Lines.Insert(0, 'ERROR: ' + E.Message);
end;
finally
if idSMTP1.Connected then idSMTP1.Disconnect;
end;
I have a delphi code that basically upload files to remote secure server using Indy 10.4.704:
IdHTTP := TIdHTTP.Create(nil);
try
TheCompressor := TIdCompressorZLib.Create(nil);
TheSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
with IdHTTP do
begin
HTTPOptions := [hoForceEncodeParams];
AllowCookies := True;
HandleRedirects := True;
ProtocolVersion := pv1_1;
IOHandler := TheSSL;
Compressor := TheCompressor;
end; // with
// Get upload resume offset
try
IdHttp.Head('https://www.domain.com/my-file.bin');
if (IdHttp.Response.ResponseCode <> 404) And (IdHttp.Response.ContentLength >= 0) then
StartPos := IdHttp.Response.ContentLength
else
StartPos := 0;
except
StartPos := 0;
end; // try/except
// Upload File
TheFile := TFileStream.Create(FileName, fmOpenRead OR fmShareDenyWrite);
RangeStream := TIdHTTPRangeStream.Create(TheFile, StartPos, -1, True);
try
if (RangeStream.ResponseCode = 206) then
IdHTTP.Post(https://www.domain.com/upload.php', RangeStream);
finally
RangeStream.Free;
end; // try/finally
finally
FreeAndNil(IdHTTP);
end; // try/finally
The problem is that sometimes the code fails with Indy throwing a EIdSocketError Socket Error # 0 exception (idHTTP.ResponseCode is -1)
Given my crappy internet connection, I launched an EC2 windows instance and tested my code on it (the windows instance is running on the cloud, so I assume connection is not a problem), yet I got the same issue!
The error seems to be random, sometimes upload works, sometimes not. I debugged with TidLogFile, all I could find is something like this:
Stat Connected.
Sent 4/26/2012 4:18:42: POST /app/upload.php...
Sent 4/26/2012 4:18:42: <uploaded_file_data_here>
Stat Disconnected.
Anyone knows what's causing this/how to fix this?
EDIT
I traced the exception back to TIdSSLIOHandlerSocketOpenSSL. I googled a lot, it seems that it's not an SSL error.
Please upgrade to the latest Indy 10 version, which is 10.5.8 r4743. SSL-related issues with Error Code 0 were fixed over a year ago.
I have built the worlds dumbest and most simple SOAP server, in about 3 clicks, in visual studio. The exact steps in visual studio 2010: First create a new project as a web application, Then add a new item of type web service. (See accepted answer here for picture.) That soap server service Service1 has a simple method GetData:
A snippet from clientService1.pas, created using WSDL importer...
IService1 = interface(IInvokable)
['{967498E8-4F67-AAA5-A38F-F74D8C7E346A}']
function GetData(const value: Integer): string; stdcall;
function GetDataUsingDataContract(const composite: CompositeType2): CompositeType2; stdcall;
end;
When I try to run this method, like this:
procedure TForm3.Button1Click(Sender: TObject);
var
rio : THTTPRIO;
sv:IService1;
addr : string;
data : string;
begin
//addr := '....'; // url from visual studio 2010 live debug instance.
rio := THTTPRIO.Create(nil);
sv := GetIService1( true, addr, rio );
try
data := sv.GetData( 0);
Button1.Caption := data;
finally
sv := nil;
rio.Free;
end;
end;
The error I get is this:
ESOAPHTTPException:
The handle is in the wrong state for the requested operation -
URL:http://localhost:8732/Design_Time_Addresses/WcfServiceLibrary1/Service1/ -
SOAPAction:http://tempuri.org/IService1/GetData'.
The URL works fine when I paste the url above into a web browser, so the usual answer that the SOAP code in Delphi has the tendency to not notice an HTTP failure, does not seem likely. Rather it seems that I am either (a) experiencing breakage in WinInet (known to happen in some versions of windows), or (b) doing something wrong?
It seems to me that anybody who has visual studio and delphi both installed, should be able to try to get the dummy starter Soap server in Visual Studio talking to the soap client in Delphi, without any effort at all. But I can not figure out the simplest things.
At one time there was a discussion about the error in a conversation now long since deleted from Embarcadero forums, by Bruneau Babet, an embarcadero staffer.
Bruno said:
Hello,
I've posted a patched version of SOAPHTTPTrans.pas that contains a fix
for this issue here:
[forum link redacted, it didn't work anymore anyways, the post is gone]
You may still override the event as described in the C++Builder
section referred; or, much simpler, at least for Delphi users, simply
add the updated SOAPHTTPTrans.pas to your app's project. Let us know
if that does not work for you.
Cheers,
Bruneau
You can get the repair and the notes about it in its original forum formatting from the following pastebin link and on bitbucket so you don't have to extract the file from the surrounding text.
Warren Update 2016: I have been informed by someone who tried to use the fix on Delphi XE that this fix does NOT work for them in Delphi XE. Any further updates to the code in bitbucket that resolve the remaining bugs would be appreciated.
I ran into the The handle is in the wrong state for the requested operation issue in November 2018 using Delphi Tokyo 10.2.3, then looked at the code patch in the pastebin link under Arjen's answer.
That code is very old and the test code no longer works (SOAP service unavailable). Also, it is unclear from Bruneau's code what he patched exactly.
Comparing that source and the one from my Delphi version it seems that these are the (two) required modifications in the HandleWinInetError procedure ('PATCH HERE'):
function THTTPReqResp.HandleWinInetError(LastError: DWord;
Request: HINTERNET;
RaiseError: Boolean): DWord;
function CallInternetErrorDlg: DWord;
var
P: Pointer;
begin
Result := InternetErrorDlg(GetDesktopWindow(), Request, LastError,
FLAGS_ERROR_UI_FILTER_FOR_ERRORS or
FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS or
FLAGS_ERROR_UI_FLAGS_GENERATE_DATA, P);
{ After selecting client certificate send request again,
Note: InternetErrorDlg always returns ERROR_SUCCESS when called with
ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED }
if LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED then
Result := ERROR_INTERNET_FORCE_RETRY;
end;
const
{ Missing from our WinInet currently }
INTERNET_OPTION_CLIENT_CERT_CONTEXT = 84;
var
Flags, FlagsLen, DWCert, DWCertLen: DWord;
ClientCertInfo: IClientCertInfo;
CertSerialNum: string;
{$IFDEF CLIENT_CERTIFICATE_SUPPORT}
hStore: HCERTSTORE;
CertContext: PCERT_CONTEXT;
{$ENDIF}
begin
{ Dispatch to custom handler, if there's one }
if Assigned(FOnWinInetError) then
Result := FOnWinInetError(LastError, Request)
else
begin
Result := ERROR_INTERNET_FORCE_RETRY;
{ Handle INVALID_CA discreetly }
if (LastError = ERROR_INTERNET_INVALID_CA) and (soIgnoreInvalidCerts in InvokeOptions) then
begin
FlagsLen := SizeOf(Flags);
InternetQueryOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
Flags := Flags or SECURITY_FLAG_IGNORE_UNKNOWN_CA;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
end
else if (LastError = ERROR_INTERNET_SEC_CERT_REV_FAILED) and (soIgnoreInvalidCerts in InvokeOptions) then
begin
FlagsLen := SizeOf(Flags);
InternetQueryOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
Flags := Flags or SECURITY_FLAG_IGNORE_REVOCATION;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_FLAGS, Pointer(#Flags), FlagsLen);
end
{$IFDEF CLIENT_CERTIFICATE_SUPPORT}
else if (LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) and
Supports(Self, IClientCertInfo, ClientCertInfo) and
(ClientCertInfo.GetCertSerialNumber <> '') then
begin
CertSerialNum := ClientCertInfo.GetCertSerialNumber();
hStore := ClientCertInfo.GetCertStore();
if hStore = nil then
begin
hStore := CertOpenSystemStore(0, PChar('MY'));
ClientCertInfo.SetCertStore(hStore);
end;
CertContext := FindCertWithSerialNumber(hStore, CertSerialNum);
if CertContext <> nil then
begin
ClientCertInfo.SetCertContext(CertContext);
InternetSetOption(Request, INTERNET_OPTION_CLIENT_CERT_CONTEXT,
CertContext, SizeOf(CERT_CONTEXT));
end
else
begin
if RaiseError then RaiseCheck(LastError); // PATCH HERE
Result := CallInternetErrorDlg;
end;
end
{$ENDIF}
else if (LastError = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) and (soPickFirstClientCertificate in InvokeOptions) then
begin
{ This instructs WinInet to pick the first (a random?) client cerficate }
DWCertLen := SizeOf(DWCert);
DWCert := 0;
InternetSetOption(Request, INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT,
Pointer(#DWCert), DWCertLen);
end
else
begin
if RaiseError then RaiseCheck(LastError); // PATCH HERE
Result := CallInternetErrorDlg;
end;
end;
end;
Note that the RaiseError procedure parameter was not even used before this patch ;-)
Here is some test code using the SOAP service from NOAA's National Digital Forecast Database (NDFD) SOAP Web Service:
Uses SOAP.SOAPHTTPTrans;
const Request2 =
'<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ndf="http://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">' +
' <soapenv:Header/>' +
' <soapenv:Body>' +
' <ndf:NDFDgenByDay soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' +
' <latitude xsi:type="xsd:decimal">38.9936</latitude>' +
' <longitude xsi:type="xsd:decimal">-77.0224</longitude>' +
' <startDate xsi:type="xsd:date">%tomorrow%</startDate>' +
' <numDays xsi:type="xsd:integer">5</numDays>' +
' <Unit xsi:type="dwml:unitType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">e</Unit>' +
' <format xsi:type="dwml:formatType" xmlns:dwml="http://graphical.weather.gov/xml/DWMLgen/schema/DWML.xsd">12 hourly</format>' +
' </ndf:NDFDgenByDay>' +
' </soapenv:Body>' +
'</soapenv:Envelope>';
const URL2= 'https://graphical.weather.gov:443/xml/SOAP_server/ndfdXMLserver.php';
procedure TFrmHandleWinINetError.Button1Click(Sender: TObject);
var
RR: THTTPReqResp;
Response: TMemoryStream;
U8: UTF8String;
begin
RR := THTTPReqResp.Create(nil);
try
try
RR.URL := URL2;
RR.UseUTF8InHeader := True;
RR.SoapAction := 'NDFDgenByDay';
Response := TMemoryStream.Create;
RR.Execute(Request2, Response);
SetLength(U8, Response.Size);
Response.Position := 0;
Response.Read(U8[1], Length(U8));
ShowMessage(String(U8));
except
on E:Exception do ShowMessage('ERROR CAUGHT: ' + e.message);
end;
finally
Response.Free;
RR.Free;
end;
end;
end;
Without the patch errors in the tail end of the URL are caught, but errors in the domain name just trigger an empty error message.
With the patch those are also caught.
I have a reported the issue in the RAD Studio Quality Portal under number RSP-21862
Use at your own risk and please report any additional findings.
Addition: The issue was fixed in Dec 2018 in Delphi 10.3 Rio and the Quality Portal issue was closed with the following remark:
In RAD Studio 10.3 the implementation of THTTPReqResp was changed and replaced with THTTPClient. So, this issue no longer applies.
I have not verified this.