WIP: reverse_proxy,endpoint,uploaded_media: add immutable cache-control flag #1068
No reviewers
Labels
No labels
approved, awaiting change
broken setup
bug
cannot reproduce
configuration
documentation
duplicate
enhancement
extremely low priority
feature request
Fix it yourself
help wanted
invalid
mastodon_api
needs change/feedback
needs docs
needs tests
not a bug
not our bug
planned
pleroma_api
privacy
question
static_fe
triage
wontfix
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
AkkomaGang/akkoma!1068
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "Yonle/akkoma:cachecontrol-1"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
this makes sense I think
Will leave it for a bit in case anyone can think of any weird edge cases
@floatingghost wrote in #1068 (comment):
unless they have weird endpoint that changes pictures on different requests, it seems it's rather onto them. but most of the time, static datas are basically returning the same bytes (emojis, avatar, medias, etc). so refetching them constantly doesn't make any sense.
for the concern though, scripts will need some kind of versioning on their endpoint (eg,
app.8b403.js), but i think we're safe with this one as most apps nowadays are built with this one.the only thing that need to keep in watch will be probablyeh, we're good:/static/terms-of-service.htmland/instance/panel.html, as these can be changed from the time to time. we can fix this by making these two endpoints to have cache expirations of 24h or 12h.For uploaded local media,
immutableis definitely fine, especially since "dedupe" is enforced and the filepaths thus contain the hash of the content. For reverse proxied content it should be fine too; maybe not perfectly accurate but fine (I’m also hoping the reverse proxy uses any remoteCache-Controlinfo when available, but haven’t checked)But for local emoji and frontend images, claiming there won’t be changes for at least two weeks seems problematic. Admins may reasonably just overwrite the configured file to switch out the default background for example and emoji images are updated too sometimes (if the pack was revised or to recompress inefficient images). I don’t think we can claim immutability here, at least not for such a long time.
@Oneric wrote in #1068 (comment):
if for instance the admin changes the default background, the URL endpoint to that new background will be updated & shouldn't cause issue. It will only be problematic when the endpoint used for the background is the same exact endpoint, for example,
https://example.com/background.jpgthe problem here is that 10-30 emojis images are kept being refetched on every textbox interactions, either via the new post or reply field of a post. Emojis images under the same :name: are a bit rare to get updated (unless they're overriding those with the same name, which may require their users to clear cache, however 2w cache should makes sense here), however a pack change should affect literally nothing as the endpoint for emoji pack list are never cached by default.
Exactly. Once a custom background path was setup admins may just overwrite the file instead of changing config again (implying a need to recompile everything). This is not too uncommon.
Same for emoji. I’ve seen an admin changing an emoji file in place several times now (e.g. because the originally added file turned out to be poorly compressed and way too big).
This should already not happen and I don’t see it happening on Firefox with the current backend config and nginx reverse proxy. After the initial load, at least for a short while, subsequent appearance of the image and page reloads just use the cached version without even making a revalidation request.
For page reloads this seems to be not fully spec compliant, but apparently browser have started to reduce revalidation on page reloads for almost a decade now to aid mobile data usage and low bandwidth connections. As my test shows, Firefox also doesn’t send a revalidation request for just recently received, fresh cache entries. Presumably they’ll still revalidate eventually, before
max-ageelapses, else it would already act likeimmutableand the in-place edits i’ve seen wouldn’t have worked as well as they did.Even once
max-agehas passed or something else forces an earlier revalidation, browsers shouldn’t need to fetch the whole image again (if it truly didn’t change), but can just make a revalidation request withIf-Modified-Sinceand receive an empty304 Not Modifiedresponse.Admittedly I haven’t checked whether our static plug can efficiently handle such revalidation requests, but if not support could be added and will not break in-place upgrades.
for some reason, firefox on desktop did exactly that sometimes, however only one time in one session.
firefox on mobile is even worser (than chromium browsers on mobile).
@Oneric wrote in #1068 (comment):
They can try to upload new background URL via Admin-FE, though. I think a better solution might be needed.
Shouldn't this only be visible to a limited amount of people? This really depends on how many people that was in the instance itself, So this one will be ambiguous. Even though it's replaced to a compressed one, Real users might barely notice it until they open the emoji lists in full. This is very depends, But if the admin is managing a single user instance, that would be even more different.
One or 10 emoji changes on a pack that people rarely open will barely have this issues.
Still though, I think this is something the admin of the instance need to improve.
added a commit that did the same thing for
favicon.pngendpointdays later, i think i've changed my mind and now have different opinion about this one:
@Oneric wrote in #1068 (comment):
I don't think it's tolerable or making any sense to sacrifice user experience just to tolerate admin's mistake. Either we want better user experience with reduced bandwidth usage on less frequent refetching or just this.
d73fffca0b303ecf83b07c494cbe0687b2377894reverse_proxy,endpoint,uploaded_media: add immutable cache-control flagto WIP: reverse_proxy,endpoint,uploaded_media: add immutable cache-control flagWIP: reverse_proxy,endpoint,uploaded_media: add immutable cache-control flagto reverse_proxy,endpoint,uploaded_media: add immutable cache-control flagtodo: fix test
reverse_proxy,endpoint,uploaded_media: add immutable cache-control flagto WIP: reverse_proxy,endpoint,uploaded_media: add immutable cache-control flagThe thing is: updating emoji files inplace is not a mistake! Only the proposed change here would turn it into one. Besides the recompression mentioned before, emoji packs can release updated version with some refinements for existing emoji, not only completely new ones.
Also, adding an "immutable" here seems entirely pointless for real-world usage.
First, the "Static" plug we use to serve it already supports cache validation via ETags (enabling browsers to even skip re-downloading past the original max-age unless the file actually changed). Meaning if nothing changed there will be at most a simple revalidation request with a header-only 304 response.
But in practice all modern browsers only revalidate the top-level document on simple reloads instead of everything as the spec originally required. In Firefox this is controlled via the
about:configtogglebrowser.soft_reload.only_force_validate_top_level_document.Even explicit
fetchrequest from JS just immediately replay the cached 200 response without doing any network request for revalidation if the last revalidation or full fetch is sufficiently recent. You can check this in the network tab. If it immediately lists a 200 response but says "from cache" in the column usually showing how much data was transmitted via the network. It will also list detailed timings for all processing stages a 0ms. Everything is only fetched once across repeated textbox interactions or new post loads for me already and otherwise just replays the cached response. I don’t know when exactly the browser decides a non-immutable resource is old enough to actually perform a revalidation request without a forced cache eviction, but it definitely takes more than a couple minutes. Presumably less than the fullmax-ageof currently 2 weeks though.Meaning, I cannot reproduce the problem you want to solve with this breaking change to the static endpoint. If you’re seeing duplicated, actual network request for emoji in quick succession, this is likely a bug either in your browser or your reverse proxy setup (e.g. it might strip incoming or outgoing etag,
If-None-Matchand/or cache-policy headers)@Oneric wrote in #1068 (comment):
it's never a mistake, but it's also unusual for keeping replacing one after another.
@Oneric wrote in #1068 (comment):
i think this is quite pointless to be discussed all along given that not applying this specifically on
/media/by default is some kind of unusual feat. closing.As I wrote in my first reply, it makes sense on
/mediaand the proxy endpoints (even if it probably won’t do too much with modern browsers give nthe results from testing described in the previous post). But the static enpoints are not pointing to immutable content, so here the flag doesn’t make sense, but can degrade things.Extracted the media and proxy bits into #1096 (i.e. your first commit without changing the InstanceStatic plug)
The immutable flags on user-uploaded local media and proxy responses is now merged.
Trying to get rid off unnecessary network traffic to improve the situation on low-bandwidth and/or high-latency networks, or even just for the sake of it are a good goal. But it shouldn’t break existing things. And importantly even with current settings there are no duped network nor revalidation requests for me on ~stock Firefox. This result doesn’t change with Firefox being throttled to 450Kb/s download and 150ms latency. (Again: i observe zero(!) network traffic after the initial download within several minutes (max time i remembered to check again)).
If you see duped refetches and/or revalidations on "every textbox interaction" like you wrote before, then i really think this is an issue in either your instance’s reverse proxy (or media proxy) or browser. It already should only at most perform a rare revalidation. But just in case it was a misreading: requests which are entirely served by the cache and don’t actually cause any network traffic do still show up in Firefox network tab. You can tell them apart by the "from cache" entry in the column otherwise showing how much data was funneled through the network.
If you really want to add an
immutableflag anyway, you can still do so either just for your own instance via an override in your reverse proxy, or if you want to see it as a default for all Akkoma instances falsely claiming immutability might at best be feasible if themay-ageis greatly reduced. Not sure however if a reducedmax-agewithimmutablemight actually end up performing worse in practice than a longermax-agewithout immutability allowing the browser to sparingly use revalidation requests rather than perhaps ending up refetching the whole content more often. This would need further testing for how often common browsers (at least Firefox and Chromium) actually issue revalidation requests and whether they keepetaged caches around past theirmax-agefor potential revalidation or just drop it.(though, if the duped fetches you described are a bug or misconfig of your browser neither helps for non-Akkoma sites)
my browser is a firefox on arch linux, apparently.
@Oneric wrote in #1068 (comment):
still, though. Assuming that emoji file gets replaced under the same filename everytime is kinda the wrong assumption that i disagree most of the time, as that change would be really noticeable and there would be rather question to the admins themselves.
the thing is, if everything that's in
instance/staticis "not static" under any way, especially favicon.png & emojis (excepting frontend files & anything non medias), i don't think it's really accurate to call it "static" in anyhow.but if flexibility is also a side goal, maybe making a config for static file header would be making more sense.
It won’t be replaced every time, but neither do browsers revalidate every time. And when changes happen, it shouldn’ŧ take two weeks for them to become visible.
Have you checked whether the
about:configflag i brought up before is set to the correct value? It defaulted to not revalidating non-root docs for me. And also whether cache-related headers all make it through your reverse proxy and/or media proxy (check request/response headers in network tab).Certain anti-fingerprinting settings might affect this too, as whether a resource is cached or not can be detected and used for fingerprinting (but in that case i’d kinda expect
immutableto not make much of a difference)Also can you share a screenshot of the full width of the network tab (such that all columns are visible), where a duped fetch occurs and with timing details for the later request? (To rule out a misreading of a cache replay as a real network request)
the akkoma-fe is still, under certain circumstances still fetching local emojis quite intensive even though these are barely visible yet. i think i will record the network traffic tab once i open my computer later, however mine has
immutableon our emoji endpoint so you can then try compare it with yours that doesn't has it. still though, even though a recheck with 302 was done, i think the fact that it still make traffic is still a bit of annoyances. it could be both good or slow.hmm, the naming here can be confusing yeah, but it’s consistent with how the term is used in general in web stuff. I believe the "static" naming here is in reference to "static webpage" in contrast to "dynamic" content, i.e. content created at runtime either inside the client via WASM or javascript or rendered on the server-side for this request specifically (e.g. via PHP). The static CSS, HTML and (yes also) JS files are the same for everyone, that is unchanging wrt to whom queries them, what they did before and what parameters (other than the path) are supplied to the server — but the files are not necessarily immutable (unchanging over time).
E.g. Pelican and Hugo are "static site generators", that is, they emit HTM, CSS, etc; but the content of those static sites can and does change (e.g. if a new blog post is published, the index HTML page and RSS feeds change in-place and this change is expected to become visible quickly. Yet since no runtime dynamic components are involved it is still considered a static site.
(I’m guessing you meant 304, not 302 the latter is a redirect response, not anything wrt caches)
How long did it take after the initial fetch before a revalidation was made? As I wrote before, I didn’t even observe revalidation requests, though I also only waited a couple minutes (i configured my browser to clear all client-side data each restart, so I probably can’t test anything taking several days. But your prior description of "every textbox interaction" made it sound like you’re observing this much more frequently anyway)
as of the
about:configthing that you mentioned, it's set totrueby default.i would say this depends on user connection. when it's slow, it gets refetched than revalidated
anyway, here's the recording. Just a normal refresh. That's the case on my end with
immutablebeing set (notice that some emoji are being fetched 4 times each)well crap, let me encode
for some rather strange reason, my video can't be played on forgejo (idk why, probably need faststart? unseekable? dunno), but you can check the video here.
Commented a screenshot to ensure we’ê on the same page how to read the netword tab details.
All but the first request for any given emoji are just cache replays and do not cause any network traffic.
(I don’t know how or why it claims a different size for the same, cached file at one point, but that’s unrealted to the caching)
On initial page load I only see a pair of two requests (one
imginitiator and onefetchfrom still image detection) not four like you seem to get, notably even at the frontend of your own instance with the logged-out defaults. This is probably some FE setting.But apart from this, all but the first request just being cache replays is already true for me too just with
cache-control public, max-age=1209600. And the cache persists at least 30min (max i just tested) without any revalidation request being done (except if i navigate directly to the image URL as them main document of the tab).With Chromium it appears to behave the same, though i didn’t leave it running for 30min yet there.
If this differed for you without
immutable, you might want to check if perhaps your reverse proxy messed with non-immutablecache-controlheaders or whether it’s some (possibly preset by your distro) browser config option. You can also try going to some other Akkoma instance which doesn't setimmutable.as of now, the cache-control header is no longer being set on the reverse proxy but rather on the akkoma-be that's running in my instance. i will give a little comparison later.
back from the other instance, so apparently:
immutabletag, however,/favicon.pngisno-cache. so even with304response, the favicon will still be displayed after we got the 304. this one is still a bit of a problem, so we can try address this.strangely, during the time when i'm still in vanilla akkoma-fe, for some reason:
<Status>in the FE (notification, notes, etc).It should probably allow caching without revalidation, yes. In theory this would be an improvement (but does not need an entire new plug module)
In practice we’ve got a funny situation though, presumably from browser treating favicon specially:
no-cacheand just replays the unvalidated cached favicon anyway. EDIT: coorection: it only used unvalidated caches for request very close to the original one. A reload a little bit later does in fact cause a 304 revalidation. The revalidation does even happen forpublic, max-age=…, immutablepublic, max-age=1209600, immutable(tested against fedinet.waltuh.cyou)Meaning, in practice, nothing will change and the benefit is purely theoretical.
@Oneric wrote in #1068 (comment):
apparently, when porting this to pleroma-be, phnt pointed out that for favicon endpoint, it checks 2 things at once (or similar):
<staticdir>/favicon.pngpriv/instance/static/favicon.pnghence the existence of separate favicon plug
@Oneric wrote in #1068 (comment):
apple being at it again.
interesting observation.
The existing
InstanceStaticmodule already takes care of that (that’s how it can handle it atm), it can simply be reused for another plug, just with different initialisation args. Probably it could even just be added to the same plug currently taking care of emoji and static images, to get (in theory) the same, only rare revalidationBut while it makes sense in principle, in practice there’s no point anyway as all browsers still force revalidations or even full redownloads disregarding cache-control headers. We could still move it to the emoji/image plug (adjusting
only) in case browsers ever drop this favicon special casing in the futurePull request closed