Class: Wrest::Native::Response

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
HttpCodes
Defined in:
lib/wrest/native/response.rb

Overview

Decorates a response providing support for deserialisation.

The following methods are also available (unlisted by rdoc because they’re forwarded to Net::HTTP::Response):

:@Http_response, :code, :message, :body, :Http_version, :[], :content_length, :content_type, :each_header, :each_name, :each_value, :fetch, :get_fields, :key?, :type_params

They behave exactly like their Net::HttpResponse equivalents.

Also provides set of HTTP response code checkers. For instance, the method ok? checks if the response was successful with HTTP code 200. See HttpCodes for a list of all such response checkers.

Direct Known Subclasses

Redirection

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from HttpCodes

#accepted?, #bad_request?, #created?, #forbidden?, #found?, #internal_server_error?, #method_not_allowed?, #moved_permanently?, #no_content?, #not_acceptable?, #not_found?, #not_modified?, #ok?, #see_other?, #temporary_redirect?, #unauthorized?, #unprocessable_entity?

Constructor Details

#initialize(http_response) ⇒ Response

Returns a new instance of Response.



53
54
55
# File 'lib/wrest/native/response.rb', line 53

def initialize(http_response)
  @http_response = http_response
end

Instance Attribute Details

#deserialised_bodyObject

Returns the value of attribute deserialised_body.



29
30
31
# File 'lib/wrest/native/response.rb', line 29

def deserialised_body
  @deserialised_body
end

#http_responseObject (readonly)

Returns the value of attribute http_response.



28
29
30
# File 'lib/wrest/native/response.rb', line 28

def http_response
  @http_response
end

Class Method Details

.new(http_response) ⇒ Object

We’re overriding :new to act as a factory so we can build the appropriate Response instance based on the response code.



46
47
48
49
50
51
# File 'lib/wrest/native/response.rb', line 46

def self.new(http_response)
  code = http_response.code.to_i
  instance = ((300..303).include?(code) || (305..399).include?(code) ? Wrest::Native::Redirection : self).allocate
  instance.send :initialize, http_response
  instance
end

Instance Method Details

#==(other) ⇒ Object

Checks equality between two Wrest::Native::Response objects.



62
63
64
65
66
67
68
# File 'lib/wrest/native/response.rb', line 62

def ==(other)
  return true if equal?(other)
  return false unless other.class == self.class
  return true if these_fields_are_equal(other)

  false
end

#cache_control_headersObject

The values in Cache-Control header as an array.



205
206
207
# File 'lib/wrest/native/response.rb', line 205

def cache_control_headers
  @cache_control_headers ||= recalculate_cache_control_headers
end

#cacheable?Boolean

Returns whether this response is cacheable.

Returns:

  • (Boolean)


117
118
119
120
121
# File 'lib/wrest/native/response.rb', line 117

def cacheable?
  cache_configs_set? &&
    (!max_age.nil? or (expires_not_in_our_past? && expires_not_in_its_past?)) && pragma_nocache_not_set? &&
    vary_header_valid?
end

#can_be_validated?Boolean

Can this response be validated by sending a validation request to the server. The response need to have either Last-Modified or ETag header (or both) for it to be validatable.

Returns:

  • (Boolean)


245
246
247
# File 'lib/wrest/native/response.rb', line 245

def can_be_validated?
  !(last_modified.nil? and headers['etag'].nil?)
end

#code_cacheable?Boolean

:nodoc:

Returns:

  • (Boolean)


124
125
126
# File 'lib/wrest/native/response.rb', line 124

def code_cacheable?
  !code.nil? && [200, 203, 300, 301, 302, 304, 307].include?(code.to_i)
end

#connection_closed?Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/wrest/native/response.rb', line 112

def connection_closed?
  self[Native::StandardHeaders::Connection].downcase == Native::StandardTokens::Close.downcase
end

#current_ageObject

Age of the response calculated according to RFC 2616 13.2.3



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/wrest/native/response.rb', line 188

def current_age
  current_time = Time.now.to_i

  # RFC 2616 13.2.3 Age Calculations. TODO: include response_delay in the calculation as defined in RFC. For this, include original Request with Response.
  date_value = begin
    Utils.datetime_to_i(DateTime.parse(headers['date']))
  rescue StandardError
    current_time
  end
  age_value = headers['age'].to_i || 0

  apparent_age = current_time - date_value

  [apparent_age, age_value].max
end

#deserialise(options = {}) ⇒ Object



75
76
77
78
# File 'lib/wrest/native/response.rb', line 75

def deserialise(options = {})
  @deserialised_body ||= deserialise_using(Wrest::Components::Translators.lookup(@http_response.content_type),
                                           options)
end

#deserialise_using(translator, options = {}) ⇒ Object



84
85
86
# File 'lib/wrest/native/response.rb', line 84

def deserialise_using(translator, options = {})
  translator.deserialise(@http_response, options)
end

#deserialize(options = {}) ⇒ Object



80
81
82
# File 'lib/wrest/native/response.rb', line 80

def deserialize(options = {})
  deserialise(options)
end

#deserialize_using(options = {}) ⇒ Object



88
89
90
# File 'lib/wrest/native/response.rb', line 88

def deserialize_using(options = {})
  deserialise_using(options)
end

#expired?Boolean

Has this response expired? The expiry is calculated from the Max-Age/Expires header.

Returns:

  • (Boolean)


232
233
234
235
236
237
# File 'lib/wrest/native/response.rb', line 232

def expired?
  freshness = freshness_lifetime
  return true if freshness <= 0

  freshness <= current_age
end

#expiresObject

Returns the Expires date from the response headers.



162
163
164
165
166
# File 'lib/wrest/native/response.rb', line 162

def expires
  return @expires if @expires

  @expires = parse_datefield(headers, 'expires')
end

#expires_not_in_its_past?Boolean

Is the Expires of this response earlier than its Date header.

Returns:

  • (Boolean)


178
179
180
181
182
183
184
185
# File 'lib/wrest/native/response.rb', line 178

def expires_not_in_its_past?
  # Invalid header value for Date or Expires means the response is not cacheable
  if expires.nil? || response_date.nil?
    false
  else
    expires > response_date
  end
end

#expires_not_in_our_past?Boolean

Returns whether the Expires header of this response is earlier than current time.

Returns:

  • (Boolean)


169
170
171
172
173
174
175
# File 'lib/wrest/native/response.rb', line 169

def expires_not_in_our_past?
  if expires.nil?
    false
  else
    Utils.datetime_to_i(expires) > Time.now.to_i
  end
end

#follow(_redirect_request_options = {}) ⇒ Object

A null object implementation - invoking this method on a response simply returns the same response unless the response is Redirection (code 3xx), in which case a get is invoked on the url stored in the response headers under the key ‘location’ and the new Response is returned.



108
109
110
# File 'lib/wrest/native/response.rb', line 108

def follow(_redirect_request_options = {})
  self
end

#freshness_lifetimeObject

How long (in seconds) is this response expected to be fresh



217
218
219
# File 'lib/wrest/native/response.rb', line 217

def freshness_lifetime
  @freshness_lifetime ||= recalculate_freshness_lifetime
end

#hashObject

Return the hash of a Wrest::Native::Response object.



71
72
73
# File 'lib/wrest/native/response.rb', line 71

def hash
  [code, message, headers, http_version, body].hash
end

#headersObject

Gives a hash of the response headers. The keys of the hash are case-insensitive.



93
94
95
96
97
98
99
100
101
# File 'lib/wrest/native/response.rb', line 93

def headers
  return @headers if @headers

  nethttp_headers_with_string_values = @http_response.to_hash.transform_values do |old_value|
    old_value.is_a?(Array) ? old_value.join(',') : old_value
  end

  @headers = Wrest::HashWithCaseInsensitiveAccess.new(nethttp_headers_with_string_values)
end

#initialize_copy(source) ⇒ Object



57
58
59
# File 'lib/wrest/native/response.rb', line 57

def initialize_copy(source)
  @headers = source.headers.clone
end

#last_modifiedObject



239
240
241
# File 'lib/wrest/native/response.rb', line 239

def last_modified
  headers['last-modified']
end

#max_ageObject

:nodoc:



134
135
136
137
138
139
140
# File 'lib/wrest/native/response.rb', line 134

def max_age
  return @max_age if @max_age

  max_age = cache_control_headers.grep(/max-age/)

  @max_age = (max_age.first.split('=').last.to_i unless max_age.empty?)
end

#no_cache_flag_not_set?Boolean

Returns:

  • (Boolean)


142
143
144
# File 'lib/wrest/native/response.rb', line 142

def no_cache_flag_not_set?
  !cache_control_headers.include?('no-cache')
end

#no_store_flag_not_set?Boolean

Returns:

  • (Boolean)


146
147
148
# File 'lib/wrest/native/response.rb', line 146

def no_store_flag_not_set?
  !cache_control_headers.include?('no-store')
end

#parse_datefield(hash, key) ⇒ Object

:nodoc: helper function. Used to parse date fields. this function is used and tested by the expires and response_date methods



252
253
254
255
256
257
258
259
260
261
# File 'lib/wrest/native/response.rb', line 252

def parse_datefield(hash, key)
  return unless hash[key]

  # Can't trust external input. Do not crash even if invalid dates are passed.
  begin
    DateTime.parse(hash[key].to_s)
  rescue ArgumentError
    nil
  end
end

#pragma_nocache_not_set?Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/wrest/native/response.rb', line 150

def pragma_nocache_not_set?
  headers['pragma'].nil? || (!headers['pragma'].include? 'no-cache')
end

#recalculate_cache_control_headersObject

:nodoc:



210
211
212
213
214
# File 'lib/wrest/native/response.rb', line 210

def recalculate_cache_control_headers
  headers['cache-control'].split(',').collect(&:strip)
rescue StandardError
  []
end

#recalculate_freshness_lifetimeObject

:nodoc:



222
223
224
225
226
227
228
229
# File 'lib/wrest/native/response.rb', line 222

def recalculate_freshness_lifetime
  return max_age if max_age

  response_date = Utils.datetime_to_i(DateTime.parse(headers['date']))
  expires_date = Utils.datetime_to_i(DateTime.parse(headers['expires']))

  (expires_date - response_date)
end

#response_dateObject

Returns the Date from the response headers.



155
156
157
158
159
# File 'lib/wrest/native/response.rb', line 155

def response_date
  return @response_date if @response_date

  @response_date = parse_datefield(headers, 'date')
end

#vary_header_valid?Boolean

:nodoc:

Returns:

  • (Boolean)


129
130
131
# File 'lib/wrest/native/response.rb', line 129

def vary_header_valid?
  headers['vary'] != '*'
end