2

If I'm making a Chrome Extension, how do I open an image in a new tab, if server forces the "Save as..." dialog? As I can see, it is something about the Content-Disposition header property.
There are dozens of server-side Q/A about how to force browser to open that dialog, but I can't find nothing, how to fight with that as an end-user, who doesn't want that dialog window.

Charles
  • 50,943
  • 13
  • 104
  • 142
Nakilon
  • 34,866
  • 14
  • 107
  • 142

2 Answers2

1

In the extended BNF notation of [RFC 822], the Content-Disposition header field is defined as follows:

    disposition := "Content-Disposition" ":"
                   disposition-type
                   *(";" disposition-parm)

    disposition-type := "inline"
                      / "attachment"
                      / extension-token
                      ; values are not case-sensitive

    disposition-parm := filename-parm / parameter

    filename-parm := "filename" "=" value;

If ignoring disposition parameters it simply does the following.

"content-disposition","attachment; filename=fname.jpeg" downloads jpeg file when ever it is served.

"content-disposition","inline; filename=fname.jpeg" displays jpeg file rather downloading jpeg file when ever it is served.

This behavior depends on the browser and the file you are trying to serve.

For example, if you have a JPEG file an inline disposition-type will open the Image within browser, whereas attachment will force it to download.

If you're using a .ZIP file, browsers won't be able to display it inline, so for inline and attachment disposition-type, the file will be downloaded.

You have to use WebRequest API, to modify your headers

Sample Code

chrome.webRequest.onBeforeSendHeaders.addListener(

function (details) {//Modify Headers
    details.requestHeaders.push({
        "name": "content-disposition",
        "value": "inline; filename=`_some_filename.some_extension`"
    });
    return {//Update Headers
        requestHeaders: details.requestHeaders
    };
}, {
    urls: ["<all_urls>"]
}, ["blocking", "requestHeaders"]);//Block the requests

Make sure you declare

"permissions": [
    "webRequest",
    "webRequestBlocking"
  ]
 

in your manifest file

References

EDIT 1

Add your URL for this code and check if it still throws a save as dialog.

chrome.webRequest.onHeadersReceived.addListener(

function (details) {

    var _content_to_append = {
        "name": "content-disposition",
        "value": "inline"
    };
    details.responseHeaders.push(_content_to_append);
    return {
        responseHeaders: details.responseHeaders
    };
}, {
    urls: ["<all_urls>"]
}, ["blocking", "responseHeaders"]);
Community
  • 1
  • 1
Sudarshan
  • 18,140
  • 7
  • 53
  • 61
  • Thank you for such detailed answer, but I can't make it work. Here are a sample problem image url, current permissions and listener from background.js http://pastebin.com/raw.php?i=rQNrvLYp and logged object: https://lh6.googleusercontent.com/-3jxp4W0IZhw/UPLya8PgF_I/AAAAAAAAGdA/wUE5pMC-oM0/s0/temp.PNG It still opens dialog. – Nakilon Jan 13 '13 at 17:45
  • @Nakilon:Can you also share your response header(s),just want to be sure your server is not ignoring any request headers. – Sudarshan Jan 15 '13 at 17:28
  • How do I see response headers? Dev tools show me only url, 'GET' and 200. – Nakilon Jan 15 '13 at 19:40
  • @Nakilon:Open `Network panel` and click on a `request` look for headers tab, where both request and response headers are listed. – Sudarshan Jan 16 '13 at 15:02
  • Ah, sure. Was blind, sry. Request: content-disposition:inline; filename=http://pcdn.500px.net/22852219/051a3352fd22b8fb225afb460c0503a5a0ce6353/4.jpg Responce: Content-Disposition:attachment; filename="" There is a detail that Chrome cached this img, so I hope he doesn't cache headers. – Nakilon Jan 19 '13 at 01:33
  • @Nakilon: Check my EDIT 1, add custom response headers for your `file responses` to set it to inline. – Sudarshan Jan 19 '13 at 09:37
  • 1
    Made it! 1. no need to override sendheaders 2. the headers should be edited inplace, not pushed. So here is final solution: http://pastebin.com/raw.php?i=wY7u1zLt – Nakilon Jan 20 '13 at 13:28
0

@Sudarshan gave the right direction.

But it's appeared on another site, that even Content-Disposition isn't enough.
So my current working code is:

chrome.webRequest.onHeadersReceived.addListener(
    function (details) {
        for (var i in details.responseHeaders) {
            if (details.responseHeaders[i].name == "Content-Disposition")
                details.responseHeaders[i].value = "inline; filename=\"\"";
            if (details.responseHeaders[i].name == "Content-Type")
                details.responseHeaders[i].value = "image/jpeg";
        };
        return { responseHeaders: details.responseHeaders };
    }, {
        urls: [
            "http://qwe.rty.net/*",
            "http://*.qwerty.com/*",
        ]
    }, ["blocking", "responseHeaders"]
);
Nakilon
  • 34,866
  • 14
  • 107
  • 142