I am trying to write my own ASP.NET C# handler page for PayPal IPN.
I have followed a number of samples I found on the web but with no success.
I seem to be failing at the first step: capturing the Instant Payment Notification (IPN) data sent to the handler page from PayPal.
I have a web page: PayPalIPNHandler.aspx.cs and in the Page_Load I have the following:
protected void Page_Load(object sender, EventArgs e)
{
byte[] param = Request.BinaryRead(Request.ContentLength);
string strRequest = Encoding.ASCII.GetString(param);
}
I use some sample data to test the handler page:
/sitename/PayPalIPNHandler.aspx?mc_gross=0.01&protection_eligibility=Eligible&address_status=confirmed&item_number1=&payer_id=pid&tax=0.00&address_street=23%20The%20Street&payment_date=12:38:53%20Jan%2010,%202012%20PST&payment_status=Completed&charset=windows-1252&address_zip=IP4%204LP&mc_shipping=0.00&mc_handling=0.00&first_name=John&mc_fee=0.01&address_country_code=GB&address_name=John%20Smith¬ify_version=3.4&custom=&payer_status=unverified&business=x#googlemail.com&address_country=United%20Kingdom&num_cart_items=1&mc_handling1=0.00&address_city=Ipswich&verify_sign=verify&payer_email=x#gmail.com&mc_shipping1=0.00&txn_id=1&payment_type=instant&last_name=Smith&address_state=Suffolk&item_name1=&receiver_email=x#googlemail.com&payment_fee=&quantity1=1&receiver_id=w&txn_type=cart&mc_gross_1=0.01&mc_currency=GBP&residence_country=GB&transaction_subject=Shopping%20Cart&payment_gross=&ipn_track_id=Bu4
However, the ContentLength always seems to be 0 and strRequest is ""
I'm obviously making a very silly mistake, but I just can't see what I'm doing wrong.
Please help.
Kind Regards
Walter
The Content of an HTTP GET request will always be empty - it is only valid to send content on POST (and PUT and possibly DELETE) requests. Based on your comment, I'd say you need to look at
Request.ServerVariables["QUERY_STRING"]
Related
I am using the SAP Cloud SDK for Java to do CRUD on the SalesOrder APIs in S/4. Everything works well in that I can carry out these actions from Postman. However, these requests from Postman only work if I include a pre-request script to get a csrf token as outlined in this blog post
If I run the requests without the pre-request script outlined in the blog post, I get a '403 Forbidden'. As I said it works from Postman, but I would like to understand how this should be handled without the need for this script, for example if I was making a request from another application. Does the SDK allow me to handle this from the application code somehow. Maybe I am missing something.
Thanks for your time.
EDIT:
I am not making requests to the S/4 directly from Postman. I have an app deployed which is using the Cloud SDK to make the requests to S/4. It works if I use the pre-request script to fetch the CSFR token and attach it to the request before I send it, but 403 if I don't. So, if we imagine I am not using Postman but some ui somewhere to fill a form and send this request my understanding is that I shouldn't, as you suggested, have to worry about this token, that my service in the middle which uses the SDK and the VDM should handle this for me. This is what I am struggling to understand.
This is the servlet code:
#Override
protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException {
String body = IOUtils.toString(request.getReader());
JSONObject so = new JSONObject(body);
String distributionChannel = so.get("DistributionChannel").toString();
String salesOrderType = so.get("SalesOrderType").toString();
String salesOrganization = so.get("SalesOrganization").toString();
String soldToParty = so.get("SoldToParty").toString();
String organizationDivision = so.get("OrganizationDivision").toString();
String material = so.get("Material").toString();
String requestedQuantityUnit = so.get("RequestedQuantityUnit").toString();
SalesOrderItem salesOrderItem = SalesOrderItem.builder()
.material(material)
.requestedQuantityUnit(requestedQuantityUnit).build();
SalesOrder salesOrder = SalesOrder.builder()
.salesOrderType(salesOrderType)
.distributionChannel(distributionChannel)
.salesOrganization(salesOrganization)
.soldToParty(soldToParty)
.organizationDivision(organizationDivision)
.item(salesOrderItem)
.build();
try {
final ErpHttpDestination destination = DestinationAccessor.getDestination(DESTINATION_NAME).asHttp()
.decorate(DefaultErpHttpDestination::new);
final SalesOrder storedSalesOrder = new CreateSalesOrderCommand(destination, new DefaultSalesOrderService(),
salesOrder).execute();
response.setStatus(HttpServletResponse.SC_CREATED);
response.setContentType("application/json");
response.getWriter().write(new Gson().toJson(storedSalesOrder));
logger.info("Succeeded to CREATE {} sales order", storedSalesOrder);
} catch (final Exception e) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
logger.error(e.getMessage(), e);
logger.error("Failed to CREATE sales order", e);
}
}
And the CreateSalesOrder command:
public SalesOrder execute() {
return ResilienceDecorator.executeSupplier(this::run, myResilienceConfig);
}
protected SalesOrder run() {
try {
return salesOrderService.createSalesOrder(salesOrder).execute(destination);
} catch (final ODataException e) {
throw new ResilienceRuntimeException(e);
}
}
I am using the version 3.16.1 of the SDK and have set logging level to DEBUG for the SDK in the manifest:
SET_LOGGING_LEVEL: '{ROOT: INFO, com.sap.cloud.sdk: DEBUG}'
and logging level to DEBUG in logback
If I remove the pre-request script from the request and send it I get the 403 response and logs shows the following messages:
"logger":"com.sap.cloud.sdk.service.prov.api.security.AuthorizationListener","thread":"http-nio-0.0.0.0-8080-exec-4","level":"DEBUG","categories":[],"msg":"Reading
user principal"
"logger":"com.sap.cloud.sdk.service.prov.api.security.AuthorizationListener","thread":"http-nio-0.0.0.0-8080-exec-4","level":"DEBUG","categories":[],"msg":"Destroying Authorization as it is end of request." }
"logger":"com.sap.cloud.sdk.service.prov.api.security.AuthorizationService","thread":"http-nio-0.0.0.0-8080-exec-4","level":"DEBUG","categories":[],"msg":"Destroying Authorization JWT Token." }
As the other answers focus on the app to S/4 communication and you adjusted your question to make clear that you mean the User (e.g. Postman) to app communication I'll provide some additional information.
As mentioned by the other answers the CSRF handling to the S/4 system (or any OData endpoint) is automatically handled on side of the OData VDM.
What you are now encountering is the secure default configuration of the SAP Cloud SDK Maven Archetypes, which have the RestCsrfPreventionFilter activated by default.
This filter automatically protects all non-GET endpoints from CSRF by requiring you to fetch a CSRF Token prior to your request which you then provide.
This is completely unrelated to the OData VDM call to the S/4 system in the background.
To remedy your problems there are now three next steps:
Use a GET endpoint instead of POST
Probably only as a temporary workaround
Remove the RestCsrfPreventionFilter temporarily from your web.xml
This should not be done for productive uses, but might make your life in the initial evaluation easier.
"Live with it"
As this is a commonly used pattern to protect your application against CSRF it's advised to keep the filter in place and do the CSRF-Token "flow" as required.
Further Reading
OWASP description of CSRF: https://owasp.org/www-community/attacks/csrf
OWASP cheat sheet on CSRF protection (linked to the approach used by the filter): https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#use-of-custom-request-headers
JavaDoc of the RestCsrfPreventionFilter: https://tomcat.apache.org/tomcat-8.5-doc/api/org/apache/catalina/filters/RestCsrfPreventionFilter.html
Inkers
You're correct, with an API tool like Postman you have to make a HEAD request first to get a CSRF token.
However, in Cloud SDK for Java, we take care of getting and refreshing CSRF token for you when you're making any CRUD request.
Here's an example of reading a Saler Oder item and updating it afterward:
// Create a new sales order item
SalesOrderItem item = new SalesOrderItem();
item.setSalesOrder(SALES_ORDER);
item.setNetAmount(new BigDecimal(NET_VALUE));
item = service.createSalesOrderItem(item).execute(destination).getResponseEntity().get();
// Modify it with a PATCH update to 9000 net value
item.setNetAmount(new BigDecimal(NET_VALUE_UPDATED));
ModificationResponse<SalesOrderItem> response = service.updateSalesOrderItem(item).modifyingEntity().execute(destination);
Try it and let up know if it works fine for you. We're happy to assist if you'll encounter any difficulties.
The SDK makes an attempt to fetch a CSRF token automatically within execute(destination). This happens before issuing the actual request. If the attempt is successful the token will be included in the request. If not, the request will be send regardless.
Please increase the log level to debug for all com.sap.cloud.sdk packages if you think this is not happening correctly. Also it would be great to see the actual HTTP requests that go in and out which you can enable by setting the log level of org.apache.http.wire also to debug. Then attach the stack trace here together with the SDK version you are using and the exact code you are invoking.
PayPal is ignoring the response to my instant update callback.
I'm on sandbox
I'm getting the callback
I'm returning the exact example result in the documentation
...and PayPal continues to show my default shipping fee
Here's what I return from the callback (the example response at the end of this page):
METHOD=CallbackResponse&OFFERINSURANCEOPTION=true&L_SHIPPINGOPTIONNAME0=UPS Next Day Air&L_SHIPPINGOPTIONAMOUNT0=20.00&L_TAXAMT0=2.20&L_INSURANCEAMOUNT0=1.51&L_SHIPPINGOPTIONISDEFAULT0=false&L_SHIPPINGOPTIONNAME1=UPS Express 2 Days&L_SHIPPINGOPTIONAMOUNT1=10.00&L_TAXAMT1=2.00&L_INSURANCEAMOUNT1=1.35&L_SHIPPINGOPTIONISDEFAULT1=true&L_SHIPPINGOPTIONNAME2=UPS Ground2 to 7 Days&L_SHIPPINGOPTIONAMOUNT2=9.99&L_TAXAMT2=1.99&L_INSURANCEAMOUNT2=1.28&L_SHIPPINGOPTIONISDEFAULT2=false
I've also tried a much simpler response with no change in effect:
L_SHIPPINGOPTIONAMOUNT0=20.00&OFFERINSURANCEOPTION=false&L_SHIPPINGOPTIONISDEFAULT0=true&L_SHIPPINGOPTIONNAME0=Standard+Domestic&METHOD=CallbackResponse
What could I possibly be doing wrong? I see the callback in my server log. This is baffling.
It seems like in the response from the above url one parameter is missing which is "L_SHIPPINGOPTIONLABEL0=somenamehere" .
Try updating your callback script to send the above variable also in the response to the PayPal and see if that works for you .
For everyone interested, here is the documentation of the "Callback Response Message". I was also searching for the documentation because of a missing parameter.
https://developer.paypal.com/docs/classic/api/merchant/Callback_API_Operation_NVP/
I have created a basic REST API where a user can ask for an acronym, and the web-page will return the meaning of the acronym via a POST call.
The majority of my end-users don't use the Internet as much as they use the Microsoft Lync application.
Is it possible for me to create a Lync account, and have it pass questions to my API, and return the answers to the user? Meaning the user just needs to open a new chat in Lync rather than a new web-page.
I'm sure this is possible, but I can't find any information on Google or on the web. How can this be accomplished?
Thanks very much.
Edit :
Adding a bounty in the hopes of someone creating a simple example as I believe it would be very useful for a large number of devs :).
Yep, absolutely. UCMA (the Unified Communications Managed API) would be my choice of API to use here, and a good place to start - UCMA apps are "normal" .net applications, but also expose an application endpoint, which can be added to a user's contact list. When users send messages, that can trigger events in your application so you can take the incoming IM, do the acronym translation and return the full wording.
I have a bunch of blog posts about UCMA, but as of yet no defined collection of "useful" posts to work through, but coming soon! In the meantime, feel free to browse the list.
-tom
To elaborate on Tom Morgan's answer, it would be easy to create an UCMA application for this.
Create an UCMA application
Now this doesn't have to be complicated. Since all you want is to receive an InstantMessage and reply to it, you don't need the full power of a trusted application. My choice would be to use a simple UserEndpoint. As luck would have it, Tom has a good example of that online: Simplest example using UCMA UserEndpoint to send an IM.
Make it listen to incoming messages
Whereas the sample app sends a message when it is connected, we need to listen to messages. On the UserEndpoint, set a message handler for instant messages:
endpoint.RegisterForIncomingCall<InstantMessagingCall>(HandleInstantMessagingCall);
private void HandleInstantMessagingCall(object sender, CallReceivedEventArgs<InstantMessagingCall> e)
{
// We need the flow to be able to send/receive messages.
e.Call.InstantMessagingFlowConfigurationRequested += HandleInstantMessagingFlowConfigurationRequested;
// And the message should be accepted.
e.Call.BeginAccept(ar => {
e.Call.EndAccept(ar);
// Grab and handle the toast message here.
}, null);
}
Process the message
There is a little complication here, your first message can be in the 'toast' of the new message argument, or arrive later on the message stream (the flow).
Dealing with the Toast message
The toast message is part of the conversation setup, but it can be null or not a text message.
if (e.ToastMessage != null && e.ToastMessage.HasTextMessage)
{
var message = e.ToastMessage.Message;
// Here message is whatever initial text the
// other party send you.
// Send it to your Acronym webservice and
// respond on the message flow, see the flow
// handler below.
}
Dealing with the flow
Your message flow is where the actual data is passed around. Get a handle on the flow and store it, because it's needed later to send messages.
private void HandleHandleInstantMessagingFlowConfigurationRequested(object sender, InstantMessagingFlowConfigurationRequestedEventArgs e)
{
// Grab your flow here, and store it somewhere.
var flow = e.Flow;
// Handle incoming messages
flow.MessageReceived += HandleMessageReceived;
}
And create a message handler to deal with incoming messages:
private void HandleMessageReceived(object sender, InstantMessageReceivedEventArgs e)
{
if (e.HasTextBody)
{
var message = e.TextBody;
// Send it to your Acronym webservice and respond
// on the message flow.
flow.BeginSendInstantMessage(
"Your response",
ar => { flow.EndSendInstantMessage(ar); },
null);
}
}
That would about sum it up for the most basic example of sending/receiving messages. Let me know if any parts of this need more clarification, I can add to the answer where needed.
I created a Gist with a full solution. Sadly it is not tested because I'm currently not near a Lync development environment. See UCMA UserEndpoint replying to IM Example.cs.
I never used Lync but while I was looking at the dev doc, I stumble upon a sample which could be what you're looking for.
Lync 2013: Filter room messages before they are posted
Once you have filtered the messages, you just need to catch the acronym and call your custom code that calls your API.
Unless I'm missing something, I think you could do it with a simple GET request as well. Just call your API like this yoursite.com/api/acronym/[the_acronym_here].
You can use UCWA (Microsoft Unified Communications Web API),is a REST API.For detail , can reference as the following..
https://ucwa.lync.com/documentation/what-is-lync-ucwa-api
In my web portal while somebody commented on a user's post i send email to post owner about it.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SubmitComment(...)
{
Comment comment = new Comment {...
Mail.SendEmail(...);
return Content("OK");
}
When a comment submitted a post
request with ajax and append the
comment bottom of comment div. Because
of sending email take relatively
longer time response return late. So
users begin to click submit link more
than once. How can I return content
while send email at background. Async
Controller is a choice but the only
where i need is this section.
Any recommendation, tutorial etc.
check this link, it describes how to send email async and catch message about sending status
http://msdn.microsoft.com/en-us/library/x5x13z6h.aspx#Y2052
and after in controller i would create an action
that will be looking into session where you write data about sending email for particular user...
and of course reading it using ajax for response... the problem is the time may wary, so the question is .. is it the best way?
p
I'm writing GWT application where I need to upload video file and encode that video into different video formats. I've decided to use Panda Video Converter. I was able to run panda on my EC2 instance (using their image) and I can upload video from Panda's test pages but now I'm trying to make same thing with my own application in GWT.
The question that I have is: How do I get Video id and how do I post my video to the server. What URL do I need to use for that? I tried to read their documentation but have no clue where to start. This is my fist time working with webservices and url, probably that's why I don't how it works.
Disclaimer: I have no idea how the Panda Video Converter works, this is just an example of using RequestBuilder to make GET and POST requests to a server.
The steps to accomplish this seem to be roughly:
Send a POST to hq.pandastream.com/videos.(yaml|xml) with your account ID as a parameter.
Receive a response including the ID of the new video you've created (a placeholder)
Display a form to the user based on the ID. The form is retrieved by sending a GET to upload.pandastream.com/videos/[id]/form
Submitting this form uploads the video, whose information can be retrieved by sending a GET to GET hq.pandastream.com/videos/id.(yaml|xml)
Since the only elements of this process are POST and GET requests, you can use the RequestBuilder to make these requests for you in GWT.
We'll go through step by step.
Send a POST to hq.pandastream.com/videos.xml with your account ID as a parameter.
RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, "http://hq.pandastream.com/videos.xml");
rb.sendRequest("account_key=foo", new RequestCallback() {
protected void onResponseReceived(Request request, Response, response) {
// parse XML to get "id" element
}
// onError() ...
});
Now that you have the ID, you can make another request to get the upload form HTML.
rb = new RequestBuilder(RequestBuilder.GET, "http://upload.pandastream.com/videos/" + id + "/form");
rb.sendRequest(null, new RequestCallback() {
protected void onResponseReceived(Request request, Response, response) {
// this may not work, and it may be a bad idea to inject third-party HTML
// straight into your page. You might also want to open a popup window
// instead of injecting the HTML directly.
someWidget.setHTML(response.getText());
}
// onError() ...
});
With that form, the user uploads the video, etc.
Now, to get info about the video, it's -- you guessed it -- another RequestBuilder call.
rb = new RequestBuilder(RequestBuilder.GET, "http://hq.pandastream.com/videos/" + id + ".xml");
rb.sendRequest(null, new RequestCallback() {
protected void onResponseReceived(Request request, Response, response) {
// parse response XML to get info you want
}
// onError() ...
});
Another disclaimer: This is a very rough outline of what appears to be the process of uploading a video, based on the docs you linked. This just serves as a basic example of using RequestBuilder to make GET/POST calls.
I just wanted to see if you had worked this out. If you need some more help with the open source version feel free to ask on the Google Groups list we have: http://groups.google.com/group/pandastream
You might also be interested in trying out the hosted version we launched publicly last week: http://pandastream.com/
In my opinion, U2Any Video Converter is also a good choice for us because it is practical and professional yet easy to use. It can handle all the problem of converting video/audio formats. Hope my info can help you.