Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some more potentially relevant response headers #325

Closed
GitBoudewijn opened this issue Dec 7, 2021 · 5 comments
Closed

Some more potentially relevant response headers #325

GitBoudewijn opened this issue Dec 7, 2021 · 5 comments
Labels
completed Feature or request has been completed enhancement New feature or request

Comments

@GitBoudewijn
Copy link

GitBoudewijn commented Dec 7, 2021

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!

@kleisauke kleisauke added the question Further information is requested label Dec 8, 2021
@kleisauke
Copy link
Member

  1. We don't use SharedArrayBuffer or Performance.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).
  2. 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.
  3. I think you can just use output=json in this case. For example:
    fetch('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);
    });
    I'm not sure whether there is much demand or any uses cases for the X-Original-Size or X-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.

@GitBoudewijn
Copy link
Author

GitBoudewijn commented Dec 8, 2021

  1. 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.

  2. Yeah that's true, I just thought that it doesn't have any downside either.

  3. 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.

@kleisauke
Copy link
Member

kleisauke commented Dec 8, 2021

  1. 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.

  2. The only drawback I can think of is that our response size increases; but that is negligible these days.

  3. Thanks for the use-case! I've just implemented X-Original-Size as X-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 as X-Cache-Status (add_header X-Cache-Status $upstream_cache_status;)? Every time an upstream request is made, you can infer that as cf-cache-status != HIT and X-X-Cache-Status != HIT. I've also added this header to our testing environment.

@kleisauke kleisauke added enhancement New feature or request and removed question Further information is requested labels Dec 8, 2021
@kleisauke kleisauke added the started This issue is being worked on label Dec 11, 2021
@kleisauke
Copy link
Member

Commit f52d724 (which has just been rolled out to production) adds the following response headers to the API:

  1. Cross-Origin-Resource-Policy: cross-origin.
  2. 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
  3. 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.

@kleisauke kleisauke added completed Feature or request has been completed and removed started This issue is being worked on labels Mar 23, 2024
@kleisauke
Copy link
Member

I'll close this issue for now, please feel free to re-open if there's still a problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
completed Feature or request has been completed enhancement New feature or request
Development

No branches or pull requests

2 participants