File download rename not working - html

I try to rename file with download attribute but it's not working.
OK
FIDDLE

It only works if the file is on the same origin so if you can download a external file with CORS + ajax then you can save the blob with a custom name
$('a').click(function(evt){
evt.preventDefault();
var name = this.download;
// we need a blob so we can create a objectURL and use it on a link element
// jQuery don't support responseType = 'blob' (yet)
// So I use the next version of ajax only avalible in blink & firefox
// it also works fine by using XMLHttpRequest v2 and set the responseType
fetch("https://crossorigin.me/" + this.href)
// res is the beginning of a request it only gets the response headers
// here you can use .blob() .text() .json or res.arrayBuffer() depending
// on what you need, if it contains Content-Type: application/json
// then you might want to choose res.json()
// all this returns a promise
.then(res => res.blob())
.then(blob => {
$("<a>").attr({
download: name,
href: URL.createObjectURL(blob)
})[0].click();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
OK

From the docs you linked:
If the HTTP header Content-Disposition: is present and gives a different filename than this attribute, the HTTP header has priority over this attribute.
My guess is that the server you're linking to sets this header.
Also if you're linking to an external resource it likely won't work:
This attribute is only honored for links to resources with the same-origin.

It appears that this attribute doesn't work anymore for external files, due to possible security concerns.
You can find a discussion about this issue for Chrome here
Use of the 'download' attribute will always trigger a download, but from M-35 onwards will only honor the suggested filename if the final resource URL is same-origin as the document. Even when it doesn't, as long as a MIME type is specified correctly, it will receive a filename like 'download.' where is the extension known to the host OS as mapping to the specified MIME type. If the resource is served with a Content-Disposition, then the Content-Disposition will take precedence.
And for Firefox here and here

Related

Display image that returns HTTP 503 in Firefox

I have a status badge image that returns the HTTP code 503 when the respective service is offline (but the webserver is still there serving calls). Now opening the image URL directly will display the image properly, regardless of the underlying 503 error code. But using it inside an <img> tag shows the broken image icon. How can I prevent that while still allowing the image itself to return a 503? (External services depend on that)
Here are some screenshots to illustrate what's going on:
The badge on the page:
The status message in the developer console:
The badge itself:
Note: This happens on Firefox. Not Chrome
Edit: Here are a few requested pieces information:
Firefox 78.0.2 (64-Bit)
It's served from the same domain. But the domain is essentially just proxying serveral underlying webservices. And this badge is originating from a different service but all on the same domain.
It's a SVG image if that makes any difference.
Since XMLHttpRequest can retrieve the output of any request, no matter the response code, it is possible to request for the image with XMLHttpRequest, and then convert the blob response type to a base64 format image, which can be loaded in the browser.
The CORS proxy I used in the sample code may not be necessary in the majority of cases, but could be useful in the case where the image you are trying to display has weird response headers that prevent access to the image from another domain.
Here is the sample code. It should work no matter the response code, CORS, etc.
var xhr = new XMLHttpRequest();
xhr.onload = function () {
var reader = new FileReader();
reader.onloadend = function () {
// here, reader.result contains the base64-formatted string you can use to set the src attribute with
document.getElementsByTagName('img')[0].src = reader.result; // sets the first <img> tag to display the image, change to the element you want to use
};
reader.readAsDataURL(xhr.response);
};
xhr.open('GET', "https://cors-anywhere.herokuapp.com/i.stack.imgur.com/8wB1j.png"); // don't include the HTTP/HTTPS protocol in the url
xhr.responseType = 'blob';
xhr.setRequestHeader('X-Requested-With', 'xhr');
xhr.send();
<img src="about:blank">
Everything works, as when you go into Inspect Element, you see that the src attribute of the <img> tag points to a base64 URL that can load in any browser.
You might want to compress or resize your images before uploading it to server , as they might be large enough to keep the server busy and show the error as most of the time, a 503 error occurs because the server is too busy.
More over the image is SVG so it might render dimesions before completing, hence I'd suggest
Try replacing the SVG with PNG or JPG
Also try for site like https://tinypng.com/ to compress the image size
This might work for you

How does img srcs' internal algorithm work?

I am curious as to what browsers (Specifically chrome) are doing when you set an img tags src to a path which returns a png binary string vs. if you would call this endpoint manually (Say using Ajax or Axios) and then set the images src to this PNG binary manually. Because the results are different between the two.
I am running a Node/expressJs server, which has an image file which returns from the images/ path.
router.get('images/', async function(req, res) {
try {
return await fs
.createReadStream('./images/sample.png')
.pipe(res);
} catch (err) {
res.status(400).json({ message: err.message });
}
});
This API call will return a PNG binary string.
scenario 1 - setting the img src to the endpoint where the PNG lives
If I will set the img element as such <img src="http://localhost/images/"
This call will return the PNG binary from my Node server and automatically display everything correctly.
scenario 2 - Using axios to request this PNG manually
If however, I would use a library like axios, to call this endpoint manually, I would get back a PNG binary string (In the chrome dev-tools 'network' tab, when looking at repsonse data, I even see a nice preview thumbnail of the image, so something in that panel is also correctly taking the PNG data and displaying it in an img element there). But if I will take this data and try to set it to the src of the image tag, I need to do all kinds of base64 conversions before it will work.
So my question is - What is the internal algo of the img element, for when it receives binary image data from a server?
There is no 'internal algorithm'. src is an HTML attribute that expects a URI, whether it is an HTTP URI or a Base64 URI. The reason you have to convert the data to Base64 if you request the image using JavaScript is because this is the most straightforward way to represent binary data as a URI. When the browser sees a Base64 URI, then it just converts it back into binary data and displays it.

HTML <object> - download file if it cannot be loaded

I have a web application that serves files for viewing. If it's a PDF, I simply attach it to an <object> element. However, the app supports serving word, excel, and powerpoint files. I have tried looking for ways to preview them online, but apparently we do not have the proper technology for that (at least not natively in a browser). So instead, I want the user to download the file to view locally.
The front-end is built with React and the back-end with Spring Boot. Currently, all static resources that are documents (PDF's, docs, spreadsheets, etc.) are served under the "/document-files/**" ant-matcher. Additionally, these resources can only be viewed privately, meaning that you have to be logged in to the application to view them. Here's how part of my SecurityConfig file looks like:
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String documentRootPath = "file:" + this.documentRootPath;
registry.addResourceHandler("/resources/**").addResourceLocations("resources/");
registry.addResourceHandler("/document-files/**").addResourceLocations(documentRootPath);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // ant matchers below are api routes and the baseUri for serving documents
.antMatchers("/clients/**", "/projects/**", "/documents/**", "/document-files/**").authenticated()
.anyRequest().permitAll() //... additional method chaining omitted for brevity
}
The problem is apparently just on the front end. I don't think it has anything to do with the configuration, but I posted it for reference. With this configuration I can download and preview PDF files just fine, using <object> but for all other files, the file does not load, so in <object> I add a link to open the file like so:
render() {
// some code omitted for brevity
return (
<Module>
{!this.state.currDoc ? (
<ul className={this.state.displayType}>{list}</ul>
) : (
<object
data={"/document-files" + this.state.filePath}
type={this.mimeTypes[document.fileType]}
title={"Current Document: " + document.description + "." + document.fileType.toLowerCase()}>
{document.fileType === "PDF" ? "File could not be loaded!" : <div id="download-prompt">This file cannot be previewed online, click below to download and open locally.<a href={"http://localhost:3000/document-files" + this.state.filePath} download>Open</a></div>}
</object>
)}
</Module>
);
}
Upon clicking, the "save as" dialog box appears with the file name populated and the correct mime type but once I hit save, Chrome displays "Failed - No File". I have tried writing the href with and without the hostname. I've also tried removing the download attribute, but it redirects the page back to itself. I've even tried onLoad attribute on <object> but apparently that only works for images. I checked the network tab on dev tools and there is no record of the file being downloaded, unlike PDFs where the request is noted down.
How can I make non-PDF files download correctly using this setup?
Thanks to javilobo8's GitHubGist, I found a way to download files using Axios, which library I was already using in my app to begin with. For quick reference, here is his code:
axios({
url: 'http://localhost:5000/static/example.xlsx',
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf');
document.body.appendChild(link);
link.click();
});
Also, there's multiple ways to work with Blobs, depending on if you're in IE, a browser that supports HTML5's Blob object, or another browser. This question helps split the code in 3 ways to form the dataUri for downloading raw data.
After setting up my <a> tag, I just trigger the click event and the non-PDF file downloads!

Chrome extension, replace HTML in response code before browser displays it

i wonder if there is some way to do something like that:
If im on a specific site i want that some of javascript files to be loaded directly from my computer (f.e. file:///c:/test.js), not from the server.
For that i was thinking if there is a possibility to make an extension which could change HTML code in a response which browser gets right before displaying it. So whole process should look like that:
request is made
browser gets response from server
#response is changed# - this is the part when extension comes in
browser parse changed response and display page with that new response.
It doesnt even have to be a Chrome extension anyway. It should just do the job described above. It can block original file and serve another one (DNS/proxy?) or filter whole HTTP traffic in my computer and replace specific code to another one of matched response.
You can use the WebRequest API to achieve that. For example, you can add a onBeforeRequest listener and redirect some requests:
chrome.webRequest.onBeforeRequest.addListener(function(details)
{
var responseData = "<div>Some text</div>"
return {redirectUrl: "data:text/html," + encodeURIComponent(responseData)};
}, {urls: ["https://www.google.com/"]}, ["blocking"]);
This will display a <div> element with the text "some text" instead of the Google homepage. Note that you can only redirect to URLs that the web server itself is allowed to redirect to. This means that redirecting to file:/// URLs is not possible, and you can only redirect to files inside your extension if these are web accessible. data: and http: URLs work fine however.
In Windows you can use the Proxomitron (proxomitron.info) which is a local proxy that can intercept any page or file being loading into your browser and change it using regular expressions (no DOM parsing) however you want, before it is rendered by the browser.

How to set the <img> tag with basic authentication

I would like to display the image from a network camera on my web page, but the image is behind a HTTP basic authentication server.
In Firefox and Chrome I can do this:
<img width="320" height="200" src="http://username:password#server/Path" />
But in Internet Explorer 8, I get an empty image box. If I use JQuery to set the src attribute, IE8 displays a blank src. It looks like IE8 is checking the string and rejecting it.
Is there a way to put the basic authentication credentials in the img tag?
Bottom line: Not all browsers allow this. It may work in some but not others.
But as someone else has said already, it's not very safe -- you're effectively giving the login and password details to anyone who browses the page. Not good.
A better option would be proxy it through the same server that you're providing the html code from, then the href in the <img> tag could just be a local URL, and no-one need know where the image is actually coming from.
You can load your img with AJAX, using XMLHttpRequest. As you might know, XMLHttpRequest has a setRequestHeaders method, so you will be able to manipulate headers for your request, hence, you will be able to do basic HTTP authentication.
Best way is to create a login page, then setup port forwarding on your router to display the camera. Does the camera come with web software?
See http://support.microsoft.com/kb/834489 and http://msdn.microsoft.com/en-us/library/ie/ee330735(v=vs.85).aspx#login_creds_urls
Long story short, usernames/passwords are not formally supported under the HTTP/HTTPS protocol schemes and due to their use in phishing attacks, they were disabled in IE6 on XPSP2. Support can be manually re-enabled by the user using a registry override (FEATURE_HTTP_USERNAME_PASSWORD_DISABLE) but this is not recommended.
Try http proxy.
On server side, enable tinyProxy, create ReversePath to
basic authentication server in configuration like:
AddHeader "Authorization" "Basic dXNlcjpwYXNz"
ReversePath "/foo/" "http://somewhere:3480/foo/"
dXNlcjpwYXNz is base64 encoded string from user:pass
Enable reverse proxy in Apache or NGINX to tinyProxy path http://localhot:8888/foo/
Img Source accessable from local server instead of old way deprecated, without http auth pop-up or CORS error.
http://user:pass#somewhere:3480/foo/DEST.jpg
ajax add http header works!
pictureUrl = "https://somewhere/file.jpg";
var oReq = new XMLHttpRequest();
oReq.open("GET", pictureUrl, true);
oReq.setRequestHeader("Authorization", "Basic " + btoa("UserName"+":"+"Password"));
// use multiple setRequestHeader calls to set multiple values
oReq.responseType = "arraybuffer";
oReq.onload = function (oEvent) {
var arrayBuffer = oReq.response; // Note: not oReq.responseText
if (arrayBuffer) {
var u8 = new Uint8Array(arrayBuffer);
var b64encoded = btoa(String.fromCharCode.apply(null, u8));
var mimetype="image/jpeg"; // or whatever your image mime type is
document.getElementById("iOdata").src="data:"+mimetype+";base64,"+b64encoded;
}
};
oReq.send(null);