Permalink
Browse files

Remove Request#headers and EnvironmentHeaders util class

  • Loading branch information...
1 parent d3c73c7 commit 362aed3a2352603d9e4abc1b703f0ca09af6a192 @rtomayko rtomayko committed Mar 8, 2009
@@ -9,10 +9,6 @@ module Rack::Cache
class Context
include Rack::Cache::Options
- # The request exactly as received. The object is an instance of
- # Rack::Cache::Request. This object cannot be modified.
- attr_reader :request
-
# Array of trace Symbols
attr_reader :trace
@@ -59,7 +55,34 @@ def call(env)
def call!(env)
@trace = []
@env = @default_options.merge(env)
- dispatch
+ @request = Request.new(@env.dup.freeze)
+
+ response =
+ if @request.get? || @request.head?
+ if !@env['HTTP_EXPECT']
+ lookup
+ else
+ pass
+ end
+ else
+ invalidate
+ end
+
+ # log trace and set X-Rack-Cache tracing header
+ trace = @trace.join(', ')
+ response.headers['X-Rack-Cache'] = trace
+
+ # write log message to rack.errors
+ if verbose?
+ message = "cache: [%s %s] %s\n" %
+ [@request.request_method, @request.fullpath, trace]
+ @env['rack.errors'].write(message)
+ end
+
+ # tidy up response a bit
+ response.not_modified! if not_modified?(response)
+ response.body = [] if @request.head?
+ response.to_a
end
private
@@ -79,58 +102,21 @@ def private_request?
# Determine if the #response validators (ETag, Last-Modified) matches
# a conditional value specified in #request.
def not_modified?(response)
- response.etag_matches?(request.if_none_match) ||
- response.last_modified_at?(request.if_modified_since)
+ response.etag_matches?(@request.env['HTTP_IF_NONE_MATCH']) ||
+ response.last_modified_at?(@request.env['HTTP_IF_MODIFIED_SINCE'])
end
# Whether the cache entry is "fresh enough" to satisfy the request.
def fresh_enough?(entry)
if entry.fresh?
- if max_age = request.cache_control.max_age
+ if max_age = @request.cache_control.max_age
max_age > 0 && max_age >= entry.age
else
true
end
end
end
- # Called at the beginning of request processing, after the complete
- # request has been fully received. Its purpose is to decide whether or
- # not to serve the request from cache and will transition to the either
- # the #pass or #lookup states.
- def dispatch
- # Store the request env exactly as we received it. Freeze the env to
- # ensure no changes are made.
- @request = Request.new(@env.dup.freeze)
-
- response =
- if @request.get? || @request.head?
- if !@env['HTTP_EXPECT']
- lookup
- else
- pass
- end
- else
- invalidate
- end
-
- # log trace and set X-Rack-Cache tracing header
- trace = @trace.join(', ')
- response.headers['X-Rack-Cache'] = trace
-
- # write log message to rack.errors
- if verbose?
- message = "cache: [%s %s] %s\n" %
- [@request.request_method, @request.fullpath, trace]
- @env['rack.errors'].write(message)
- end
-
- # tidy up response a bit
- response.not_modified! if not_modified?(response)
- response.body = [] if @request.head?
- response.to_a
- end
-
# Delegate the request to the backend and create the response.
def forward
Response.new(*backend.call(@env))
@@ -157,10 +143,10 @@ def invalidate
# stale, attempt to #validate the entry with the backend using conditional
# GET. When no matching cache entry is found, trigger #miss processing.
def lookup
- if request.cache_control.no_cache?
+ if @request.cache_control.no_cache?
record :reload
fetch
- elsif entry = metastore.lookup(request, entitystore)
+ elsif entry = metastore.lookup(@request, entitystore)
if fresh_enough?(entry)
record :fresh
entry.headers['Age'] = entry.age.to_s
@@ -201,6 +187,7 @@ def validate(entry)
record :invalid
backend_response
end
+
store(response) if response.cacheable?
response
@@ -229,6 +216,7 @@ def fetch
# default ttl assigment.
response.ttl = default_ttl
end
+
store(response) if response.cacheable?
response
@@ -237,9 +225,8 @@ def fetch
# Write the response to the cache.
def store(response)
record :store
- metastore.store(request, response, entitystore)
+ metastore.store(@request, response, entitystore)
response.headers['Age'] = response.age.to_s
- nil
end
end
end
@@ -1,12 +1,22 @@
require 'set'
-require 'rack/utils/environment_headers'
module Rack::Cache
- # Generic HTTP header helper methods. Provides access to headers that can be
- # included in requests and responses. This can be mixed into any object that
- # responds to #headers by returning a Hash.
+ # HTTP response header helper methods.
+ module ResponseHeaders
+ # Status codes of responses that MAY be stored by a cache or used in reply
+ # to a subsequent request.
+ #
+ # http://tools.ietf.org/html/rfc2616#section-13.4
+ CACHEABLE_RESPONSE_CODES = [
+ 200, # OK
+ 203, # Non-Authoritative Information
+ 300, # Multiple Choices
+ 301, # Moved Permanently
+ 302, # Found
+ 404, # Not Found
+ 410 # Gone
+ ].to_set
- module Headers
# A Hash of name=value pairs that correspond to the Cache-Control header.
# Valueless parameters (e.g., must-revalidate, no-store) have a Hash value
# of true. This method always returns a Hash, empty if no Cache-Control
@@ -31,53 +41,6 @@ def cache_control=(value)
end
end
- # The literal value of the ETag HTTP header or nil if no ETag is specified.
- def etag
- headers['ETag']
- end
- end
-
- # HTTP request header helpers. When included in Rack::Cache::Request, headers
- # may be accessed by their standard RFC 2616 names using the #headers Hash.
- module RequestHeaders
- include Rack::Cache::Headers
-
- # A Hash-like object providing access to HTTP request headers.
- def headers
- @headers ||= Rack::Utils::EnvironmentHeaders.new(env)
- end
-
- # The literal value of the If-Modified-Since request header or nil when
- # no If-Modified-Since header is present.
- def if_modified_since
- headers['If-Modified-Since']
- end
-
- # The literal value of the If-None-Match request header or nil when
- # no If-None-Match header is present.
- def if_none_match
- headers['If-None-Match']
- end
- end
-
- # HTTP response header helper methods.
- module ResponseHeaders
- include Rack::Cache::Headers
-
- # Status codes of responses that MAY be stored by a cache or used in reply
- # to a subsequent request.
- #
- # http://tools.ietf.org/html/rfc2616#section-13.4
- CACHEABLE_RESPONSE_CODES = [
- 200, # OK
- 203, # Non-Authoritative Information
- 300, # Multiple Choices
- 301, # Moved Permanently
- 302, # Found
- 404, # Not Found
- 410 # Gone
- ].to_set
-
# Determine if the response is "fresh". Fresh responses may be served from
# cache without any interaction with the origin. A response is considered
# fresh when it includes a Cache-Control/max-age indicator or Expiration
@@ -190,6 +153,11 @@ def last_modified
headers['Last-Modified']
end
+ # The literal value of ETag HTTP header or nil if no ETag is specified.
+ def etag
+ headers['ETag']
+ end
+
# Determine if the response was last modified at the time provided.
# time_value is the exact string provided in an origin response's
# Last-Modified header.
@@ -1,6 +1,6 @@
require 'rack/request'
require 'rack/cache/headers'
-require 'rack/utils/environment_headers'
+require 'rack/cache/cachecontrol'
module Rack::Cache
@@ -11,14 +11,17 @@ module Rack::Cache
# everything defined by Rack::Request as well as the Headers and
# RequestHeaders modules.
class Request < Rack::Request
- include Rack::Cache::RequestHeaders
-
# The HTTP request method. This is the standard implementation of this
# method but is respecified here due to libraries that attempt to modify
# the behavior to respect POST tunnel method specifiers. We always want
# the real request method.
def request_method
@env['REQUEST_METHOD']
end
+
+ # A CacheControl instance based on the request's Cache-Control header.
+ def cache_control
+ @cache_control ||= CacheControl.new(env['HTTP_CACHE_CONTROL'])
+ end
end
end
@@ -39,7 +39,7 @@ def initialize(status, headers, body)
@headers = Rack::Utils::HeaderHash.new(headers)
@body = body
@now = Time.now
- @headers['Date'] ||= now.httpdate
+ @headers['Date'] ||= @now.httpdate
end
def initialize_copy(other)
@@ -1,78 +0,0 @@
-require 'rack/utils'
-
-module Rack::Utils #:nodoc:
- # A facade over a Rack Environment Hash that gives access to headers
- # using their normal RFC 2616 names.
-
- class EnvironmentHeaders
- include Enumerable
-
- # Create the facade over the given Rack Environment Hash.
- def initialize(env)
- @env = env
- end
-
- # Return the value of the specified header. The +header_name+ should
- # be as specified by RFC 2616 (e.g., "Content-Type", "Accept", etc.)
- def [](header_name)
- @env[env_name(header_name)]
- end
-
- # Set the value of the specified header. The +header_name+ should
- # be as specified by RFC 2616 (e.g., "Content-Type", "Accept", etc.)
- def []=(header_name, value)
- @env[env_name(header_name)] = value
- end
-
- # Determine if the underlying Rack Environment includes a header
- # of the given name.
- def include?(header_name)
- @env.include?(env_name(header_name))
- end
-
- # Iterate over all headers yielding a (name, value) tuple to the
- # block. Rack Environment keys that do not map to an header are not
- # included.
- def each
- @env.each do |key,value|
- next unless key =~ /^(HTTP_|CONTENT_)/
- yield header_name(key), value
- end
- end
-
- # Delete the entry in the underlying Rack Environment that corresponds
- # to the given RFC 2616 header name.
- def delete(header_name)
- @env.delete(env_name(header_name))
- end
-
- # Return the underlying Rack Environment Hash.
- def to_env
- @env
- end
-
- alias_method :to_hash, :to_env
-
- private
-
- # Return the Rack Environment key for the given RFC 2616 header name.
- def env_name(header_name)
- case header_name = header_name.upcase
- when 'CONTENT-TYPE' then 'CONTENT_TYPE'
- when 'CONTENT-LENGTH' then 'CONTENT_LENGTH'
- else "HTTP_#{header_name.tr('-', '_')}"
- end
- end
-
- # Return the RFC 2616 header name for the given Rack Environment key.
- def header_name(env_name)
- env_name.
- sub(/^HTTP_/, '').
- downcase.
- capitalize.
- gsub(/_(.)/) { '-' + $1.upcase }
- end
-
- end
-
-end
Oops, something went wrong.

0 comments on commit 362aed3

Please sign in to comment.