I need to send a multipart form POST request from my web application running on Chrome.
That works well with the following code:
<form method="post" action="http://localhost:999/some/path" target="iframeId" id="mainForm">
...
</form>
<iframe id="iframeId" name="iframeId" width="100%"></iframe>
I would like to create the multipart request payload manually instead, since the file to be submitted needs to be encrypted first.
var boundary = "---------------------------7da24f2e50046";
var body = '--' + boundary + '\r\n'
+ 'Content-Disposition: form-data; name="file";'
+ 'filename="temp.bin"\r\n'
+ 'Content-type: application/octet-stream\r\n\r\n'
+ body + '\r\n'
+ boundary + '--';
$.ajax({
contentType: "multipart/form-data",
data: body,
type: "POST",
url: "http://localhost:999/some/path",
success: function (data, status) {
alert('done');
}
});
When I run this code I get the following error:
XMLHttpRequest cannot load localhost:999/some/path. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'file://' is therefore not allowed access.
Why setting the target of the POST to an iFrame works, but an ajax won't? Is there a way to work around this, to be able to build my own multipart payload?
Why setting the target of the POST to an iFrame works, but an ajax won't?
Because Ajax would let the JavaScript running in Alice's browser on the site (Mallory's site) that triggered the request access the response from Bob's site (which could leak private data to Mallory when only Alice and Bob should have access to it).
iframes have other mechanisms to prevent JS from accessing the data.
Is there a way to work around this, to be able to build my own multipart payload?
Several. The main ones are:
CORS
JSONP (not suitable for POST requests)
Having JS make the request to the same server and then relaying it using server side code
To make a cross domain AJAX request the receiving domain must accept CORS requests, or you need to send in JSONP format. The latter is not really going to work for you as you're trying to send multi-part form data.
Your only option is to check if the receiving domain does indeed accept CORS. If not you will need to make this request on the server side.
This is all due to the Same Origin Policy which is a security policy that all modern browsers now implement.
Related
I am trying to access a Google Apps Script WebAPI from my website using javascript to pass some value and create an excel file and download it through this API.
I tried 2 following way:
Using POST request with $.post.
My values are many. So, at first, I use a POST request with a body is JSON of list values. Browser rejects API response, because of CORS error.
I researched about CORS to understand it. At some topics, I found a solution is the following second way.
Access to XMLHttpRequest at 'https://script.google.com/macros/s/xxxxxxx' from origin 'https://example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Using GET request with $.getJSON.
I pass JSON of list values to URL parameter and make GET request. It worked fine.
var url = 'https://script.google.com/macros/s/' + api_id + '/exec?' + request_parameter_string;
$.post(url, payload, function(data, textStatus) {
// Do something
}, 'json');
$.getJSON(url, function(json_result) {
// Do something
})
.fail(function() {
// Do something
});
What I do not understand is why? Why it works with getJSON but not work with post?
I think CORS work with both of GET and POST requests. And I checked the response header with Postman. The headers are the same Access-Control-Allow-Origin →*.
I think have something is different inside getJSON and post functions.
*UPDATE: Update POST CORS error message.
GET requests are not bound by CORS we can host images and static files in CDN which is different from the origin and would help in improving the performance by caching and making parallel requests.
Similarly GET is used for serving ads, trackers and analytics from third party domains as well.
More information about Same Origin Policy and GET is at https://security.stackexchange.com/a/16221/9517
How the browsers identify Other HTTP Verbs are allowed for the cross origin request is elaborated # https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
I am trying to access the JSON metadata corresponding to Python packages in the form http://pypi.python.org/pypi/<package_name>/json using JavaScript.
My code looks something like this:
var name = $('#name').val();
var url = 'http://pypi.python.org/pypi/' + name + '/json';
$.getJSON(url, function(result){
console.log(result);
});
The problem is that the url for the json is case sensitive, so for example, pypi.python.org/pypi/flask/json gets redirected to pypi.python.org/pypi/Flask/json since the package 'Flask' needs to have a capital F.
Thus, if name is flask, I get the error XMLHttpRequest cannot load https://pypi.python.org/pypi/flask/json. Redirect from 'https://pypi.python.org/pypi/flask/json' to 'https://pypi.python.org/pypi/Flask/json' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
Any idea on how to properly access the json even if the package name has the wrong capitalization?
If you make the request through an open CORS proxy it should work; try changing your code to:
var url = 'https://cors-anywhere.herokuapp.com/http://pypi.python.org/pypi/'
+ name + '/json';
That sends the request through https://cors-anywhere.herokuapp.com, an open CORS proxy which adds the Access-Control-Allow-Origin response header to it and then passes that back to your requesting frontend code as the response.
That redirect response with the Access-Control-Allow-Origin response header is what the browser sees, so the browser will actually follow the redirect instead of stopping.
All the said, it seems like the pypi.python.org site should really be including the Access-Control-Allow-Origin response header in their 3xx redirect responses, so you might consider filing a bug at https://sourceforge.net/p/pypi/support-requests/ requesting that they do.
I'm attempting to create an HTML-file that acts as a direct link to a cached site made by proxysite. Is there any way I can send a form containing a URL, without having the user fill in any field?
Sending it via ajax like so:
var params = {
"d" : "http://www.web.site/"
};
$.ajax({
url: "https://eu1.proxysite.com/includes/process.php?action=update",
type: "POST",
data: params
});
Seems to be purposefully blocked, as it returns this error message:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
EDIT: I realize why the above won't work. Since I don't have access to the previously mentioned website, I am looking for a possible workaround.
The reason you are receiving the "No Access-Control-Allow-Origin" header is because the receiving server needs to provide CORS headers. If you have access to the proxysite you will need to set the following headers to allow your request to go through
<?php
header("Access-Control-Allow-Origin: *");
Where the asterisk is the domain you want to allow. If you leave the asterisk in the the server will accept all requests from any local scripts on any domain.
Regarding sending the form without having the user input any fields-- Yes, it's possible to send data without user input. The way you are doing it is the correct way to send data via the jQuery Ajax method.
Problem
I'm working with a open data, city API for river levels, but when I make my ajax call using jsonp I receive an error for Uncaught SyntaxError: Unexpected token < which doesn't appear to be coming from my scripts.js
It is also my understanding that my ajax call might not be working because this API only spits out XML or json. I've tried to switch my dataType: json, but when I do that I receive the error below. Not particular sure if using jQuery's .getJSON is the best method to grab this data?
Data: http://opengov.brandon.ca/OpenDataService/opendata.html
Documentation: http://opengov.brandon.ca/api.aspx
Error (when switching dataType: json)
XMLHttpRequest cannot load http://opengov.brandon.ca/opendataservice/Default.aspx?date=riverlevel&columns=date&dataset=riverlevel. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
scripts.js
$(function(){
$.ajax({
url: 'http://opengov.brandon.ca/opendataservice/Default.aspx?date=riverlevel&columns=date&dataset=riverlevel',
type: 'GET',
dataType: 'jsonp',
success: function(response){
console.log(response)
}
});
});
You may be interested in reading What are the differences between JSON and JSONP?
A "JSONP response" from a server is actually an executable script. The client runs the executable script, and the script happens to contain the data you want, supplied as an argument to a function. If the server doesn't serve an executable script, that server does not support JSONP.
For your next error, see "No 'Access-Control-Allow-Origin' header is present on the requested resource". Ajax requests to other domains are not permitted, unless explicitly allowed by CORS headers (like the Access-Control-Allow-Origin response header) from the server. Due to the same-origin policy, scripts on one origin are not allowed to access the contents of another origin. Cross-Origin Resource Sharing (CORS) is a way for the server to relax the same-origin policy.
I would suggest contacting the providers of the API and requesting CORS support. In this case, it really is as simple as serving an Access-Control-Allow-Origin: * header in the response. Per the W3C's own security recommendations for CORS:
A resource that is publicly accessible, with no access control checks, can always safely return an Access-Control-Allow-Origin header whose value is "*".
Alternatively, you can set up a reverse proxy server that fetches the API resources for you and serves them on your own origin, as noted in an answer on Ways to circumvent the same-origin policy. Since the same-origin policy is a browser restriction, you can have any server you control fetch the API resource and then serve the response to your browser.
The default data format is XML, but can be changed by setting the format query variable to "json" to return JSON formatted data.
You need to add &format=json to the end of the URL:
http://opengov.brandon.ca/opendataservice/Default.aspx?date=riverlevel&columns=date&dataset=riverlevel&format=json
I can make a GET request from PHP and get the correct response. This is the function I use:
PHP
function httpGet($url)
{
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_HEADER, false);
$output=curl_exec($ch);
curl_close($ch);
return $output;
}
A simple example:
$fakevalue='iamfake';
$url="http://fakeurl.com?fakeparameter=".$fakevalue;
$jsondata= httpGet($url);
$fake_array = json_decode($jsondata, true);
$weed_var=$fake_array['weeds']; // successfully obtained weed.
This function returns the response from the server.
Now I am trying the same HTTP GET request in AJAX, but I can't get the response.
Initially I thought the problem was with the JavaScript function that I use. Google provided with me lots of JavaScript functions for performing the HTTP GET request but they all had the same problem. The request returns an error instead of the data that I got when I used PHP.
JAVASCRIPT
var fakevalue = "iamfake";
var fake_data = {
fakeparameter: fakevalue
};
$.ajax({
url: "http://fakeurl.com",
data: fake_data,
type: "GET",
crossDomain: true,
dataType: "json",
success: function(a) {
$("#getcentre").html(a);
},
error: function() {
alert("Failed!");
}
});
Error from JavaScript
XMLHttpRequest cannot load http://fakeurl.com?fakeparameter=fakevalue. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.`
I know you are going to tell me to use CORS, but if it was because of the absence of 'Access-Control-Allow-Origin' header, then how did I get response for the same service in PHP?
With PHP (or anything else running on your server, or a standalone application (including those installed as a browser extension)), you are requesting data from Bob's server using your credentials (your cookies, your IP address, your everything else).
With Ajax, you are asking Alice's browser to request data from Bob's server using her credentials and then to make that data available to your JavaScript (which can then send it back to your server so you can see it yourself).
Bob might give different data to Alice then he would give to you. For example: Bob might be running Alice's eBanking system or company intranet.
Consequently, unless Bob's server tells Alice's browser that it is OK to make that data available to you (with CORS), the browser will prevent your JavaScript from accessing that data.
There are alternatives to CORS, but they involve either distributing the data using a file type that isn't designed to be a data format (JSONP) (which also requires Bob's server to cooperate) or having your server fetch the data from Bob and then make it available through a URL on your server (or some combination of the two like YQL does) (which means that you get the data Bob will give to you and not the data Bob will give to Alice).
Simple answer: PHP isn't affected by CORS. It is a restriction placed by the browser on client-side code, so that the accessed URL gets to allow or deny the request.
You are running into CORS, because you are doing an XMLHttpRequest request from your browser to a different domain than your page is on. The browser is blocking it as it usually allows a request in the same origin for security reasons. You need to do something different when you want to do a cross-domain request. Try this: http://www.html5rocks.com/en/tutorials/cors/
If you only want to launch a GET request, you might try using JSONP datatype="jsonp".
Examples: http://www.sitepoint.com/jsonp-examples/