Skip to content

Commit

Permalink
Prefer lower case headers.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Feb 22, 2022
1 parent 68cf79d commit 6efa762
Show file tree
Hide file tree
Showing 19 changed files with 317 additions and 317 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ Rack::Cache
===========

Rack::Cache is suitable as a quick drop-in component to enable HTTP caching for
Rack-based applications that produce freshness (Expires, Cache-Control) and/or
validation (Last-Modified, ETag) information:
Rack-based applications that produce freshness (`expires`, `cache-control`)
and/or validation (`last-modified`, `etag`) information:

* Standards-based (RFC 2616)
* Freshness/expiration based caching
* Validation (If-Modified-Since / If-None-Match)
* Vary support
* Cache-Control: public, private, max-age, s-maxage, must-revalidate,
and proxy-revalidate.
* Validation (`if-modified-since` / `if-none-match`)
* `vary` support
* `cache-control` `public`, `private`, `max-age`, `s-maxage`, `must-revalidate`,
and `proxy-revalidate`.
* Portable: 100% Ruby / works with any Rack-enabled framework
* Disk, memcached, and heap memory storage backends

Expand Down Expand Up @@ -95,7 +95,7 @@ Noop entity store

Does not persist response bodies (no disk/memory used).<br/>
Responses from the cache will have an empty body.<br/>
Clients must ignore these empty cached response (check for X-Rack-Cache response header).<br/>
Clients must ignore these empty cached response (check for `x-rack-cache` response header).<br/>
Atm cannot handle streamed responses, patch needed.

```Ruby
Expand Down
12 changes: 6 additions & 6 deletions doc/configuration.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ configuration context to write messages to the errors stream.

An integer specifying the number of seconds a cached object should be considered
"fresh" when no explicit freshness information is provided in a response.
Explicit `Cache-Control` or `Expires` response headers always override this
Explicit `cache-control` or `expires` response headers always override this
value. The `default_ttl` option defaults to `0`, meaning responses without
explicit freshness information are considered immediately "stale" and will not
be served from cache without validation.
Expand Down Expand Up @@ -79,17 +79,17 @@ An array of request header names that cause the response to be treated with
private cache control semantics. The default value is `['Authorization', 'Cookie']`.
If any of these headers are present in the request, the response is considered
private and will not be cached _unless_ the response is explicitly marked public
(e.g., `Cache-Control: public`).
(e.g., `cache-control: public`).

### `allow_reload`

A boolean specifying whether reload requests sent by the client should be
honored by the cache. When this option is enabled (`rack-cache.allow_reload`
is `true`), requests that include a `Cache-Control: no-cache` header cause
is `true`), requests that include a `cache-control: no-cache` header cause
the cache to discard anything it has stored for the request and ask that the
response be fully generated.

Most browsers include a `Cache-Control: no-cache` header when the user performs
Most browsers include a `cache-control: no-cache` header when the user performs
a "hard refresh" (e.g., holding `Shift` while clicking the "Refresh" button).

*IMPORTANT: Enabling this option globally allows all clients to break your cache.*
Expand All @@ -98,11 +98,11 @@ a "hard refresh" (e.g., holding `Shift` while clicking the "Refresh" button).

A boolean specifying whether revalidate requests sent by the client should be
honored by the cache. When this option is enabled (`rack-cache.allow_revalidate`
is `true`), requests that include a `Cache-Control: max-age=0` header cause the
is `true`), requests that include a `cache-control: max-age=0` header cause the
cache to assume its copy of the response is stale, resulting in a conditional
GET / validation request to be sent to the server.

Most browsers include a `Cache-Control: max-age=0` header when the user performs
Most browsers include a `cache-control: max-age=0` header when the user performs
a refresh (e.g., clicking the "Refresh" button).

*IMPORTANT: Enabling this option globally allows all clients to break your cache.*
Expand Down
12 changes: 6 additions & 6 deletions doc/faq.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ approach to caching.

__Rack::Cache__ takes a standards-based approach to caching that provides some
benefits over framework-integrated systems. It uses standard HTTP headers
(`Expires`, `Cache-Control`, `Etag`, `Last-Modified`, etc.) to determine
(`expires`, `cache-control`, `Etag`, `last-modified`, etc.) to determine
what/when to cache. Designing applications to support these standard HTTP
mechanisms gives the benefit of being able to switch to a different HTTP
cache implementation in the future.
Expand Down Expand Up @@ -74,9 +74,9 @@ Features
### Q: Does Rack::Cache support validation?

Yes. Both freshness and validation-based caching is supported. A response
will be cached if it has a freshness lifetime (e.g., `Expires` or
`Cache-Control: max-age=N` headers) and/or includes a validator (e.g.,
`Last-Modified` or `ETag` headers). When the cache hits and the response is
will be cached if it has a freshness lifetime (e.g., `expires` or
`cache-control: max-age=N` headers) and/or includes a validator (e.g.,
`last-modified` or `etag` headers). When the cache hits and the response is
fresh, it's delivered immediately without talking to the backend application;
when the cache is stale, the cached response is validated using a conditional
GET request.
Expand All @@ -103,9 +103,9 @@ own cache policy.
Although planned, there is currently no mechanism for manually purging
an entry stored in the cache.

Note that using an `Expires` or `Cache-Control: max-age=N` header and relying on
Note that using an `expires` or `cache-control: max-age=N` header and relying on
manual purge to invalidate cached entry can often be implemented more simply
using efficient validation based caching (`Last-Modified`, `Etag`). Many web
using efficient validation based caching (`last-modified`, `Etag`). Many web
frameworks are based entirely on manual purge and do not support validation at
the cache level.

Expand Down
6 changes: 3 additions & 3 deletions doc/index.markdown
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
__Rack::Cache__ is suitable as a quick drop-in component to enable HTTP caching
for [Rack][]-based applications that produce freshness (`Expires`,
`Cache-Control`) and/or validation (`Last-Modified`, `ETag`) information.
for [Rack][]-based applications that produce freshness (`expires`,
`cache-control`) and/or validation (`last-modified`, `etag`) information.

* Standards-based (see [RFC 2616][rfc] / [Section 13][s13]).
* Freshness/expiration based caching
* Validation
* Vary support
* `vary` support
* Portable: 100% Ruby / works with any [Rack][]-enabled framework.
* Disk, memcached, and heap memory [storage backends][storage].

Expand Down
2 changes: 1 addition & 1 deletion doc/layout.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html lang='en'>
<head>
<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>
<meta http-equiv='content-type' content='text/html;charset=utf-8'>
<title>Rack::Cache <%= title %></title>
<link rel='stylesheet' href='rack-cache.css' type='text/css' media='all'>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.2.3.js'></script>
Expand Down
4 changes: 2 additions & 2 deletions lib/rack/cache.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# = HTTP Caching For Rack
#
# Rack::Cache is suitable as a quick, drop-in component to enable HTTP caching
# for Rack-enabled applications that produce freshness (+Expires+, +Cache-Control+)
# and/or validation (+Last-Modified+, +ETag+) information.
# for Rack-enabled applications that produce freshness (+expires+, +cache-control+)
# and/or validation (+last-modified+, +etag+) information.
#
# * Standards-based (RFC 2616 compliance)
# * Freshness/expiration based caching and validation
Expand Down
22 changes: 11 additions & 11 deletions lib/rack/cache/cache_control.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module Rack
module Cache

# Parses a Cache-Control header and exposes the directives as a Hash.
# Parses a cache-control header and exposes the directives as a Hash.
# Directives that do not have values are set to +true+.
class CacheControl < Hash
def initialize(value=nil)
Expand Down Expand Up @@ -80,7 +80,7 @@ def no_store?
end

# The expiration time of an entity MAY be specified by the origin
# server using the Expires header (see section 14.21). Alternatively,
# server using the expires header (see section 14.21). Alternatively,
# it MAY be specified using the max-age directive in a response. When
# the max-age cache-control directive is present in a cached response,
# the response is stale if its current age is greater than the age
Expand All @@ -89,19 +89,19 @@ def no_store?
# response is cacheable (i.e., "public") unless some other, more
# restrictive cache directive is also present.
#
# If a response includes both an Expires header and a max-age
# directive, the max-age directive overrides the Expires header, even
# if the Expires header is more restrictive. This rule allows an origin
# If a response includes both an expires header and a max-age
# directive, the max-age directive overrides the expires header, even
# if the expires header is more restrictive. This rule allows an origin
# server to provide, for a given response, a longer expiration time to
# an HTTP/1.1 (or later) cache than to an HTTP/1.0 cache. This might be
# useful if certain HTTP/1.0 caches improperly calculate ages or
# expiration times, perhaps due to desynchronized clocks.
#
# Many HTTP/1.0 cache implementations will treat an Expires value that
# Many HTTP/1.0 cache implementations will treat an expires value that
# is less than or equal to the response Date value as being equivalent
# to the Cache-Control response directive "no-cache". If an HTTP/1.1
# to the cache-control response directive "no-cache". If an HTTP/1.1
# cache receives such a response, and the response does not include a
# Cache-Control header field, it SHOULD consider the response to be
# cache-control header field, it SHOULD consider the response to be
# non-cacheable in order to retain compatibility with HTTP/1.0 servers.
#
# When the max-age directive is included in the request, it indicates
Expand All @@ -114,7 +114,7 @@ def max_age
# If a response includes an s-maxage directive, then for a shared
# cache (but not for a private cache), the maximum age specified by
# this directive overrides the maximum age specified by either the
# max-age directive or the Expires header. The s-maxage directive
# max-age directive or the expires header. The s-maxage directive
# also implies the semantics of the proxy-revalidate directive. i.e.,
# that the shared cache must not use the entry after it becomes stale
# to respond to a subsequent request without first revalidating it with
Expand All @@ -128,7 +128,7 @@ def shared_max_age
# If a response includes a r-maxage directive, then for a reverse cache
# (but not for a private or proxy cache), the maximum age specified by
# this directive overrides the maximum age specified by either the max-age
# directive, the s-maxage directive, or the Expires header. The r-maxage
# directive, the s-maxage directive, or the expires header. The r-maxage
# directive also implies the semantics of the proxy-revalidate directive.
# i.e., that the reverse cache must not use the entry after it becomes
# stale to respond to a subsequent request without first revalidating it
Expand All @@ -148,7 +148,7 @@ def reverse_max_age
# MUST NOT use the entry after it becomes stale to respond to a
# subsequent request without first revalidating it with the origin
# server. (I.e., the cache MUST do an end-to-end revalidation every
# time, if, based solely on the origin server's Expires or max-age
# time, if, based solely on the origin server's expires or max-age
# value, the cached response is stale.)
#
# The must-revalidate directive is necessary to support reliable
Expand Down
18 changes: 9 additions & 9 deletions lib/rack/cache/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ def call!(env)
end
end

# log trace and set X-Rack-Cache tracing header
# log trace and set x-rack-cache tracing header
trace = @trace.join(', ')
response.headers['X-Rack-Cache'] = trace
response.headers['x-rack-cache'] = trace

# write log message to rack.errors
if verbose?
Expand Down Expand Up @@ -113,7 +113,7 @@ def private_request?
@private_header_keys.any? { |key| @env.key?(key) }
end

# Determine if the #response validators (ETag, Last-Modified) matches
# Determine if the #response validators (etag, last-modified) matches
# a conditional value specified in #request.
def not_modified?(response)
last_modified = @request.env['HTTP_IF_MODIFIED_SINCE']
Expand Down Expand Up @@ -181,7 +181,7 @@ def lookup
if entry
if fresh_enough?(entry)
record :fresh
entry.headers['Age'] = entry.age.to_s
entry.headers['age'] = entry.age.to_s
entry
else
record :stale
Expand All @@ -204,7 +204,7 @@ def validate_with_stale_cache_failover(entry)
rescue => e
record :connnection_failed
age = entry.age.to_s
entry.headers['Age'] = age
entry.headers['age'] = age
record "Fail-over to stale cache data with age #{age} due to #{e.class.name}: #{e}"
entry
end
Expand Down Expand Up @@ -232,12 +232,12 @@ def validate(entry)
record :valid

# Check if the response validated which is not cached here
etag = response.headers['ETag']
etag = response.headers['etag']
return response if etag && request_etags.include?(etag) && !cached_etags.include?(etag)

entry = entry.dup
entry.headers.delete('Date')
%w[Date Expires Cache-Control ETag Last-Modified].each do |name|
entry.headers.delete('date')
%w[Date expires cache-control etag last-modified].each do |name|
next unless value = response.headers[name]
entry.headers[name] = value
end
Expand Down Expand Up @@ -287,7 +287,7 @@ def fetch
def store(response)
strip_ignore_headers(response)
metastore.store(@request, response, entitystore)
response.headers['Age'] = response.age.to_s
response.headers['age'] = response.age.to_s
rescue => e
log_error(e)
nil
Expand Down
2 changes: 1 addition & 1 deletion lib/rack/cache/entity_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ def self.resolve(uri)
# Set `entitystore` to 'noop:/'.
# Does not persist response bodies (no disk/memory used).
# Responses from the cache will have an empty body.
# Clients must ignore these empty cached response (check for X-Rack-Cache response header).
# Clients must ignore these empty cached response (check for x-rack-cache response header).
# Atm cannot handle streamed responses, patch needed.
#
class Noop < EntityStore
Expand Down
20 changes: 10 additions & 10 deletions lib/rack/cache/meta_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ def lookup(request, entity_store)

# find a cached entry that matches the request.
env = request.env
match = entries.detect{ |req,res| requests_match?((res['Vary'] || res['vary']), env, req) }
match = entries.detect{ |req,res| requests_match?((res['vary'] || res['vary']), env, req) }
return nil if match.nil?

_, res = match
if body = entity_store.open(res['X-Content-Digest'])
if body = entity_store.open(res['x-content-digest'])
restore_response(res, body)
else
# the metastore referenced an entity that doesn't exist in
Expand All @@ -64,14 +64,14 @@ def store(request, response, entity_store)

# write the response body to the entity store if this is the
# original response.
if response.headers['X-Content-Digest'].nil?
if response.headers['x-content-digest'].nil?
if request.env['rack-cache.use_native_ttl'] && response.fresh?
digest, size = entity_store.write(response.body, response.ttl)
else
digest, size = entity_store.write(response.body)
end
response.headers['X-Content-Digest'] = digest
response.headers['Content-Length'] = size.to_s unless response.headers['Transfer-Encoding']
response.headers['x-content-digest'] = digest
response.headers['content-length'] = size.to_s unless response.headers['Transfer-Encoding']

# If the entitystore backend is a Noop, do not try to read the body from the backend, it always returns an empty array
unless entity_store.is_a? Rack::Cache::EntityStore::Noop
Expand All @@ -91,12 +91,12 @@ def store(request, response, entity_store)
vary = response.vary
entries =
read(key).reject do |env, res|
(vary == (res['Vary'] || res['vary'])) &&
(vary == (res['vary'] || res['vary'])) &&
requests_match?(vary, env, stored_env)
end

headers = persist_response(response)
headers.delete('Age')
headers.delete('age')
headers.delete('age')

entries.unshift [stored_env, headers]
Expand Down Expand Up @@ -146,13 +146,13 @@ def persist_request(request)
# Converts a stored response hash into a Response object. The caller
# is responsible for loading and passing the body if needed.
def restore_response(hash, body=[])
status = hash.delete('X-Status').to_i
status = hash.delete('x-status').to_i
Rack::Cache::Response.new(status, hash, body)
end

def persist_response(response)
hash = response.headers.to_hash
hash['X-Status'] = response.status.to_s
hash = response.headers.dup
hash['x-status'] = response.status.to_s
hash
end

Expand Down
12 changes: 6 additions & 6 deletions lib/rack/cache/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def option_name(key)

# The number of seconds that a cache entry should be considered
# "fresh" when no explicit freshness information is provided in
# a response. Explicit Cache-Control or Expires headers
# a response. Explicit cache-control or expires headers
# override this value.
#
# Default: 0
Expand All @@ -83,24 +83,24 @@ def option_name(key)
# example, in most cases, it makes sense to prevent cookies from being
# stored in the cache.
#
# Default: ['Set-Cookie']
# Default: ['set-cookie']
option_accessor :ignore_headers

# Set of request headers that trigger "private" cache-control behavior
# on responses that don't explicitly state whether the response is
# public or private via a Cache-Control directive. Applications that use
# public or private via a cache-control directive. Applications that use
# cookies for authorization may need to add the 'Cookie' header to this
# list.
#
# Default: ['Authorization', 'Cookie']
option_accessor :private_headers

# Specifies whether a client can force cache reload by including a
# Cache-Control "no-cache" directive in the request. Disabled by default.
# cache-control "no-cache" directive in the request. Disabled by default.
option_accessor :allow_reload

# Specifies whether a client can force cache revalidate by including a
# Cache-Control "max-age=0" directive in the request. Disabled by default.
# cache-control "max-age=0" directive in the request. Disabled by default.
option_accessor :allow_revalidate

# Specifies whether the underlying entity store's native expiration should
Expand Down Expand Up @@ -148,7 +148,7 @@ def initialize_options(options={})
'rack-cache.metastore' => 'heap:/',
'rack-cache.entitystore' => 'heap:/',
'rack-cache.default_ttl' => 0,
'rack-cache.ignore_headers' => ['Set-Cookie'],
'rack-cache.ignore_headers' => ['set-cookie'],
'rack-cache.private_headers' => ['Authorization', 'Cookie'],
'rack-cache.allow_reload' => false,
'rack-cache.allow_revalidate' => false,
Expand Down
Loading

0 comments on commit 6efa762

Please sign in to comment.