Skip to content

Allow web browsers to cache publicly shared files #45399

@f0k

Description

@f0k

How to use GitHub

  • Please use the 👍 reaction to show that you are interested into the same feature.
  • Please don't comment if you have no relevant information to add. It's just extra noise for everyone subscribed to this issue.
  • Subscribe to receive notifications on status change and new comments.

Is your feature request related to a problem? Please describe.
When sharing a file or folder via a public link, Nextcloud serves the download in a way that does not enable functioning caching. It sets cache-control: must-revalidate, post-check=0, pre-check=0, which asks browsers to revalidate each request (which could be okay), but it does not set last-modified or etag, and it does not respect if-modified-since or if-none-match requests.
For an image file preview of a public share, caching works: cache-control includes a max-age, the last-modified response header gives the date the preview was first requested (I assume), and conditional requests with a recent enough if-modified-since return status 304.

(On a side note, "pragma: no-cache" in the response is deprecated, and "post-check" and "pre-check" were never standardized in the "cache-control" header.)

Describe the solution you'd like
The PublicPreviewController uses a FileDisplayResponse to serve the file preview with proper cache control.
Something similar would be nice for the ShareController. That is, instead of forbidding caching in sendHeaders, set the last-modified header to the file modification date and possibly set an etag, and return a 304 response in getSingleFile when appropriate.

Describe alternatives you've considered
My use case is to embed shared files in web pages. The alternative would be to set up a web server to serve static files. Using Nextcloud to do so is not very efficient, but can be handy. For this, it would be useful to avoid needless re-requests of downloads by clients.

Additional context

Simulation of getting a preview URL for the first time:
$ curl -I 'https://SERVER/index.php/apps/files_sharing/publicpreview/SHAREID?file=/&fileId=FILEID&x=1920&y=1200&a=true&etag=ETAG' 
HTTP/2 200 
date: Fri, 17 May 2024 17:38:01 GMT
pragma: no-cache
x-request-id: ZkeV-S6ejSRIelV3YpDT0wAAAQc
cache-control: private, max-age=86400, must-revalidate
content-security-policy: default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none'
feature-policy: autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone 'none';payment 'none'
x-robots-tag: noindex, nofollow
content-disposition: inline; filename="512-512-max.jpg"
expires: Sat, 18 May 2024 17:38:01 +0000
set-cookie: SOME COOKIES
referrer-policy: no-referrer
x-permitted-cross-domain-policies: none
x-xss-protection: 1; mode=block
last-modified: Fri, 17 May 2024 14:20:28 GMT
etag: "98ce490be53325b5f254d210cbab4624"
content-length: 60210
content-type: image/jpeg
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
strict-transport-security: max-age=31536000

Simulation of getting a preview URL for the second time:
$ curl -I 'https://SERVER/index.php/apps/files_sharing/publicpreview/SHAREID?file=/&fileId=FILEID&x=1920&y=1200&a=true&etag=ETAG' -H 'If-Modified-Since: Fri, 17 May 2024 17:38:01 GMT'
HTTP/2 304 

(followed by all the same headers as before)

Getting a download URL:
$ curl -I 'https:/SERVER/index.php/s/SHAREID/download/test.jpg'
HTTP/2 200 
date: Fri, 17 May 2024 17:41:41 GMT
content-security-policy: default-src 'self'; script-src 'self' 'nonce-NONCE'; style-src 'self' 'unsafe-inline'; frame-src *; img-src * data: blob:; font-src 'self' data:; media-src *; connect-src *; object-src 'none'; base-uri 'self';
pragma: no-cache
content-disposition: attachment; filename*=UTF-8''test.jpg; filename="test.jpg"
content-transfer-encoding: binary
expires: 0
cache-control: must-revalidate, post-check=0, pre-check=0
x-accel-buffering: no
set-cookie: SOME COOKIES
referrer-policy: no-referrer
x-permitted-cross-domain-policies: none
x-robots-tag: noindex, nofollow
x-xss-protection: 1; mode=block
content-length: 63834
content-type: image/jpeg
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
strict-transport-security: max-age=31536000

Adding an if-modified-since to the last request does not change the outcome.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions