class Faraday::HttpCache::Response

Internal: A class to represent a response from a Faraday request. It decorates the response hash into a smarter object that queries the response headers and status informations about how the caching middleware should handle this specific response.

Constants

CACHEABLE_STATUS_CODES

Internal: List of status codes that can be cached:

  • 200 - ‘OK’

  • 203 - ‘Non-Authoritative Information’

  • 300 - ‘Multiple Choices’

  • 301 - ‘Moved Permanently’

  • 302 - ‘Found’

  • 404 - ‘Not Found’

  • 410 - ‘Gone’

Attributes

etag[R]

Internal: Gets the ‘ETag’ header from the headers Hash.

last_modified[R]

Internal: Gets the ‘Last-Modified’ header from the headers Hash.

payload[R]

Internal: Gets the actual response Hash (status, headers and body).

Public Class Methods

new(payload = {}) click to toggle source

Internal: Initialize a new Response with the response payload from a Faraday request.

payload - the response Hash returned by a Faraday request.

:status - the status code from the response.
:response_headers - a 'Hash' like object with the headers.
:body - the response body.
# File lib/faraday/http_cache/response.rb, line 39
def initialize(payload = {})
  @now = Time.now
  @payload = payload
  wrap_headers!
  ensure_date_header!

  @last_modified = headers['Last-Modified']
  @etag = headers['ETag']
end

Public Instance Methods

age() click to toggle source

Internal: Gets the response age in seconds.

Returns the ‘Age’ header if present, or subtracts the response ‘date’ from the current time.

# File lib/faraday/http_cache/response.rb, line 93
def age
  (headers['Age'] || (@now - date)).to_i
end
cacheable_in_private_cache?() click to toggle source

Internal: Checks if the response can be cached by the client when the client is acting as a private cache per RFC 2616. This is validated by the ‘Cache-Control’ directives, the response status code and it’s freshness or validation status.

Returns false if the ‘Cache-Control’ says that we can’t store the response, or if isn’t fresh or it can’t be revalidated with the origin server. Otherwise, returns true.

# File lib/faraday/http_cache/response.rb, line 85
def cacheable_in_private_cache?
  cacheable?(false)
end
cacheable_in_shared_cache?() click to toggle source

Internal: Checks if the response can be cached by the client when the client is acting as a shared cache per RFC 2616. This is validated by the ‘Cache-Control’ directives, the response status code and it’s freshness or validation status.

Returns false if the ‘Cache-Control’ says that we can’t store the response, or it can be stored in private caches only, or if isn’t fresh or it can’t be revalidated with the origin server. Otherwise, returns true.

# File lib/faraday/http_cache/response.rb, line 73
def cacheable_in_shared_cache?
  cacheable?(true)
end
date() click to toggle source

Internal: Parses the ‘Date’ header back into a Time instance.

Returns the Time object.

# File lib/faraday/http_cache/response.rb, line 108
def date
  Time.httpdate(headers['Date'])
end
fresh?() click to toggle source

Internal: Checks the response freshness based on expiration headers. The calculated ‘ttl’ should be present and bigger than 0.

Returns true if the response is fresh, otherwise false.

# File lib/faraday/http_cache/response.rb, line 53
def fresh?
  !cache_control.no_cache? && ttl && ttl > 0
end
max_age() click to toggle source

Internal: Gets the response max age. The max age is extracted from one of the following:

  • The shared max age directive from the ‘Cache-Control’ header;

  • The max age directive from the ‘Cache-Control’ header;

  • The difference between the ‘Expires’ header and the response date.

Returns the max age value in seconds or nil if all options above fails.

# File lib/faraday/http_cache/response.rb, line 120
def max_age
  cache_control.shared_max_age ||
    cache_control.max_age ||
    (expires && (expires - @now))
end
not_modified?() click to toggle source

Internal: Checks if the Response returned a ‘Not Modified’ status.

Returns true if the response status code is 304.

# File lib/faraday/http_cache/response.rb, line 60
def not_modified?
  @payload[:status] == 304
end
serializable_hash() click to toggle source

Internal: Exposes a representation of the current payload that we can serialize and cache properly.

Returns a ‘Hash’.

# File lib/faraday/http_cache/response.rb, line 139
def serializable_hash
  prepare_to_cache

  {
    status: @payload[:status],
    body: @payload[:body],
    response_headers: @payload[:response_headers],
    reason_phrase: @payload[:reason_phrase]
  }
end
to_response(env) click to toggle source

Internal: Creates a new ‘Faraday::Response’, merging the stored response with the supplied ‘env’ object.

Returns a new instance of a ‘Faraday::Response’ with the payload.

# File lib/faraday/http_cache/response.rb, line 130
def to_response(env)
  env.update(@payload)
  Faraday::Response.new(env)
end
ttl() click to toggle source

Internal: Calculates the ‘Time to live’ left on the Response.

Returns the remaining seconds for the response, or nil the ‘max_age’ isn’t present.

# File lib/faraday/http_cache/response.rb, line 101
def ttl
  max_age - age if max_age
end

Private Instance Methods

cache_control() click to toggle source

Internal: Gets the ‘CacheControl’ object.

# File lib/faraday/http_cache/response.rb, line 185
def cache_control
  @cache_control ||= CacheControl.new(headers['Cache-Control'])
end
cacheable?(shared_cache) click to toggle source

Internal: The logic behind cacheable_in_private_cache? and cacheable_in_shared_cache? The logic is the same except for the treatment of the private Cache-Control directive.

# File lib/faraday/http_cache/response.rb, line 163
def cacheable?(shared_cache)
  return false if (cache_control.private? && shared_cache) || cache_control.no_store?

  cacheable_status_code? && (validateable? || fresh?)
end
cacheable_status_code?() click to toggle source

Internal: Validates the response status against the ‘CACHEABLE_STATUS_CODES’ constant.

Returns true if the constant includes the response status code.

# File lib/faraday/http_cache/response.rb, line 173
def cacheable_status_code?
  CACHEABLE_STATUS_CODES.include?(@payload[:status])
end
ensure_date_header!() click to toggle source

Internal: Try to parse the Date header, if it fails set it to @now.

Returns nothing.

# File lib/faraday/http_cache/response.rb, line 207
def ensure_date_header!
  date
rescue StandardError
  headers['Date'] = @now.httpdate
end
expires() click to toggle source

Internal: Gets the ‘Expires’ in a Time object.

Returns the Time object, or nil if the header isn’t present or isn’t RFC 2616 compliant.

# File lib/faraday/http_cache/response.rb, line 180
def expires
  @expires ||= headers['Expires'] && Time.httpdate(headers['Expires']) rescue nil # rubocop:disable Style/RescueModifier
end
headers() click to toggle source

Internal: Gets the headers ‘Hash’ from the payload.

# File lib/faraday/http_cache/response.rb, line 214
def headers
  @payload[:response_headers]
end
prepare_to_cache() click to toggle source

Internal: Prepares the response headers to be cached.

It removes the ‘Age’ header if present to allow cached responses to continue aging while cached. It also normalizes the ‘max-age’ related headers if the ‘Age’ header is provided to ensure accuracy once the ‘Age’ header is removed.

Returns nothing.

# File lib/faraday/http_cache/response.rb, line 226
def prepare_to_cache
  if headers.key? 'Age'
    cache_control.normalize_max_ages(headers['Age'].to_i)
    headers.delete 'Age'
    headers['Cache-Control'] = cache_control.to_s
  end
end
validateable?() click to toggle source

Internal: Checks if this response can be revalidated.

Returns true if the ‘headers’ contains a ‘Last-Modified’ or an ‘ETag’ entry.

# File lib/faraday/http_cache/response.rb, line 156
def validateable?
  headers.key?('Last-Modified') || headers.key?('ETag')
end
wrap_headers!() click to toggle source

Internal: Converts the headers ‘Hash’ into ‘Faraday::Utils::Headers’. Faraday actually uses a Hash subclass, ‘Faraday::Utils::Headers` to store the headers hash. When retrieving a serialized response, the headers object is decoded as a ’Hash’ instead of the actual ‘Faraday::Utils::Headers’ object, so we need to ensure that the ‘response_headers’ is always a ‘Headers’ instead of a plain ‘Hash’.

Returns nothing.

# File lib/faraday/http_cache/response.rb, line 197
def wrap_headers!
  headers = @payload[:response_headers]

  @payload[:response_headers] = Faraday::Utils::Headers.new
  @payload[:response_headers].update(headers) if headers
end