(
req_parts: &http::request::Parts,
res_parts: &http::response::Parts,
options: &ServerCacheOptions,
)
| 832 | res_parts: &http::response::Parts, |
| 833 | options: &ServerCacheOptions, |
| 834 | ) -> Option<Duration> { |
| 835 | // RFC 7234: Only cache successful responses (2xx) |
| 836 | if !res_parts.status.is_success() { |
| 837 | return None; |
| 838 | } |
| 839 | |
| 840 | // RFC 9111 §3.5: Check Authorization header |
| 841 | let has_authorization = |
| 842 | req_parts.headers.contains_key(http::header::AUTHORIZATION); |
| 843 | |
| 844 | // RFC 7234: Check Cache-Control directives |
| 845 | if let Some(cc) = res_parts.headers.get(http::header::CACHE_CONTROL) { |
| 846 | let cc_str = cc.to_str().ok()?; |
| 847 | |
| 848 | // RFC 9111 §3.5: If request has Authorization header, only cache if |
| 849 | // response explicitly permits it |
| 850 | if has_authorization |
| 851 | && options.respect_authorization |
| 852 | && !response_permits_authorized_caching(cc_str) |
| 853 | { |
| 854 | return None; |
| 855 | } |
| 856 | |
| 857 | // RFC 7234: MUST NOT store if no-store directive present |
| 858 | if has_directive(cc_str, "no-store") { |
| 859 | return None; |
| 860 | } |
| 861 | |
| 862 | // RFC 7234: MUST NOT store if no-cache |
| 863 | // Note: Per RFC, no-cache means "cache but always revalidate". However, |
| 864 | // without conditional request support (ETag/If-None-Match), we cannot |
| 865 | // revalidate, so we skip caching entirely. |
| 866 | if has_directive(cc_str, "no-cache") { |
| 867 | return None; |
| 868 | } |
| 869 | |
| 870 | // RFC 7234: Shared caches MUST NOT store responses with private directive |
| 871 | if has_directive(cc_str, "private") { |
| 872 | return None; |
| 873 | } |
| 874 | |
| 875 | // RFC 7234: s-maxage directive overrides max-age for shared caches |
| 876 | if let Some(s_maxage) = parse_s_maxage(cc_str) { |
| 877 | let ttl = Duration::from_secs(s_maxage); |
| 878 | let ttl = apply_ttl_constraints(ttl, options); |
| 879 | return Some(ttl); |
| 880 | } |
| 881 | |
| 882 | // RFC 7234: Extract max-age for cache lifetime |
| 883 | if let Some(max_age) = parse_max_age(cc_str) { |
| 884 | let ttl = Duration::from_secs(max_age); |
| 885 | let ttl = apply_ttl_constraints(ttl, options); |
| 886 | return Some(ttl); |
| 887 | } |
| 888 | |
| 889 | // RFC 7234: public directive makes response cacheable |
| 890 | if has_directive(cc_str, "public") { |
| 891 | return options.default_ttl; |
no test coverage detected