Paypal-IPN Simulator ends up in HTTP 404 error after successfully completion of the function - paypal-ipn

have spent lot of hours trying to figure this out with Paypal Simulator, Sandbox but the result is same. My handler function(handleIpn) gets called and processed, with "Verified" "Complete" status but the IPN history as well as the simulator ends up in the HTTP 404 error. On IPN Simulator page the error is - "We're sorry, but there's an HTTP error. Please try again." My set up is Java-Spring MVC.
#RequestMapping(value = "/ipnHandler.html")
public void handleIpn (HttpServletRequest request) throws IpnException {
logger.info("inside ipn");
IpnInfo ipnInfo = new IpnInfo();
Enumeration reqParamNames = request.getParameterNames();
StringBuilder cmd1 = new StringBuilder();
String pName;
String pValue;
cmd1.append("cmd=_notify-validate");
while (reqParamNames.hasMoreElements()) {
pName = (String) reqParamNames.nextElement();
pValue = request.getParameter(pName);
try{
cmd1.append("&").append(pName).append("=").append(pValue);
}
catch(Exception e){
e.printStackTrace();
}
}
try
{
URL u = new URL("https://www.sandbox.paypal.com/cgi-bin/webscr");
HttpsURLConnection con = (HttpsURLConnection) u.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Host", "www.sandbox.paypal.com/cgi-bin/webscr");
con.setRequestProperty("Content-length", String.valueOf(cmd1.length()));
con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
con.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0;Windows98;DigExt)");
con.setDoOutput(true);
con.setDoInput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(cmd1.toString());
output.flush();
output.close();
//4. Read response from Paypal
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String res = in.readLine();
in.close();
//5. Capture Paypal IPN information
ipnInfo.setLogTime(System.currentTimeMillis());
ipnInfo.setItemName(request.getParameter("item_name"));
ipnInfo.setItemNumber(request.getParameter("item_number"));
ipnInfo.setPaymentStatus(request.getParameter("payment_status"));
ipnInfo.setPaymentAmount(request.getParameter("mc_gross"));
ipnInfo.setPaymentCurrency(request.getParameter("mc_currency"));
ipnInfo.setTxnId(request.getParameter("txn_id"));
ipnInfo.setReceiverEmail(request.getParameter("receiver_email"));
ipnInfo.setPayerEmail(request.getParameter("payer_email"));
ipnInfo.setResponse(res);
// ipnInfo.setRequestParams(reqParamNames);
//6. Validate captured Paypal IPN Information
if (res.equals("VERIFIED")) {
//6.1. Check that paymentStatus=Completed
if(ipnInfo.getPaymentStatus() == null || !ipnInfo.getPaymentStatus().equalsIgnoreCase("COMPLETED"))
ipnInfo.setError("payment_status IS NOT COMPLETED {" + ipnInfo.getPaymentStatus() + "}");
//6.2. Check that txnId has not been previously processed
IpnInfo oldIpnInfo = this.getIpnInfoService().getIpnInfo(ipnInfo.getTxnId());
if(oldIpnInfo != null)
ipnInfo.setError("txn_id is already processed {old ipn_info " + oldIpnInfo);
//6.3. Check that receiverEmail matches with configured {#link IpnConfig#receiverEmail}
if(!ipnInfo.getReceiverEmail().equalsIgnoreCase(this.getIpnConfig().getReceiverEmail()))
ipnInfo.setError("receiver_email " + ipnInfo.getReceiverEmail()
+ " does not match with configured ipn email " + this.getIpnConfig().getReceiverEmail());
//6.4. Check that paymentAmount matches with configured {#link IpnConfig#paymentAmount}
if(Double.parseDouble(ipnInfo.getPaymentAmount()) != Double.parseDouble(this.getIpnConfig().getPaymentAmount()))
ipnInfo.setError("payment amount mc_gross " + ipnInfo.getPaymentAmount()
+ " does not match with configured ipn amount " + this.getIpnConfig().getPaymentAmount());
//6.5. Check that paymentCurrency matches with configured {#link IpnConfig#paymentCurrency}
if(!ipnInfo.getPaymentCurrency().equalsIgnoreCase(this.getIpnConfig().getPaymentCurrency()))
ipnInfo.setError("payment currency mc_currency " + ipnInfo.getPaymentCurrency()
+ " does not match with configured ipn currency " + this.getIpnConfig().getPaymentCurrency());
}
else
ipnInfo.setError("Inavlid response {" + res + "} expecting {VERIFIED}");
logger.info("ipnInfo = " + ipnInfo);
this.getIpnInfoService().log(ipnInfo);
//7. In case of any failed validation checks, throw {#link IpnException}
if(ipnInfo.getError() != null)
throw new IpnException(ipnInfo.getError());
}
catch(Exception e)
{
if(e instanceof IpnException)
throw (IpnException) e;
logger.log(Level.FATAL, e.toString(), e);
throw new IpnException(e.toString());
}
//8. If all is well, return {#link IpnInfo} to the caller for further business logic execution
paymentController.processSuccessfulPayment(ipnInfo);
}
Any help /pointers would greatly appreciate.
thanks.

Finally, got it working! Didn't realize that my issue of redirection in Spring MVC could have impact on Paypal - IPN status. May be my lack of good understanding of HTTP redirections! In above method instead of void return am now returning a jsp page, so "void" is changed to "String" with returning value the jsp file name.
Hope it does help someone!

Related

Can we recognise inaccessible url using apache CloseableHttpAsyncClient

I am using CloseableHttpAsyncClient for downloading image with socketreadtimemout of 10 sec , connect timeout 5sec and doing a retry if it fails with sockettimeout and Timeout exception.
Now when the url is not accessible(404) then instead of resource not found exception it is failing with socket timeout and doing a retry again.So in my case for this invalid url also we are trying again and it adds up to the latency(~10+10=20 sec).
Below is the code snippet
Future<HttpResponse> httpResponseFuture = asyncCloseableHttpClient.execute(httpUriRequest, null);
try {
return httpResponseFuture.get(10000, TimeUnit.MILLISECONDS);
} catch (ExecutionException e) {
Throwable cause = e.getCause() != null ? e.getCause() : e;
if (cause instanceof ConnectException) {
throw new DownloadConnectionException("ConnectionException " + cause, DOWNLOAD_FAILED, cause);
}
if (cause instanceof SocketTimeoutException) {
throw new DownloadTimeoutException(DOWNLOAD_TIMEOUT_EXCEPTION);
}
if (cause instanceof ConnectionClosedException) {
throw new DownloadConnectionClosedException("ConnectionClosedException " + DOWNLOAD_FAILED, cause);
}
if(cause instanceof UnsupportedCharsetException) {
throw new BadRequestException("Image download failed with UnsupportedCharsetException " + cause,
INVALID_CONTENT_TYPE_EXCEPTION, cause);
}
} catch (TimeoutException e) {
throw new DownloadTimeoutException(DOWNLOAD_TIMEOUT_EXCEPTION);
}
This the config values for CloseableHttpAsyncClient
RequestConfig config = RequestConfig.custom()
.setSocketTimeout(10000)
.setConnectTimeout(5000)
.setRedirectsEnabled(true)
.setMaxRedirects(3)
.setStaleConnectionCheckEnabled(false) // never set this to true, 30 ms extra per request
.setProxyPreferredAuthSchemes(Arrays.asList(AuthSchemes.BASIC))
.build();
This is retry config
RetryConfig.custom().maxAttempts(downloadAttempts).retryOnException(e -> ( e instanceof DownloadTimeoutException) ) .waitDuration(Duration.ofMillis(30)).build();
To give more context why I am setting the socketreadtimemout of 10 sec because let's say for some bigger image download it may fail 1st time,so in that case retry is valid scenario but not in the resource not found case.
Can we do anything to make resource not found/invalid url fail fast so that it wont fail with sockettimeout exception.

Retrieve all the entities via SOAP in Javascript (CRM 2011)

With the following SOAP query I'm trying to get all the entities in the solution but it doesn't return entity. Maybe a second eye could help. Do you see anything wrong that I can't see? Thank you !
JCL.RetrieveAllEntitiesRequest = function (fnCallBack) {
/// Returns a sorted array of entities
var request = "";
request += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
request += " <s:Body>";
request += " <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
request += " <request i:type=\"a:RetrieveAllEntitiesRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\">";
request += " <a:Parameters xmlns:b=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>EntityFilters</b:key>";
request += " <b:value i:type=\"c:EntityFilters\" xmlns:c=\"http://schemas.microsoft.com/xrm/2011/Metadata\">Entity</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " <a:KeyValuePairOfstringanyType>";
request += " <b:key>RetrieveAsIfPublished</b:key>";
request += " <b:value i:type=\"c:boolean\" xmlns:c=\"http://www.w3.org/2001/XMLSchema\">true</b:value>";
request += " </a:KeyValuePairOfstringanyType>";
request += " </a:Parameters>";
request += " <a:RequestId i:nil=\"true\" />";
request += " <a:RequestName>RetrieveAllEntities</a:RequestName>";
request += " </request>";
request += " </Execute>";
request += " </s:Body>";
request += "</s:Envelope>";
return JCL._ExecuteRequest(request, "Execute", JCL._RetrieveAllEntitiesResponse, fnCallBack);
};
JCL._ExecuteRequest = function (sXml, sMessage, fInternalCallback, fUserCallback) {
'use strict';
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", JCL.server + "/XRMServices/2011/Organization.svc/web", (fUserCallback !== null));
xmlhttp.setRequestHeader("Accept", "application/xml, text/xml, */*");
xmlhttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlhttp.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/" + sMessage);
if (fUserCallback !== null) {
// asynchronous: register callback function, then send the request.
xmlhttp.onreadystatechange = function () {
fInternalCallback.call(this, xmlhttp, fUserCallback);
};
xmlhttp.send(sXml);
} else {
// synchronous: send request, then call the callback function directly
xmlhttp.send(sXml);
return fInternalCallback.call(this, xmlhttp, null);
}
};
Update after #Paul Way replied to me:
This is the error message I get when I select the entity that I need to investigate in CRM Data Detective. I can't add any field to this entity that's why I am using CRM Data Detective to find out which field I could delete, but it happens that the solution couldn't also handle an entity with a maximum number of attributes. Could you please have a look Paul? thank you So much !
Well, I'm embarrassed :)
I've updated the CRM Data Detective and JCL libraries to support CRM 2011 pre UR 12.
https://crmdatadetective.codeplex.com/
https://github.com/paul-way/JCL
The problem has to do with how the returned XML is parsed. Let me know if this fixes your problems...
The CRM 2011 SDK includes some good sample code to do this...
http://msdn.microsoft.com/en-us/library/gg594428.aspx

Google Web Toolkit - XSRF Protected Services : Invalid RPC Token

I've implemented XSRF Protected Services in GWT project. I'm using GWT 2.6.0 release. When I try to load my app in a browser I get a very strange exception as follows:
Uncaught com.google.gwt.user.client.rpc.RpcTokenException: Invalid RPC token (Invalid RpcToken type: expected 'com.google.gwt.user.client.rpc.XsrfToken' but got 'class com.google.gwt.user.client.rpc.XsrfToken')
I've searched my classpath and I only have one XsrfToken class provided by gwt-servlet.jar located inside my WAR file. I downloaded 2.6 code from GIT and I see the code that is throwing the exception is provided by ProxyCreator.java in the method generateCheckRpcTokenTypeOverride.
Does anyone have any idea as to why this exception would be thrown. The error indicates to me at least that it should pass given that what is expected is what it has.
I'm pasting the method in for completeness:
protected void generateCheckRpcTokenTypeOverride(SourceWriter srcWriter, TypeOracle typeOracle,
SerializableTypeOracle typesSentFromBrowser) {
JClassType rpcTokenType = typeOracle.findType(RpcToken.class.getName());
JClassType[] rpcTokenSubtypes = rpcTokenType.getSubtypes();
String rpcTokenImplementation = "";
for (JClassType rpcTokenSubtype : rpcTokenSubtypes) {
if (typesSentFromBrowser.isSerializable(rpcTokenSubtype)) {
if (rpcTokenImplementation.length() > 0) {
// >1 implematation of RpcToken, bail
rpcTokenImplementation = "";
break;
} else {
rpcTokenImplementation = rpcTokenSubtype.getQualifiedSourceName();
}
}
}
if (rpcTokenImplementation.length() > 0) {
srcWriter.println("#Override");
srcWriter.println("protected void checkRpcTokenType(RpcToken token) {");
srcWriter.indent();
srcWriter.println("if (!(token instanceof " + rpcTokenImplementation + ")) {");
srcWriter.indent();
srcWriter.println("throw new RpcTokenException(\"Invalid RpcToken type: " + "expected '"
+ rpcTokenImplementation + "' but got '\" + " + "token.getClass() + \"'\");");
srcWriter.outdent();
srcWriter.println("}");
srcWriter.outdent();
srcWriter.println("}");
}
}
Thanks very much in advance.

Windows Azure REST API Update Role Doesn't Take Effect

I'm doing some proof of concept work on azure, trying to get a role using the Get Role URL:
https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deployments/<deployment-name>/roles/<role-name>
And then update the role using the Update Role URL:
https://management.core.windows.net/<subscription-id>/services/hostedservices/<cloudservice-name>/deployments/<deployment-name>/roleinstances/<role-name>
Both of those URLs are straight from the msdn pages. The GET request works and I get XML that matches what I see in the management console.
When I then add an element to the xml and send that back with a PUT on the update URL, I get a 200 response, but I never see the change in the management console. I also don't see any error message when I send gibberish. I'm connecting from C#, and a coworker suggested I could get the response with this:
var response = (HttpWebResponse)request.GetResponse();
Console.WriteLine(response.ToString());
But that gets me a 404 error.
Is there an extra step to commit the update? And how can I see the response that msdn mentions?
2 suggestions:
When I am just doing quick SMAPI work I use AzureTools (http://blogs.msdn.com/b/kwill/archive/2013/08/26/azuretools-the-diagnostic-utility-used-by-the-windows-azure-developer-support-team.aspx). Specifically, look in the Misc Tools section under "Service Management REST API". This will show you the full response.
To answer your question about how to get the response (txtSMAPIResponse is where AzureTools puts the response info):
System.IO.Stream receiveStream;
System.IO.StreamReader readStream;
Encoding encode;
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
txtSMAPIRequest.Text = request.Headers.ToString();
txtSMAPIResponse.Text = ex.Message + Environment.NewLine + Environment.NewLine + ex.Response.Headers.ToString();
try
{
receiveStream = ex.Response.GetResponseStream();
encode = System.Text.Encoding.GetEncoding("utf-8");
// Pipes the stream to a higher level stream reader with the required encoding format.
readStream = new System.IO.StreamReader(receiveStream, encode);
txtSMAPIResponse.Text += readStream.ReadToEnd();
// Releases the resources of the response.
response.Close();
// Releases the resources of the Stream.
readStream.Close();
}
catch
{
}
return;
}
txtSMAPIRequest.Text = request.Method + " " + request.RequestUri + " " + request.ProtocolVersion + Environment.NewLine + Environment.NewLine;
txtSMAPIRequest.Text += request.Headers.ToString();
txtSMAPIResponse.Text = (int)response.StatusCode + " - " + response.StatusDescription + Environment.NewLine + Environment.NewLine;
txtSMAPIResponse.Text += response.Headers + Environment.NewLine + Environment.NewLine;
receiveStream = response.GetResponseStream();
encode = System.Text.Encoding.GetEncoding("utf-8");
// Pipes the stream to a higher level stream reader with the required encoding format.
readStream = new System.IO.StreamReader(receiveStream, encode);
txtSMAPIResponse.Text += readStream.ReadToEnd();
// Releases the resources of the response.
response.Close();
// Releases the resources of the Stream.
readStream.Close();
}
I've got the same problem. In my case EndPointACL is not getting updated. Very painful thing is for every update , we have to send the entire ConfigurationSet; There is no way to update the ACL for particular end point.
A typical update looks like this:
<?xml version="1.0"?>
<PersistentVMRole xmlns="http://schemas.microsoft.com/windowsazure" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ConfigurationSets>
<ConfigurationSet>
<ConfigurationSetType>NetworkConfiguration</ConfigurationSetType>
<InputEndpoints>
<InputEndpoint>
<LocalPort>100</LocalPort>
<Name>TCP-100</Name>
<Port>100</Port>
<Protocol>tcp</Protocol>
<EndpointACL>
<Rules>
<Rule>
<Order>1</Order>
<Action>deny</Action>
<RemoteSubnet>108.239.229.0/24</RemoteSubnet>
<Description>test-rule</Description>
</Rule>
</Rules>
</EndpointACL>
</InputEndpoint>
</InputEndpoints>
<SubnetNames>
<SubnetName>Subnet-1</SubnetName>
</SubnetNames>
</ConfigurationSet>
</ConfigurationSets>
</PersistentVMRole>

force.com callout exception Unable to tunnel through proxy

We make a callout from one Salesforce org to another Salesforce org using the REST API. That worked until end of november. We didn't make any changes at the affected classes or configuration.
Now, while sending a request to the rest api a callout exception will be thrown with the message : "Unable to tunnel through proxy. Proxy returns "HTTP/1.0 503 Service Unavailable".
The authorisation to the rest api is done by session id.
Does anyone have any idea what the problem is?
Here the code snipped:
final String WS_ENDPOINT = 'https://login.salesforce.com/services/Soap/c/24.0';
final String REST_ENDPOINT = 'https://eu2.salesforce.com/services/apexrest/UsageReporterService';
final String USERNAME = '*****';
final String PASSWORD = '*****';
HTTP h = new HTTP();
HTTPRequest req = new HTTPRequest();
req.setMethod('POST');
req.setEndpoint(REST_ENDPOINT);
req.setHeader('Content-Type', 'application/json');
req.setTimeout(60000);
HTTP hLogin = new HTTP();
HTTPRequest reqLogin = new HTTPRequest();
reqLogin.setMethod('POST');
reqLogin.setEndpoint(WS_ENDPOINT);
reqLogin.setHeader('Content-Type', 'text/xml');
reqLogin.setHeader('SOAPAction', 'login');
reqLogin.setTimeout(60000);
reqLogin.setCompressed(false);
// get a valid session id
String sessionId;
String loginSoap = '<?xml version="1.0" encoding="UTF-8"?>';
loginSoap += '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com">';
loginSoap += '<soapenv:Body>';
loginSoap += '<urn:login>';
loginSoap += '<urn:username>' + USERNAME + '</urn:username>';
loginSoap += '<urn:password>' + PASSWORD + '</urn:password>';
loginSoap += '</urn:login>';
loginSoap += '</soapenv:Body>';
loginSoap += '</soapenv:Envelope>';
reqLogin.setBody(loginSoap);
HTTPResponse respLogin;
try {
respLogin = hLogin.send(reqLogin);
} catch(CalloutException c){
return null;
}
System.debug('++++++'+respLogin.getStatus() + ': ' + respLogin.getBody());
Dom.Document doc = new Dom.Document();
doc.load(respLogin.getBody());
Dom.XMLNode root = doc.getRootElement();
String ns = root.getNamespace();
Dom.XMLNode bodyEl = root.getChildElements()[0];
if(bodyEl.getChildElements()[0].getName().equals('loginResponse')){
sessionId = bodyEl.getChildElements()[0].getChildElement('result', ns).getChildElement('sessionId', ns).getText();
}
// finished getting session Id
if(sessionId != null){ // login was successfull
req.setHeader('Authorization', 'Bearer ' + sessionId);
// serialize data into json string
UsageReporterModel usageReporterData = new UsageReporterModel();
String inputStr = usageReporterData.serialize();
req.setBody('{ "usageReportData" : ' + inputStr + '}');
// fire!
HTTPResponse resp;
try {
resp = h.send(req);
} catch(CalloutException c){
return null;
}
}
I suspect this will relate to a change of IP addresses for one of the org's which haven't been whitelisted correctly (or added to the "network access" object). With it being Salesforce to Salesforce I would hope that Salesforce.com support can assist?