This file is indexed.

/usr/lib/ruby/vendor_ruby/rack/cache/response.rb is in ruby-rack-cache 1.2-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
require 'time'
require 'set'
require 'rack/response'
require 'rack/utils'
require 'rack/cache/cachecontrol'

module Rack::Cache

  # Provides access to the response generated by the downstream application. The
  # +response+, +original_response+, and +entry+ objects exposed by the Core
  # caching engine are instances of this class.
  #
  # Response objects respond to a variety of convenience methods, including
  # those defined in Rack::Response::Helpers, Rack::Cache::Headers,
  # and Rack::Cache::ResponseHeaders.
  #
  # Note that Rack::Cache::Response is not a subclass of Rack::Response and does
  # not perform many of the same initialization and finalization tasks. For
  # example, the body is not slurped during initialization and there are no
  # facilities for generating response output.
  class Response
    include Rack::Response::Helpers

    # Rack response tuple accessors.
    attr_accessor :status, :headers, :body

    # The time when the Response object was instantiated.
    attr_reader :now

    # Create a Response instance given the response status code, header hash,
    # and body.
    def initialize(status, headers, body)
      @status = status.to_i
      @headers = Rack::Utils::HeaderHash.new(headers)
      @body = body
      @now = Time.now
      @headers['Date'] ||= @now.httpdate
    end

    def initialize_copy(other)
      super
      @headers = other.headers.dup
    end

    # Return the status, headers, and body in a three-tuple.
    def to_a
      [status, headers.to_hash, body]
    end

    # 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

    # 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
    # header is present.
    def cache_control
      @cache_control ||= CacheControl.new(headers['Cache-Control'])
    end

    # Set the Cache-Control header to the values specified by the Hash. See
    # the #cache_control method for information on expected Hash structure.
    def cache_control=(value)
      if value.respond_to? :to_hash
        cache_control.clear
        cache_control.merge!(value)
        value = cache_control.to_s
      end

      if value.nil? || value.empty?
        headers.delete('Cache-Control')
      else
        headers['Cache-Control'] = value
      end
    end

    # 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
    # header and the calculated age is less than the freshness lifetime.
    def fresh?
      ttl && ttl > 0
    end

    # Determine if the response is worth caching under any circumstance. Responses
    # marked "private" with an explicit Cache-Control directive are considered
    # uncacheable
    #
    # Responses with neither a freshness lifetime (Expires, max-age) nor cache
    # validator (Last-Modified, ETag) are considered uncacheable.
    def cacheable?
      return false unless CACHEABLE_RESPONSE_CODES.include?(status)
      return false if cache_control.no_store? || cache_control.private?
      validateable? || fresh?
    end

    # Determine if the response includes headers that can be used to validate
    # the response with the origin using a conditional GET request.
    def validateable?
      headers.key?('Last-Modified') || headers.key?('ETag')
    end

    # Mark the response "private", making it ineligible for serving other
    # clients.
    def private=(value)
      value = value ? true : nil
      self.cache_control = cache_control.
        merge('public' => !value, 'private' => value)
    end

    # Indicates that the cache must not serve a stale response in any
    # circumstance without first revalidating with the origin. When present,
    # the TTL of the response should not be overriden to be greater than the
    # value provided by the origin.
    def must_revalidate?
      cache_control.must_revalidate || cache_control.proxy_revalidate
    end

    # Mark the response stale by setting the Age header to be equal to the
    # maximum age of the response.
    def expire!
      headers['Age'] = max_age.to_s if fresh?
    end

    # The date, as specified by the Date header. When no Date header is present,
    # set the Date header to Time.now and return.
    def date
      if date = headers['Date']
        Time.httpdate(date)
      else
        headers['Date'] = now.httpdate unless headers.frozen?
        now
      end
    end

    # The age of the response.
    def age
      (headers['Age'] ||  [(now - date).to_i, 0].max).to_i
    end

    # The number of seconds after the time specified in the response's Date
    # header when the the response should no longer be considered fresh. First
    # check for a s-maxage directive, then a max-age directive, and then fall
    # back on an expires header; return nil when no maximum age can be
    # established.
    def max_age
      cache_control.shared_max_age ||
        cache_control.max_age ||
        (expires && (expires - date))
    end

    # The value of the Expires header as a Time object.
    def expires
      headers['Expires'] && Time.httpdate(headers['Expires'])
    end

    # The number of seconds after which the response should no longer
    # be considered fresh. Sets the Cache-Control max-age directive.
    def max_age=(value)
      self.cache_control = cache_control.merge('max-age' => value.to_s)
    end

    # Like #max_age= but sets the s-maxage directive, which applies only
    # to shared caches.
    def shared_max_age=(value)
      self.cache_control = cache_control.merge('s-maxage' => value.to_s)
    end

    # The response's time-to-live in seconds, or nil when no freshness
    # information is present in the response. When the responses #ttl
    # is <= 0, the response may not be served from cache without first
    # revalidating with the origin.
    def ttl
      max_age - age if max_age
    end

    # Set the response's time-to-live for shared caches to the specified number
    # of seconds. This adjusts the Cache-Control/s-maxage directive.
    def ttl=(seconds)
      self.shared_max_age = age + seconds
    end

    # Set the response's time-to-live for private/client caches. This adjusts
    # the Cache-Control/max-age directive.
    def client_ttl=(seconds)
      self.max_age = age + seconds
    end

    # The String value of the Last-Modified header exactly as it appears
    # in the response (i.e., no date parsing / conversion is performed).
    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

    # Headers that MUST NOT be included with 304 Not Modified responses.
    #
    # http://tools.ietf.org/html/rfc2616#section-10.3.5
    NOT_MODIFIED_OMIT_HEADERS = %w[
      Allow
      Content-Encoding
      Content-Language
      Content-Length
      Content-MD5
      Content-Type
      Last-Modified
    ].to_set

    # Modify the response so that it conforms to the rules defined for
    # '304 Not Modified'. This sets the status, removes the body, and
    # discards any headers that MUST NOT be included in 304 responses.
    #
    # http://tools.ietf.org/html/rfc2616#section-10.3.5
    def not_modified!
      body.close if body.respond_to?(:close)
      self.status = 304
      self.body = []
      NOT_MODIFIED_OMIT_HEADERS.each { |name| headers.delete(name) }
      nil
    end

    # The literal value of the Vary header, or nil when no header is present.
    def vary
      headers['Vary']
    end

    # Does the response include a Vary header?
    def vary?
      ! vary.nil?
    end

    # An array of header names given in the Vary header or an empty
    # array when no Vary header is present.
    def vary_header_names
      return [] unless vary = headers['Vary']
      vary.split(/[\s,]+/)
    end

  end
end