Converting cURL to JQuery.ajax request - javascript

Hi I'm working on connecting to an API that is using Layer 7 as an IP authorizer and eGalaxy as a credentials authorizer, when the curl request is sent a line of xml is sent back to me. I'm currently working on localhost, I've implemented the Access-Control-Allow-Origin chrome extension.
My curl request looks as such:
curl https://client-url/eGalaxy.aspx -H 'Content-Type:text/html' --data '<?xml version:"1.0" encoding="UTF-8"?><Envelope><Header><SourceID>0</SourceID><MessageID>131</MessageID><MessageType>Authenticate</MessageType></Header><Body><Authenticate><Username>*username*</Username><Password>*password*</Password><PasswordEncrypted>NO</PasswordEncrypted></Authenticate></Body></Envelope>' --insecure
When I tried to create an ajax request I receive an "Invalid HTTP status code 500" error and "OPTIONS url" which drops down to show:
n.ajaxTransport.k.cors.a.crossDomain.send # jquery-2.1.3.js:4
n.extend.ajax # jquery-2.1.3.js:4
(anonymous function) # VM947:2
InjectedScript._evaluateOn # VM899:895
InjectedScript._evaluateAndWrap # VM899:828
InjectedScript.evaluate # VM899:694
My ajax code is as follows:
$.ajax({
url:'https://client-url/eGalaxy.aspx',
data:'<?xml version:"1.0" encoding="UTF-8"?><Envelope><Header>
<SourceID>0</SourceID><MessageID>131</MessageID>
<MessageType>Authenticate</MessageType></Header><Body>
<Authenticate><Username>*username*</Username>
<Password>*password*</Password>
<PasswordEncrypted>NO</PasswordEncrypted></Authenticate></Body>
</Envelope>',
type:'POST',
contentType:'text/xml',
dataType:'xml',
success: function(data){
},
error: function(){
}
});
Any help with translating into a proper AJAX request would be appreciated!
EDIT: If this makes a difference these are the headers that are returned with the client's xml when the curl is complete(client information deleted)
This application will be made into a widget as well, so it will not be running off of a hosting site.
UPDATE 1: I'm using #KevinB's suggestion that the CORS headers were still not properly added.
Here is my updated JS code, copied from this link:
var url = 'https://client-url/eGalaxy.aspx';
var data = '<?xml version="1.0" encoding="UTF-8"?><Envelope><Header><SourceID>1</SourceID><MessageID>131</MessageID><MessageType>Authenticate</MessageType></Header><Body><Authenticate><Username>*username*</Username><Password>*password</Password><PasswordEncrypted>NO</PasswordEncrypted></Authenticate></Body></Envelope>';
var xhr = createCORSRequest('POST', url);
xhr.send(data);
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// Check if the XMLHttpRequest object has a "withCredentials" property.
// "withCredentials" only exists on XMLHTTPRequest2 objects.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// Otherwise, check if XDomainRequest.
// XDomainRequest only exists in IE, and is IE's way of making CORS requests.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// Otherwise, CORS is not supported by the browser.
xhr = null;
}
return xhr;
}
var xhr = createCORSRequest('GET', url);
if (!xhr) {
throw new Error('CORS not supported');
}
When run with the CORS Chrome extension off I receive an Access-Control-Allow-Origin =! 'null' error. Knowing that CORS needs Access-Control-Allow-Origin header to =! 'null' will this cause problems in the future with making this into a widget that will be put into a Content Manager system?
With it on the origin is set to 'www.evil.com', with the only error in the code being that it says the xhr.send() is an anonymous method. Using breakpoints I can see the xhr in xhr.send() is set to an empty request:
> XMLHttpRequest {response: "", responseText: ""}
Inside the createCORSRequest this line is undefined. I've tested using 'GET' and 'POST' as the method.
xhr.open(method, url, true)
EDIT 2:
Using #Fabiano's approach I've changed the web.config for two versions of what I suspect is my server(?). I'm attaching screenshots of what I've gone through
No luck, so far. Decided to use xhr.AppendHeader:
I decided to use xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
The Network tab Headers for eGalaxy.aspx

There is an error in your XML. You put version:"1.0", and this makes the XML invalid.
Change to version="1.0" and try to make your request. It should work.
This may be the cause for the "Bad request" error.
You can validate your XML here: enter link description here
EDIT: After some research, the problem may be with the headers sent by your server. Your server (or page, .aspx in this case) seems to skip the header you need, the "Access-Control-Allow-Origin: *".
Look at this link: http://enable-cors.org/server.html
This site shows you how to implement it for your server. Since the page you are requesting is called eGalaxy.aspx, then you have 2 ways to implement the headers:
1- Put the line Response.AppendHeader("Access-Control-Allow-Origin", "*"); if the page is a simple ASP.NET application. If it uses Web API 2, you need to implement a different way as it is shown here: http://enable-cors.org/server_aspnet.html
2- Edit the web.config file on the root of your server and add these lines inside the tag:
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
For a ASP.NET application, these are the ways you have. The link I mentioned has solutions for other applications, take a look and choose the right one. :)
Note that the value * tells you that your server will accept any cross-origin request. This may lead to a security issue, so the best you can do is to put your domain address instead of *.
I hope it helps!

Related

Sending a POST request from JavaScript not passing in JSON params

I am trying to call a Firebase Cloud function written in python from my website. The function works perfectly when I call it from command line using curl, however, when I try to do the same from JavaScript I am getting the following issue. Essentially the JSON params are not being received.
How I am calling in JavaScript
var xmlhttp = new XMLHttpRequest();
var theUrl = "https://us-central1-scan2checkout.cloudfunctions.net/registerUser";
xmlhttp.open("POST", theUrl,true);
xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xmlhttp.send('{"auth":"ac_Fn0GuKLhuh8yltMVlmFeBkQpdpaTrqug"}');
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
console.log(xmlhttp.responseText);
}
}
Cloud Function
def registerUser(request):
print(request) # Printing '<Request 'http://us-central1-scan2checkout.cloudfunctions.net/' [OPTIONS]>'
print(request.json) # Printing 'NONE' :(
auth = request.json['auth'] # Issue is here
# ... SOME STUFF ...
return {...},201
How it works when I use command line
time curl -v -X POST -d '{"auth":"ac_Fn0GuKLhuh8yltMVlmFeBkQpdpaTrqug"}' -H "Content-type: application/json" https://us-central1-scan2checkout.cloudfunctions.net/registerUser
If you run this now you'll probably get something like "Authorization code expired" which is correct.
To handle this request, you will need to set the appropriate Access-Control-Allow-* headers in your Cloud Function to match the requests you want to accept. Please see an example of a CORS function written in Python.
You will notice that CORS consists of two requests: a preflight OPTIONS request, and a main request that follows it.
The preflight request contains the following headers:
Access-Control-Request-Method - indicates which method will be sent in the main request.
Access-Control-Request-Headers - indicates additional headers along with the origin of the main request.
Let me know if it helps.

Issue with JSON.parse() from URL

I have this code trying to obtain prices from Bloomberg but I can't make it works.
This is the URL:
https://www.bloomberg.com/markets2/api/intraday/BACHOCOB:MM?days=1&interval=2&volumeInterval=15
And my failure code:
<p id="quote"></p>
<script>
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var price= JSON.parse(this.responseText);
document.getElementById("quote").innerHTML = price[0]["previousClosingPriceOneTradingDayAgo"];
}
};
xmlhttp.open("GET", "https://www.bloomberg.com/markets2/api/intraday/BACHOCOB:MM?days=1&interval=2&volumeInterval=15&currency=MXN", true);
xmlhttp.send();
</script>
Thanks in advance.
What is the excat error message your getting? Is it something like "No 'Access-Control-Allow-Origin' header is present on the requested resource"?
If so, that has nothing to do with JSON.parse as it is a security measure against XSS (Cross Site Scripting). You cannot request web responses from other domains if the server doesn't allows it explicitly.
See https://en.wikipedia.org/wiki/Cross-origin_resource_sharing for more information.
As an additional note: you can work around this. Even if you have no access to the server you could make use of a proxy server, that gets the request for you and uses the appropriate response header to allow your script to make the response. An example would be "corsproxy" from npm (No experience with it. Just a quick google search).
You can get value as below by adding jQuery to your project
$.ajax({
type: "GET",
url: "https://www.bloomberg.com/markets2/api/intraday/BACHOCOB:MM?days=1&interval=2&volumeInterval=15",
dataType: "json",
success: function(getPrice) {
$('#quote').append(getPrice[0].previousClosingPriceOneTradingDayAgo);
}
});
It seems CORS is an issue. Since you are using GET request to an SSL URL, it expects you to send this request from an HTTPS origin. To test your script, use Chrome Browser with CORS extension installed. You shall see the result.
In short, you need an HTTPS origin URL, you might want to try CURL with PHP for a possible solution if SSL is an issue !

How to get rid of No 'Access-Control-Allow-Origin' header is present on the requested resource error in java based web-service server

I'm trying to build a webservice (Java based server and Javascript base client) I only need to send a Post request with json data and I need to get a post response with json data from server.Since client and server have different domains I think cors need to be supported. Up to now, I've implemented these: (My client implementaion is almost same with html5 rocs tutorial)
Web service client (js):
// I call client = new WSclient() in one of my js files
WSclient=function(){
makeCorsRequest();
}
// Create the XHR object.
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// XHR for Chrome/Firefox/Opera/Safari.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// XDomainRequest for IE.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// CORS not supported.
xhr = null;
}
return xhr;
}
// Helper method to parse the title tag from the response.
function getTitle(text) {
return text;
}
// Make the actual CORS request.
function makeCorsRequest() {
// All HTML5 Rocks properties support CORS.
var url = 'http://localhost:8080/myapp/myfunction';
var xhr = createCORSRequest('POST', url);
xhr.setRequestHeader(
'X-Custom-Header', 'value');
xhr.send();
}
Web service server (java)
#Path("/myapp/")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public class myFunctionClass {
#POST
#Path("myfunction")
public Response recommendations(User inf){
// From the client I also need to send json
// like {"name":"john","surname":"smith","name":"marry","surname":"smith"}
// and if possible I want to put this infformation inside inf object
List<String> infos = inf.getInformation();
// here I call one of the my methods to get recommendations
// I remove it for simplicity and just put type of recommendations object
// list<Recommendation> recommendations= runFunction(infos);
final StringWriter sw =new StringWriter();
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(sw, recommendations);
System.out.println(sw.toString());
sw.close();
return Response.ok(sw.toString(), MediaType.APPLICATION_JSON).header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "POST").allow("OPTIONS").build();
}
}
However, I think I need to do something more because when I run these, I got
XMLHttpRequest cannot load http://localhost:8080/myapp/myfunction.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:3000' is therefore not allowed access.
So what should I add to my server code to get rid of this error? Besides, how could I send json data inside my request in client? This is my first time dealing with such issues therefore, If my question a bit absurd, sorry about that.
EDIT
When I remove
xhr.setRequestHeader(
'X-Custom-Header', 'value');
part from the client, It works properly. As I said before, this is my first time with web-services and javascript so actually I dont know what does this line of code. Could anyone explain me what happens if it exists or not?
EDIT2
I understood that, I need to put
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
in order to send a json with request.But when I added this, same errors come back. What should I add to server to achive this ?
What's happening is that there is a preflight request (which is an OPTIONS request), made before the initial request. So you need an #OPTIONS endpoint to handle that request (i.e. set the response header). In your current code, you are trying to set it in the original requested endpoint response, where the OPTIONS request won't even reach.
A more common approach, instead of creating an #OPTIONS endpoint for each target, just use a Jersey filter as seen in this answer. The headers will get sent out for all request.
See Also:
HTTP access control (CORS)
EDIT
Example #OPTIONS
#OPTIONS
#Path("myfunction")
public Response cors() {
return Response.ok()
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD")
// whatever other CORS headers
.build();
}

Cross Domain XHR failing inspite of Access-Control-Allow-Origin header

I am new to XHR and am trying to solve a simple use case. I have a web server, from where my javascript would fetch data. But instead of serving the data itself, the server would redirect the javascript XHR request to an alternate location (for example a file on Amazon's S3) to fulfill the request.
This brought me into the world of cross domain XHR, and I am unable to get even a simple example working inspite of reading a bit about it. I am adding "Access-Control-Allow-Origin: *" to the header in my main domain which serves the web page containing the javascript. But it does not work. What am I missing? I need this to work regardless of browser so am looking for something the initial server can do other than serving as a proxy, which defeats the purpose of offloading the request to S3.
Chrome : Gives "Exception: NetworkError: DOM Exception 19" on the
second call.
IE: Shows a warning but opens second url after
confirmation.
Firefox: Just says "Exception: Faliure" on the second
call.
Code follows for test.php:
<?php
header('Content-type: text/html');
header('Access-Control-Allow-Origin: *');
?>
<!DOCTYPE html>
<html>
<header>
<script type="text/javascript">
var request;
var url1 = "data/file.csv";
var url2 = "http://stackoverflow.com/users/1293955/ng-algo";
try
{
if (window.XMLHttpRequest) {
// IE7+, Firefox, Chrome, Opera, Safari
request = new XMLHttpRequest();
}
else {
// code for IE6, IE5
request = new ActiveXObject('Microsoft.XMLHTTP');
}
// load data. 'false' indicates that further script
// is not executed until data is loaded and parsed
alert("Test1 with url: "+url1);
request.open('GET', url1, false);
request.send();
alert(request.responseText);
alert("Test2 with url: "+url2);
request.open('GET', url2, false);
request.send();
alert(request.responseText);
} catch (e) { alert("Exception: "+e.message); }
</script>
</header>
This is a test page
</html>
For any arbitrary request (given the mix of Amazon and Stack Overflow in the question), CORS may not be enough as it's actually the remote server that has to give the permission.
For the 2nd request to succeed, stackoverflow.com would have to include relevant Access-Control-Allow-* headers in their responses that give your website permission to make the request. And whether those are included in the response or not is entirely up to Stack Exchange, in this case.
Also, by including Access-Control-Allow-Origin: * in the response, you're actually allowing other websites to request your page from their origin.
What you may need is a "proxy" script on your server. You can find a generalized solution from Ben Alman:
http://benalman.com/projects/php-simple-proxy/
https://github.com/cowboy/php-simple-proxy
Which would allow:
request.open('GET', 'proxy.php?url=' + encodeURIComponent(url2), false);

Cross domain XHR failing

I have an API hosted on one domain that has CORS enabled with the following headers:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Max-Age: 1728000
I am able to make a GET or POST request from hackst.com and it works fine. Link: http://hackst.com/#w3SbV
From my backbone app hosted on another domain, GET requests work fine. But when I try to create and save a new model (i.e. make a POST request), it fails with the following error:
Failed to load resource: the server responded with a status of 501 (Not Implemented) http://projectwhatup.us:5000/api/posts
XMLHttpRequest cannot load http://projectwhatup.us:5000/api/posts. Origin http://ayush.projectwhatup.us is not allowed by Access-Control-Allow-Origin.
My relevant backbone code:
var newPostData = {
topic : "New Post",
body : "new body",
user_id : 1,
};
var newPostModel = new Post(newPostData);
this.model.create(newPostModel);
I even tried over-riding the create method and making a POST request manually like this:
create : function(data) {
console.log('overriden create');
$.ajax({
"url" : this.url,
"async" : true,
"beforeSend" : function(obj){
console.log(obj);
},
"contentType" : 'application/json',
//"crossDomain" : true, // uncommenting this doesnt help either
"headers" : {
},
"dataType" : 'json',
"type" : 'POST',
"data" : JSON.stringify(data),
"error" : function(err){
console.log('new post creation failed');
console.log(err);
},
"success" : function(resp){
console.log('new post created');
console.log(resp);
}
});
}
Same error.
I tried a stand-alone GET request on JSFiddle as well (http://jsfiddle.net/X9cqh/5/), but that fails even though my backbone app can make the GET request fine.
I'm completely clueless at this point. Any hints, pointers, solutions?
The server should also reply to the preflight with the following header:
Access-Control-Allow-Headers: Content-Type
This is necessary because the content type is application/json, which is outside the acceptable values defined in the CORS spec (http://www.w3.org/TR/cors/).
Your sever setup works. JSFiddle apparently does not make the ajax requests, but you can quickly test that it works by entering these four lines into Chrome console or Safari developer console:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://projectwhatup.us:5000/api/posts', false);
xhr.send();
xhr.responseText;
If you try this with a domain that does not allow CORS, it will error out.
The reason that adding a 'Content-Type' header makes your CORS request fail is because your server is set up wrongly.
If the client wishes to specify particular headers or use an unusual http method verb (e.g. PUT), then the browser will first do a 'preflight' OPTIONS call to ensure that it is allowed to set those headers. Your server needs to respond to this OPTIONS call with the appropriate headers. You'll see that options call in the network tab of the Chrome developer tools or firebug if you want to confirm that this is what the problem is.
You may be interested in my more detailed answer here.

Categories