Repository: static-web-server/static-web-server (Rust)

Issue:
Don't force `public` in `Cache-Control` header to prevent conflicts with CDN and Authentication
### Search for duplicate feature request

- [x] I already searched, and this feature request or improvement is not a duplicate.

### Feature scope

Completely new feature

### Feature request related to a problem

https://github.com/static-web-server/static-web-server/blob/c5477fe78573b98b951bf578c67c529aeb70eb49/src/control_headers.rs#L50

Seems like either an option or simply defaulting to not including it would be better. Otherwise, this breaks authorization such as htaccess when passed through a CDN. The CDN caches the pages and no longer requires authorization.

Dropping falls back to effectively the same behavior when no authorization is required. AFAIK the public option is meant to force caching for resources that are known to be public. That seems like a dubious default.

### Describe the solution you'd like

Either drop the public bit or flag to enable/disable it.

### Describe alternatives you've considered

Override header via reverse proxy, but then have to recreate file type TTL logic.

### Build target

All targets

### Additional context

_No response_


Discussion:
I understand the CDN conflict because of the Cache-Control header defaults when using Basic Auth.
However, this default can already be turned off via https://static-web-server.net/features/cache-control-headers/.
Does it work for you?
That then prevent browser side caching or at least doesn't instruct it to do so? It works in the sense that the Basic Auth is not invalidated.
I was mostly curious if there was a reason for explicit `public` that I was missing.
> I was mostly curious if there was a reason for explicit `public` that I was missing.

It was just an ad-hoc default to apply (_force_) browser cache that we did at the time, due to we didn't provide a fine-grained way to apply this header logic (e.g., apply control headers per paths per resource).
Later, we added [Custom-Headers](https://static-web-server.net/features/custom-http-headers/) feature to do that.

But at this point, the cache-control header feature is probably not the best default (depending on the case). But it can be turned off.

However, if you have a better default in mind for this feature, we can talk about it.
The idea is not to force users but rather to be reasonable.

Btw, if you have a proposal, I would suggest changing the issue title and description to reflect that.

Or if you just wanted to ask why and discuss further, you could use the [Discussions](https://github.com/static-web-server/static-web-server/discussions) page and close the issue.

Let me know what your thoughts are on that.
My original thinking was to perhaps just drop the `public` part so the CDN can decide based on headers. Some experimentation makes it unclear if that is consistently respected. As `private` only caches on browser side. Might make sense to drop the scope declaration, but I've ended up overriding via a reverse proxy that I need anyway and could otherwise use your custom headers.

Thanks for the responses and the great project.
Thanks, I see.
Let's remove `public` from `Cache-Control` header then. That change should no break users and will keep cache private as you mentioned, solving the CDN + Authentication issue.
Just FYI, this will be delivered in version `2.38.1` this week.



Patch:
diff --git a/docs/content/features/directory-listing.md b/docs/content/features/directory-listing.md
index 533282c5..22a5c86a 100644
--- a/docs/content/features/directory-listing.md
+++ b/docs/content/features/directory-listing.md
@@ -121,7 +121,7 @@ curl -iH "content-type: application/json" http://localhost:8787
 # HTTP/1.1 200 OK
 # content-type: application/json
 # content-length: 163
-# cache-control: public, max-age=86400
+# cache-control: max-age=86400
 # date: Tue, 11 Oct 2022 23:24:55 GMT
 
 # [{"name":"spécial directöry","type":"directory","mtime":"2022-10-07T00:53:50Z"},{"name":"index.html.gz","type":"file","mtime":"2022-09-27T22:44:34Z","size":332}]⏎
diff --git a/docs/content/features/http-methods.md b/docs/content/features/http-methods.md
index 68972dd8..01d7297f 100644
--- a/docs/content/features/http-methods.md
+++ b/docs/content/features/http-methods.md
@@ -15,7 +15,7 @@ curl -I -X OPTIONS http://localhost:8787/assets/main.js
 # HTTP/1.1 204 No Content
 # allow: OPTIONS, HEAD, GET
 # accept-ranges: bytes
-# cache-control: public, max-age=31536000
+# cache-control: max-age=31536000
 # date: Thu, 10 Mar 2022 21:26:01 GMT
 ```
 
@@ -39,6 +39,6 @@ curl http://localhost:8787/assets/main.js \
 # accept-ranges: bytes
 # access-control-allow-headers: content-type, origin
 # access-control-allow-methods: GET, OPTIONS, HEAD
-# cache-control: public, max-age=31536000
+# cache-control: max-age=31536000
 # date: Thu, 10 Mar 2022 21:45:55 GMT
 ```
diff --git a/src/control_headers.rs b/src/control_headers.rs
index 670480f2..2d34c7e8 100644
--- a/src/control_headers.rs
+++ b/src/control_headers.rs
@@ -47,7 +47,7 @@ pub fn append_headers(uri: &str, resp: &mut Response<Body>) {
     resp.headers_mut().insert(
         "cache-control",
         format!(
-            "public, max-age={}",
+            "max-age={}",
             // It caps value in seconds at ~136 years
             std::cmp::min(max_age, u32::MAX as u64)
         )
@@ -100,7 +100,7 @@ mod tests {
             assert_eq!(resp.status(), StatusCode::OK);
             assert_eq!(
                 cache_control.to_str().unwrap(),
-                format!("public, max-age={MAX_AGE_ONE_HOUR}")
+                format!("max-age={MAX_AGE_ONE_HOUR}")
             );
         }
     }
@@ -116,7 +116,7 @@ mod tests {
         assert_eq!(resp.status(), StatusCode::OK);
         assert_eq!(
             cache_control.to_str().unwrap(),
-            format!("public, max-age={MAX_AGE_ONE_DAY}")
+            format!("max-age={MAX_AGE_ONE_DAY}")
         );
     }
 
@@ -132,7 +132,7 @@ mod tests {
             assert_eq!(resp.status(), StatusCode::OK);
             assert_eq!(
                 cache_control.to_str().unwrap(),
-                format!("public, max-age={MAX_AGE_ONE_YEAR}")
+                format!("max-age={MAX_AGE_ONE_YEAR}")
             );
         }
     }


Test patch:
diff --git a/tests/compression.rs b/tests/compression.rs
index 35ea122a..8e89059f 100644
--- a/tests/compression.rs
+++ b/tests/compression.rs
@@ -60,7 +60,7 @@ pub mod tests {
                 );
                 assert_eq!(
                     res.headers().get("cache-control"),
-                    Some(&HeaderValue::from_static("public, max-age=86400"))
+                    Some(&HeaderValue::from_static("max-age=86400"))
                 );
                 assert_eq!(
                     res.headers().get("server"),
diff --git a/tests/handler.rs b/tests/handler.rs
index eb6b295b..3ef17c99 100644
--- a/tests/handler.rs
+++ b/tests/handler.rs
@@ -89,7 +89,7 @@ pub mod tests {
 
                 assert_eq!(
                     res.headers().get("cache-control"),
-                    Some(&HeaderValue::from_static("public, max-age=86400"))
+                    Some(&HeaderValue::from_static("max-age=86400"))
                 );
                 assert_eq!(
                     res.headers().get("server"),