images
images copied to clipboard
Some more potentially relevant response headers
Hi!
I did some more research on response headers and found the following that would be useful for you to have:
1. Cross-Origin-Resource-Policy: cross-origin
To use some features like high precision timing with Performance.now()
you have to have cross-origin isolation on your site:
http://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy
This requires all resources to have the Cross-Origin-Resource-Policy
header for non-CORS requests (like <img>
tags without crossorigin or CSS background-image).
2. X-Content-Type-Options: nosniff
Pretty much every other image host has this header on all images. Not sure if it's really needed since you transform all the images so the chance that one of them could be interpreted as a script is pretty low. But apparently site security scanners expect this to be set so that could be a benefit as well.
3. Access-Control-Expose-Headers: *
You can do this:
fetch('//images.weserv.nl/?url=images.weserv.nl/lichtenstein.jpg', {
'method': 'HEAD',
}).then(response=>{
console.log(Object.fromEntries(response.headers));
});
But this only allows you to read the default safelisted headers: http://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_response_header
It would be useful to be able to read all headers, for example Age
and X-Images-API
, and then maybe you can add some more headers like X-Width
/X-Height
or X-Original-Size
(content length of the original image) or maybe X-Requested
(timestamp when the image was requested by your server).
Thanks!
- We don't use
SharedArrayBuffer
orPerformance.now()
, so I'm not sure if there are any benefits of setting this header. Setting the CORP header on our site also requires that any sub-resources we load are properly allowed via CORS or CORP, which we cannot ensure at this moment on our homepage (for example, we use Algolia search as an external service). - Indeed, this header is only relevant for user generated content. It's probably redundant to set this header, since all our images are processed. Also, I'm reluctant to set this header only to aid site security scanners.
- I think you can just use
output=json
in this case. For example:
I'm not sure whether there is much demand or any uses cases for thefetch('https://images.weserv.nl/static/lichtenstein.jpg?output=json').then(async (response) => { let data = await response.json(); console.log(data.width); console.log(data.height); });
X-Original-Size
orX-Requested
headers.
Note that any response header we set comes at the expense of performance, although in most cases this is minimal. Also to ensure API compatibility, we cannot add headers and remove them afterwards, therefore we're a bit conservative in such cases. As always, feel free to use our source code to host your own solution.
-
I'm sorry maybe I wasn't clear. With 'you' I meant you as the user. So if I want to use those features on my site and have your images on my site, the images need to have the
Cross-Origin-Resource-Policy: cross-origin
header. -
Yeah that's true, I just thought that it doesn't have any downside either.
-
X-Original-Size
would be so you can calculate the amount of filesize reduction so you can compare different formats and quality settings and calculate how much bandwidth you've saved.X-Requested
would be so that you can know when the image was actually updated, since the regular headers are modified by CloudFlare. But you're right that these could also be added to the JSON, although including it in the headers would mean you can access all of it at once together with the image. Also not all the information from the headers is included in the JSON.
-
You're right, the CORP header is necessary for websites that have opt-in to a cross-origin isolated state and make non-CORS requests to images.weserv.nl. See for example this live demo. I just deployed this to our testing environment (t0.nl) and will add this header on our production environment later this week.
-
The only drawback I can think of is that our response size increases; but that is negligible these days.
-
Thanks for the use-case! I've just implemented
X-Original-Size
asX-Upstream-Response-Length
by doing this on our testing environment (t0.nl):location / { weserv proxy; add_header X-Upstream-Response-Length $upstream_response_length; }
(see for an example: https://t0.nl/?url=images.weserv.nl/lichtenstein.jpg&w=200) Regarding
X-Requested
, could that be implemented asX-Cache-Status
(add_header X-Cache-Status $upstream_cache_status;
)? Every time an upstream request is made, you can infer that ascf-cache-status
!=HIT
andX-X-Cache-Status
!=HIT
. I've also added this header to our testing environment.
Commit https://github.com/weserv/images/commit/f52d724a57949f4f1fc7bc45c9f25119a94d4b84 (which has just been rolled out to production) adds the following response headers to the API:
-
Cross-Origin-Resource-Policy: cross-origin
. -
X-Cache-Status: <MISS|BYPASS|EXPIRED|STALE|UPDATING|REVALIDATED|HIT>
, see: https://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_cache_status -
X-Upstream-Response-Length: <LENGTH>
.
In addition to that, I just enabled the X-Content-Type-Options: nosniff
header in Cloudflare (SSL/TLS -> Edge Certificates -> HTTP Strict Transport Security (HSTS) -> No-Sniff Header -> On
).
I still need to think about adding the Access-Control-Expose-Headers
header, and what value(s) to put in there.
I'll close this issue for now, please feel free to re-open if there's still a problem.