I originally posted the question on the Actix discussion boards over at GitHub, but I think it may get a bit more exposure in SO, so here it goes.
So, I have a setup like this:
// --snip--
.wrap(DefaultHeaders::new().header("cache-control", "public, max-age=5, must-revalidate"))
.service(
actix_files::Files::new("/", &settings.server.public_dir)
.index_file(&settings.server.index_file)
)
// --snip--
If I run my server without SSL, it defaults to HTTP/1.1 and so when I make a request (any browser) to a static file, for example app.js
, everything works as I would expect. The server returns a 200 status with the correct file and the correct caching header along with an ETag
and Last-Modified
headers. Etags and last modified are enabled by default.
If I make a subsequent request in less than 5 seconds, there is no surprise either - the browsers don't attempt a new request because they have cached the file for 5 seconds.
When I make another request in more than 5 seconds, browsers would correctly send conditional requests to the server, including an if-none-match
header with the expected etag value for app.js
and the server would correctly return a 304 Not Modified
response without actually sending the file in the body of the response.
RESPONSE: Ok(
ServiceResponse HTTP/1.1 304 Not Modified
headers:
"last-modified": "Mon, 08 Feb 2021 14:56:48 GMT"
"accept-ranges": "bytes"
"cache-control": "public, max-age=5, must-revalidate"
"content-encoding": "gzip"
"content-type": "image/jpeg"
"etag": "\"c55582f:11923:60215130:4678e1d\""
"content-disposition": "inline; filename=\"test.jpeg\""
body: Stream
)
There are no surprises here either as this behaviour is exactly what I expect to happen. The problem is when I enable SSL and my server starts returning streaming bodies over HTTP/2.
Chrome and Firefox browsers behave the exact same way as before, requesting the resource again if the subsequent request is made after 5 seconds and when a 304 response is received, they simply load my app.js
from their caches.
Safari (both on macos and iOS), on the other hand, has absolutely no clue how to deal with the 304 response. It does correctly send the if-none-match and since-last-modified headers, but when actix replies with 304, it can't load my static file.
The Network tab doesn't help either:
Where it says "No response headers" is obviously BS, since I can debug the headers in Actix and see they are in fact correct:
RESPONSE: Ok(
ServiceResponse HTTP/1.1 304 Not Modified
headers:
"last-modified": "Sun, 14 Feb 2021 10:54:28 GMT"
"accept-ranges": "bytes"
"content-encoding": "br"
"content-type": "application/javascript"
"etag": "\"a352043:2db3:60290164:2f00192\""
"content-disposition": "attachment; filename=\"VideoPlayer.js\""
body: Stream
)
I'm noticing that on the first request to the file when the browser hasn't cached it, the response is a HTTP/2, but the response to the conditional request is a HTTP/1.1 as you can see in the excerpt above.
Been stuck on this one for a while how, so any help or direction is greatly appreciated.
Thanks!