We're getting the following message from Chrome when downloading (or attempting to download) a pdf in our mobile web application.
"Warning: Something's not right here!... The site you are trying to access is acting strangely, and Chrome is unable to verify that the URL is correct."
This is working fine in Safari and essentially we are doing this.
On load do a call to verify that the document that we want to show is OK.
if the document is not ok message the user and then close the tab
Direct the tab to navigate to an address which downloads the PDF.
Without posting too much code the Javascript is something like this:
DoRequest ("print_report",
"VALIDATE",
mycallback);
function mycallback (data,error) {
var h_href = "";
var h_widget = "";
if(error == true) {
window.close();
return;
}
h_href = GenerateHREF( "print_report", "PRINT" );
window.location.href = h_href;
}
The URL provided by GenerateHREF is for the same originating site and is relative to the original.
the mime type is set to application/pdf.
The content-disposition is set to inline. I've tried setting the content-size header as well but it doesn't seem to have any effect.
Content-Disposition: attachment; filename="pp66.26.pdf"
Content-Length: 31706
Content-Type: application/pdf
I'm missing something ... just what?
Try to parse document to base64 and added to your document or iframe.
function getAsyncBase64(fileName, callBack){
var xhr = new XMLHttpRequest();
xhr.open('GET', fileName, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function (e) {
if (this.status == 200) {
var uInt8Array = new Uint8Array(this.response || this.responseText);
var i = uInt8Array.length;
var binaryString = new Array(i);
while (i--) {
binaryString[i] = String.fromCharCode(uInt8Array[i]);
}
var dataBinary = binaryString.join('');
var data64 = window.btoa(dataBinary);
callback(data64);
}
xhr.send();
};
function callback(base64){
window.open(base64, "_blank");
//or
iframe.src = "data:application/pdf;base64,"+ base64;
};
getAsyncBase64(url,callback);
If it's a popup/download issue you might be able to show it using an iframe?
<iframe src="downloads/report.pdf"></iframe>
I also think that popup behavior is probably high on the list of suspects (specifically the window.close(); line seems pretty suspicious especially if the popup is blocked by the user).
However, since the ultimate goal is to download the file, you could try changing the response headers to
Content-Disposition: attachment; filename="pp66.26.pdf"
Content-Length: 31706
Content-Type: applicaton/octet-stream
or you could try forcing all pdfs in a particular folder to force a download via .htaccess file, then just linking to them via the location.href you are using:
<FilesMatch "\.pdf$">
ForceType applicaton/octet-stream
Header set Content-Disposition attachment
</FilesMatch>
Related
I need a way to insert the text downloaded from a .txt file from a URL into an element or variable which i can use further.
I have tried adding the URL to an object element which displays the text correctly, but I do not know how to add this text into a variable.
var storage = firebase.storage();
var storageRef = storage.ref();
var tangRef = storageRef.child('Recs');
var fileRef = tangRef.child("rec3.txt");
fileRef.getDownloadURL().then(function(url)
{
alert(url);
var para = document.getElementById('p1');
var par = document.createElement("object");
par.setAttribute('data', url);
para.appendChild(par);
}).catch(function(error)
{
console.error(error);
});
As mentionned, you can get some file through an object HTML element as you can do through a script HTML element to load a file. From these elements you won't have a same-origin policy problem, that's why your document is loaded with setAttribute and appendChild.
If you tried to access a resource by XHR or if you tried to interact with a document (both by JS), which are not from the same origin than your current resource, you will need to manage a same-origin policy mechanism see : https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
You can choose XHR or choose to access the nested document from the object HTML element, in both case you will have the same-origin policy problem. This is for security reasons which are linked with JavaScript.
If you choose nested document you could do something like this :
<div id="p1"></div>
<script>
var url = "https://firebasestorage.googleapis.com/v0/b/ninjatest-1b0ab.appspot.com/o/random%20text%20file.txt?alt=media&token=c09ae3ee-6a01-4f2b-b2b3-2f57ed7ff111";
// or
// var url = "http://localhost:4000/file.txt";
var para = document.getElementById('p1');
var par = document.createElement("object");
par.setAttribute('data', url);
para.appendChild(par);
par.onload = function() {
var doc = par.contentDocument || par.contentWindow.document;
var data = doc.body.childNodes[0].innerHTML;
console.log(data);
};
</script>
If you run this code, you can see that it doesn't accept cross-origin. This is because i'm trying to get a document (nested in the HTML document) which is from another domain. The browser won't let me access it. In the other hand, if i run in local with a node server, it allows me to get it without the error.
If you choose to use XHR (XMLHttpRequest) you can do something like that :
var data;
var url = "https://firebasestorage.googleapis.com/v0/b/ninjatest-1b0ab.appspot.com/o/random%20text%20file.txt?alt=media&token=c09ae3ee-6a01-4f2b-b2b3-2f57ed7ff111";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
data = xhr.responseText;
console.log(data);
}
};
xhr.open('GET', url);
xhr.send();
Again here, it won't work because of the different origin. In the two situations, it's the browser which implements a security rule. You can fix it if you have access to the server part. On the server, you could tell the browser (by HTTP header) to allows client from different origin.
With XHR you need to search about CORS.
With Nested document, you can look here :
SecurityError: Blocked a frame with origin from accessing a cross-origin frame
How Can I Bypass the X-Frame-Options: SAMEORIGIN HTTP Header?
If you don't have access to the server part, you could grab the file with a GET request from a server that you own (and so have access to the server part). In this case, you won't have the browser security issue because from your server, you will serve the file without the restriction of same-origin. It will be a proxy server solution.
With Firebase
When you create project with Firebase you can configurate the server part to allow the XHR as mention here : https://firebase.google.com/docs/storage/web/download-files#download_data_via_url
Firstly install Google Cloud SDK to have gsutil : https://cloud.google.com/storage/docs/gsutil_install#install
Then create a .json file on your computer : https://cloud.google.com/storage/docs/configuring-cors#configure-cors-bucket
Then execute this command : gsutil cors set cors.json gs://<your-cloud-storage-bucket>
JSON file example :
[
{
"origin": ["*"],
"method": ["GET"],
"maxAgeSeconds": 3600
}
]
I created a Firebase account, tried it and it works very well.
Working example with XHR (you can run it) :
var data;
var url = "https://firebasestorage.googleapis.com/v0/b/first-app-a7872.appspot.com/o/firebase.txt?alt=media&token=925fef9e-750e-40e5-aa92-bdfe8204d32e";
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
data = xhr.responseText;
console.log(data);
}
};
xhr.open('GET', url);
xhr.send();
https://codepen.io/anon/pen/JmoqQY?editors=1010
In HTML file:
<div id="p1">
</div>
script
url = "https://firebasestorage.googleapis.com/v0/b/ninjatest-1b0ab.appspot.com/o/random%20text%20file.txt?alt=media&token=c09ae3ee-6a01-4f2b-b2b3-2f57ed7ff111"
var para = document.getElementById('p1');
var par = document.createElement("object");
par.setAttribute('data', url);
para.appendChild(par);
EDIT: I made a stackblitz to try to see if I could extract the data in the text file into a variable for manipulation.
https://stackblitz.com/edit/angular-eyhaj5
I was unable to find a way. Problem is that because of CORS policy in browsers you are not supposed to open files outside of your own site.
To get around this you have to either have to send the URL to a function on your server that downloads the textFile and then makes it accessible in a folder.
Or you could set up a proxy server that allows cors. Or you could ask the owner of the text file to make it into an API.
Possibly it was a bad idea to put the textfile in firestorage in the first place. If you are the owner of the text file, it would maybe be better to put the text in a firestore database rather than save it as a textfile.
How can I get the contents of a file using JS, while letting the file be cached by the browser?
One possible way is to make that file a .js and let it be var SuperVar = 'BASE64-ENCODED-CONTENT' (base64 to escape special chars), but access and maintenance of the real contents would become indeed hard. I am trying to have normal files after all.
As the files are in size of 1-100 KB and of an unlimited quantity, so is localStorage not an option (will run out of space).
Have tried with <iframe>. Browsers parse .html files somewhat fine. Files need to begin with <html> else they get wrapped in a <pre> tag. By other filetypes IE creates an <object> and offers the file for download.
The point is for JS to work with the same file contents on multiple page loads without downloading them every time.
You can simply use AJAX, which will use the cache, if your server is configured correctly, and if you make GET requests.
btn.onclick = function() {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(xhr.response.substr(0, 20));
};
xhr.open('GET', 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js');
xhr.send();
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Open your dev-tools Network panel to see how it has been transferred.</p>
<button id="btn">request jQuery</button>
You have to send cache-control header from your server to let browser cache your ajax request.
index.html
<button id="btn">GET</button>
<script>
btn.onclick = function() {
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(xhr.response);
};
xhr.open('GET', 'cached.php');
xhr.send();
};
</script>
cached.php
<?php
header('Cache-Control: private, must-revalidate, max-age=60');
echo file_get_contents("file.any");
file.any
Contents
of
File...
You will see the status code 200, but if you check the Size column
in chrome developer-tools you can see if it was loaded from cache.
I'm loading a motion jpeg from third-party site, which I can trust. I'm trying to getImageData() but the browser (Chrome 23.0) complains that:
Unable to get image data from canvas because the canvas has been tainted by
cross-origin data.
There are some similar questions on SO, but they are using local file and I'm using third party media. My script runs on a shared server and I don't own the remote server.
I tried img.crossOrigin = 'Anonymous' or img.crossOrigin = '' (see this post on the Chromium blog about CORS), but it didn't help. Any idea on how can I getImageData on a canvas with cross-origin data? Thanks!
You cannot reset the crossOrigin flag once it is tainted, but if you know before hand what the image is you can convert it to a data url, see Drawing an image from a data URL to a canvas
But no, you cannot and should not be using getImageData() from external sources that don't support CORS
While the question is very old the problem remains and there is little on the web to solve it. I came up with a solution I want to share:
You can use the image (or video) without the crossorigin attribute set first and test if you can get a HEAD request thru to the same resource via AJAX. If that fails, you cannot use the resource. if it succeeds you can add the attribute and re-set the source of the image/video with a timestamp attached which reloads it.
This workaround allows you to show your resource to the user and simply hide some functions if CORS is not supported.
HTML:
<img id="testImage" src="path/to/image.png?_t=1234">
JavaScript:
var target = $("#testImage")[0];
currentSrcUrl = target.src.split("_t=").join("_t=1"); // add a leading 1 to the ts
$.ajax({
url: currentSrcUrl,
type:'HEAD',
withCredentials: true
})
.done(function() {
// things worked out, we can add the CORS attribute and reset the source
target.crossOrigin = "anonymous";
target.src = currentSrcUrl;
console.warn("Download enabled - CORS Headers present or not required");
/* show make-image-out-of-canvas-functions here */
})
.fail(function() {
console.warn("Download disabled - CORS Headers missing");
/* ... or hide make-image-out-of-canvas-functions here */
});
Tested and working in IE10+11 and current Chrome 31, FF25, Safari 6 (Desktop).
In IE10 and FF you might encounter a problem if and only if you try to access http-files from a https-script. I don't know about a workaround for that yet.
UPDATE Jan 2014:
The required CORS headers for this should be as follows (Apache config syntax):
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "referer, range, accept-encoding, x-requested-with"
the x-header is required for the ajax request only. It's not used by all but by most browsers as far as I can tell
Also worth noting that the CORS will apply if you are working locally regardless of if the resource is in the same directory as the index.html file you are working with. For me this mean the CORS problems disappeared when I uploaded it to my server, since that has a domain.
You can use base64 of the image on canvas,
While converting into base64 you can use a proxy URL (https://cors-anywhere.herokuapp.com/) before your image path to avoid cross-origin issue
check full details here
https://stackoverflow.com/a/44199382/5172571
var getDataUri = function (targetUrl, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var reader = new FileReader();
reader.onloadend = function () {
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
var proxyUrl = 'https://cors-anywhere.herokuapp.com/';
xhr.open('GET', proxyUrl + targetUrl);
xhr.responseType = 'blob';
xhr.send();
};
getDataUri(path, function (base64) {
// base64 availlable here
})
Hello I'm new at web developing so I apologize if my methods/questions makes no sense.
I am trying to load an audio file from a server directory to an audio html element. I was following fetch data example in this tutorial
var xhr = new XMLHttpRequest();
xhr.open('GET', http://*ipAddress*/audioUpload/test.mp3, true, *serverUsername*, *serverPassword*);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var blob = new Blob([this.response], {type: 'mp3'});
var audioReader = new FileReader();
audioReader.onload = function(d) {
var e = document.createElement("audio");
e.src = d.target.result;
e.id = "audioHTMLId";
e.setAttribute("type", 'mp3');
e.setAttribute("controls", "controls");
e.setAttribute("autoplay", "true");
document.getElementById("container").appendChild(e);
}
audioReader.readAsDataURL(blob);
}
};
xhr.send();
}
However I am getting this statement in console log:
GET http://*ipAddress*/audioUpload/test.mp3 net::ERR_CONNECTION_REFUSED
And don't know why.
Also I was wondering if there were a better way to play/get audio files on client's audio html element for large mp3 files (1-1.5 hour long)?
Is this by chance in Chrome? I've send this when you try and send a request and the server disconnects. This can be HTTPS / SSL related, or a problem with the actual server . I'd check whether or not you can actually hit the file like so:
wget http://*ipAddress*/audioUpload/test.mp3
It could be that said server is actually unreachable from wherever your environment is.
As for the second half of your question, you might just want to upload the audio to youtube and embed it, rather than dealing with the hassle of dealing with it yourself (storage, bandwidth, etc). However, I'm sure someone more versed than I could give you a better answer on that.
You need to set the authorization headers manually:
....
xhr.open('GET', http://*ipAddress*/audioUpload/test.mp3, true);
xhr.setRequestHeader("Authorization", "Basic " + btoa(*serverUsername* + ":" + *serverPassword*))
....
I'm loading a motion jpeg from third-party site, which I can trust. I'm trying to getImageData() but the browser (Chrome 23.0) complains that:
Unable to get image data from canvas because the canvas has been tainted by
cross-origin data.
There are some similar questions on SO, but they are using local file and I'm using third party media. My script runs on a shared server and I don't own the remote server.
I tried img.crossOrigin = 'Anonymous' or img.crossOrigin = '' (see this post on the Chromium blog about CORS), but it didn't help. Any idea on how can I getImageData on a canvas with cross-origin data? Thanks!
You cannot reset the crossOrigin flag once it is tainted, but if you know before hand what the image is you can convert it to a data url, see Drawing an image from a data URL to a canvas
But no, you cannot and should not be using getImageData() from external sources that don't support CORS
While the question is very old the problem remains and there is little on the web to solve it. I came up with a solution I want to share:
You can use the image (or video) without the crossorigin attribute set first and test if you can get a HEAD request thru to the same resource via AJAX. If that fails, you cannot use the resource. if it succeeds you can add the attribute and re-set the source of the image/video with a timestamp attached which reloads it.
This workaround allows you to show your resource to the user and simply hide some functions if CORS is not supported.
HTML:
<img id="testImage" src="path/to/image.png?_t=1234">
JavaScript:
var target = $("#testImage")[0];
currentSrcUrl = target.src.split("_t=").join("_t=1"); // add a leading 1 to the ts
$.ajax({
url: currentSrcUrl,
type:'HEAD',
withCredentials: true
})
.done(function() {
// things worked out, we can add the CORS attribute and reset the source
target.crossOrigin = "anonymous";
target.src = currentSrcUrl;
console.warn("Download enabled - CORS Headers present or not required");
/* show make-image-out-of-canvas-functions here */
})
.fail(function() {
console.warn("Download disabled - CORS Headers missing");
/* ... or hide make-image-out-of-canvas-functions here */
});
Tested and working in IE10+11 and current Chrome 31, FF25, Safari 6 (Desktop).
In IE10 and FF you might encounter a problem if and only if you try to access http-files from a https-script. I don't know about a workaround for that yet.
UPDATE Jan 2014:
The required CORS headers for this should be as follows (Apache config syntax):
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "referer, range, accept-encoding, x-requested-with"
the x-header is required for the ajax request only. It's not used by all but by most browsers as far as I can tell
Also worth noting that the CORS will apply if you are working locally regardless of if the resource is in the same directory as the index.html file you are working with. For me this mean the CORS problems disappeared when I uploaded it to my server, since that has a domain.
You can use base64 of the image on canvas,
While converting into base64 you can use a proxy URL (https://cors-anywhere.herokuapp.com/) before your image path to avoid cross-origin issue
check full details here
https://stackoverflow.com/a/44199382/5172571
var getDataUri = function (targetUrl, callback) {
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var reader = new FileReader();
reader.onloadend = function () {
callback(reader.result);
};
reader.readAsDataURL(xhr.response);
};
var proxyUrl = 'https://cors-anywhere.herokuapp.com/';
xhr.open('GET', proxyUrl + targetUrl);
xhr.responseType = 'blob';
xhr.send();
};
getDataUri(path, function (base64) {
// base64 availlable here
})