wrest 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG +3 -0
  3. data/LICENCE +1 -1
  4. data/README.md +29 -28
  5. data/bin/wrest +2 -1
  6. data/bin/wrest_shell.rb +10 -8
  7. data/lib/wrest/async_request/event_machine_backend.rb +3 -1
  8. data/lib/wrest/async_request/thread_backend.rb +5 -2
  9. data/lib/wrest/async_request/thread_pool.rb +4 -2
  10. data/lib/wrest/async_request.rb +7 -6
  11. data/lib/wrest/cache_proxy.rb +39 -28
  12. data/lib/wrest/caching/memcached.rb +21 -18
  13. data/lib/wrest/caching/redis.rb +22 -22
  14. data/lib/wrest/caching.rb +16 -14
  15. data/lib/wrest/callback.rb +19 -16
  16. data/lib/wrest/components/container/alias_accessors.rb +51 -47
  17. data/lib/wrest/components/container/typecaster.rb +146 -96
  18. data/lib/wrest/components/container.rb +171 -152
  19. data/lib/wrest/components/mutators/base.rb +43 -34
  20. data/lib/wrest/components/mutators/camel_to_snake_case.rb +7 -3
  21. data/lib/wrest/components/mutators/{xml_mini_type_caster.rb → xml_type_caster.rb} +29 -16
  22. data/lib/wrest/components/mutators.rb +21 -19
  23. data/lib/wrest/components/translators/content_types.rb +20 -16
  24. data/lib/wrest/components/translators/json.rb +19 -16
  25. data/lib/wrest/components/translators/txt.rb +19 -15
  26. data/lib/wrest/components/translators/xml/conversions.rb +56 -0
  27. data/lib/wrest/components/translators/xml.rb +60 -18
  28. data/lib/wrest/components/translators.rb +7 -6
  29. data/lib/wrest/components.rb +11 -8
  30. data/lib/wrest/core_ext/hash/conversions.rb +10 -10
  31. data/lib/wrest/core_ext/hash.rb +4 -2
  32. data/lib/wrest/core_ext/string/conversions.rb +14 -13
  33. data/lib/wrest/core_ext/string.rb +5 -3
  34. data/lib/wrest/exceptions.rb +4 -2
  35. data/lib/wrest/hash_with_case_insensitive_access.rb +8 -8
  36. data/lib/wrest/hash_with_indifferent_access.rb +442 -0
  37. data/lib/wrest/http_codes.rb +20 -19
  38. data/lib/wrest/http_shared/headers.rb +2 -0
  39. data/lib/wrest/http_shared/standard_headers.rb +2 -2
  40. data/lib/wrest/http_shared/standard_tokens.rb +8 -6
  41. data/lib/wrest/http_shared.rb +5 -3
  42. data/lib/wrest/multipart.rb +20 -11
  43. data/lib/wrest/native/connection_factory.rb +15 -11
  44. data/lib/wrest/native/delete.rb +15 -11
  45. data/lib/wrest/native/get.rb +60 -56
  46. data/lib/wrest/native/options.rb +15 -11
  47. data/lib/wrest/native/patch.rb +16 -12
  48. data/lib/wrest/native/post.rb +15 -11
  49. data/lib/wrest/native/post_multipart.rb +22 -18
  50. data/lib/wrest/native/put.rb +16 -12
  51. data/lib/wrest/native/put_multipart.rb +22 -18
  52. data/lib/wrest/native/redirection.rb +13 -12
  53. data/lib/wrest/native/request.rb +144 -108
  54. data/lib/wrest/native/response.rb +87 -78
  55. data/lib/wrest/native/session.rb +49 -40
  56. data/lib/wrest/native.rb +14 -12
  57. data/lib/wrest/test/request_patches.rb +10 -3
  58. data/lib/wrest/test.rb +3 -1
  59. data/lib/wrest/uri/builders.rb +14 -12
  60. data/lib/wrest/uri.rb +70 -52
  61. data/lib/wrest/uri_template.rb +11 -7
  62. data/lib/wrest/utils.rb +129 -0
  63. data/lib/wrest/version.rb +3 -1
  64. data/lib/wrest.rb +31 -33
  65. data/lib/wrest_no_ext.rb +2 -0
  66. metadata +98 -48
  67. data/lib/wrest/components/mutators/xml_simple_type_caster.rb +0 -37
  68. data/lib/wrest/xml_mini/jdom/xpath_filter.rb +0 -17
  69. data/lib/wrest/xml_mini/jdom.rb +0 -6
  70. data/lib/wrest/xml_mini/libxml/xpath_filter.rb +0 -12
  71. data/lib/wrest/xml_mini/libxml.rb +0 -8
  72. data/lib/wrest/xml_mini/nokogiri/xpath_filter.rb +0 -15
  73. data/lib/wrest/xml_mini/nokogiri.rb +0 -7
  74. data/lib/wrest/xml_mini/rexml/xpath_filter.rb +0 -15
  75. data/lib/wrest/xml_mini/rexml.rb +0 -8
  76. data/lib/wrest/xml_mini.rb +0 -8
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright 2009 Sidu Ponnappa
2
4
 
3
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -7,119 +9,153 @@
7
9
  # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
10
  # See the License for the specific language governing permissions and limitations under the License.
9
11
 
10
- module Wrest::Native
11
- # This represents a HTTP request. Typically you will never need to instantiate
12
- # one of these yourself - you can use one of the more conveient APIs via Wrest::Uri
13
- # or Wrest::Native::Get etc. instead.
14
- class Request
15
- attr_reader :http_request, :uri, :body, :headers, :username, :password, :follow_redirects,
16
- :follow_redirects_limit, :follow_redirects_count, :timeout, :connection, :parameters,
17
- :cache_store, :verify_mode, :options, :ca_path
18
- # Valid tuples for the options are:
19
- # :username => String, defaults to nil
20
- # :password => String, defaults to nil
21
- # :follow_redirects => Boolean, defaults to true for Get, false for anything else
22
- # :follow_redirects_limit => Integer, defaults to 5. This is the number of redirects
23
- # that Wrest will automatically follow before raising an
24
- # Wrest::Exceptions::AutoRedirectLimitExceeded exception.
25
- # For example, if you set this to 1, the very first redirect
26
- # will raise the exception.
27
- # :follow_redirects_count => Integer, defaults to 0. This is a count of the hops made to
28
- # get to this request and increases by one for every redirect
29
- # until the follow_redirects_limit is hit. You should never set
30
- # this option yourself.
31
- # :timeout => The period, in seconds, after which a Timeout::Error is raised
32
- # in the event of a connection failing to open. Defaulted to 60 by Uri#create_connection.
33
- # :connection => The HTTP Connection object to use. This is how a keep-alive connection can be
34
- # used for multiple requests.
35
- # :cache_store => The object which should be used as cache store for cacheable responses. If not supplied, caching will be disabled.
36
- # :callback => A Hash whose keys are the response codes (or Range of response codes),
37
- # and the values are the callback functions to be executed.
38
- # eg: { <response code> => lambda { |response| some_operation } }
39
- # The following options are Net::HTTP specific config options
40
- # :detailed_http_logging => nil/$stdout/$stderr or File/Logger/IO object. Defaults to nil (recommended).
41
- # *WARNING* : detailed_http_logging causes a serious security hole. Never use it in production code.
42
- # :verify_mode => The verification mode to be used for Net::HTTP https connections. Defaults to OpenSSL::SSL::VERIFY_PEER
43
- # :ca_path => The path to the certificates
44
- def initialize(wrest_uri, http_request_klass, parameters = {}, body = nil, headers = {}, options = {})
45
- @uri = wrest_uri
46
- @headers = headers.stringify_keys
47
- @parameters = parameters
48
- @body = body
49
- @options = options.clone
50
- @username = @options[:username]
51
- @password = @options[:password]
52
- @follow_redirects = (@options[:follow_redirects] ||= false)
53
- @follow_redirects_count = (@options[:follow_redirects_count] ||= 0)
54
- @follow_redirects_limit = (@options[:follow_redirects_limit] ||= 5)
55
- @timeout = @options[:timeout]
56
- @connection = @options[:connection]
57
- @http_request = self.build_request(http_request_klass, @uri, @parameters, @headers)
58
- @cache_store = @options[:cache_store]
59
- @verify_mode = @options[:verify_mode]
60
- @ca_path = @options[:ca_path]
61
- @detailed_http_logging = options[:detailed_http_logging]
62
- @callback = @options[:callback] || Wrest::Callback.new({})
63
- @callback = @callback.merge(Wrest::Callback.new(@options[:callback_block] || {}))
64
- end
12
+ module Wrest
13
+ module Native
14
+ # This represents a HTTP request. Typically you will never need to instantiate
15
+ # one of these yourself - you can use one of the more conveient APIs via Wrest::Uri
16
+ # or Wrest::Native::Get etc. instead.
17
+ class Request
18
+ attr_reader :http_request, :uri, :body, :headers, :username, :password, :follow_redirects,
19
+ :follow_redirects_limit, :follow_redirects_count, :timeout, :connection, :parameters,
20
+ :cache_store, :verify_mode, :options, :ca_path
65
21
 
66
- # Makes a request, runs the appropriate callback if any and
67
- # returns a Wrest::Native::Response.
68
- #
69
- # Data about the request is and logged to Wrest.logger
70
- # The log entry contains the following information:
71
- #
72
- # <- indicates a request
73
- # -> indicates a response
74
- #
75
- # The type of request is mentioned in caps, followed by a hash
76
- # uniquely identifying a particular request/response pair.
77
- # In a multi-process or multi-threaded scenario, this can be used
78
- # to identify request-response pairs.
79
- #
80
- # The request hash is followed by a connection hash; requests using the
81
- # same connection (effectively a keep-alive connection) will have the
82
- # same connection hash.
83
- #
84
- # Passing nil for either username or password will skip HTTP authentication
85
- #
86
- # This is followed by the response code, the payload size and the time taken.
87
- def invoke
88
- response = nil
89
- @connection ||= @uri.create_connection(:timeout => timeout, :verify_mode => verify_mode, :ca_path => ca_path)
90
- @connection.set_debug_output @detailed_http_logging
91
- http_request.basic_auth username, password unless username.nil? || password.nil?
92
-
93
- prefix = "#{http_request.method} #{self.hash} #{@connection.hash} #{Thread.current.object_id}"
94
-
95
- Wrest.logger.debug "<- (#{prefix}) #{@uri.protocol}://#{@uri.host}:#{@uri.port}#{@http_request.path}"
96
- Wrest.logger.debug "<- Body: #{@body}"
97
- time = Benchmark.realtime { response = Wrest::Native::Response.new( do_request ) }
98
-
99
- execute_callback_if_any(response)
100
-
101
- @follow_redirects ? response.follow(@options) : response
102
- rescue Timeout::Error => e
103
- raise Wrest::Exceptions::Timeout.new(e)
104
- end
22
+ # Valid tuples for the options are:
23
+ # :username => String, defaults to nil
24
+ # :password => String, defaults to nil
25
+ # :follow_redirects => Boolean, defaults to true for Get, false for anything else
26
+ # :follow_redirects_limit => Integer, defaults to 5. This is the number of redirects
27
+ # that Wrest will automatically follow before raising an
28
+ # Wrest::Exceptions::AutoRedirectLimitExceeded exception.
29
+ # For example, if you set this to 1, the very first redirect
30
+ # will raise the exception.
31
+ # :follow_redirects_count => Integer, defaults to 0. This is a count of the hops made to
32
+ # get to this request and increases by one for every redirect
33
+ # until the follow_redirects_limit is hit. You should never set
34
+ # this option yourself.
35
+ # :timeout => The period, in seconds, after which a Timeout::Error is raised
36
+ # in the event of a connection failing to open. Defaulted to 60 by Uri#create_connection.
37
+ # :connection => The HTTP Connection object to use. This is how a keep-alive connection can be
38
+ # used for multiple requests.
39
+ # :cache_store => The object which should be used as cache store for cacheable responses. If not supplied, caching will be disabled.
40
+ # :callback => A Hash whose keys are the response codes (or Range of response codes),
41
+ # and the values are the callback functions to be executed.
42
+ # eg: { <response code> => lambda { |response| some_operation } }
43
+ # The following options are Net::HTTP specific config options
44
+ # :detailed_http_logging => nil/$stdout/$stderr or File/Logger/IO object. Defaults to nil (recommended).
45
+ # *WARNING* : detailed_http_logging causes a serious security hole. Never use it in production code.
46
+ # :verify_mode => The verification mode to be used for Net::HTTP https connections. Defaults to OpenSSL::SSL::VERIFY_PEER
47
+ # :ca_path => The path to the certificates
48
+ def initialize(wrest_uri, http_request_klass, parameters = {}, body = nil, headers = {}, options = {}) # rubocop:disable Metrics/ParameterLists
49
+ setup_request_state!(body, headers, parameters, wrest_uri)
50
+ setup_options_state!(options)
51
+ @detailed_http_logging = options[:detailed_http_logging]
52
+ @follow_redirects = (@options[:follow_redirects] ||= false)
53
+ @follow_redirects_count = (@options[:follow_redirects_count] ||= 0)
54
+ @follow_redirects_limit = (@options[:follow_redirects_limit] ||= 5)
55
+ @callback = @options[:callback] || Wrest::Callback.new({})
56
+ @callback = @callback.merge(Wrest::Callback.new(@options[:callback_block] || {}))
57
+ @http_request = build_request(http_request_klass, @uri, @parameters, @headers)
58
+ end
59
+
60
+ # Makes a request, runs the appropriate callback if any and
61
+ # returns a Wrest::Native::Response.
62
+ #
63
+ # Data about the request is and logged to Wrest.logger
64
+ # The log entry contains the following information:
65
+ #
66
+ # <- indicates a request
67
+ # -> indicates a response
68
+ #
69
+ # The type of request is mentioned in caps, followed by a hash
70
+ # uniquely identifying a particular request/response pair.
71
+ # In a multi-process or multi-threaded scenario, this can be used
72
+ # to identify request-response pairs.
73
+ #
74
+ # The request hash is followed by a connection hash; requests using the
75
+ # same connection (effectively a keep-alive connection) will have the
76
+ # same connection hash.
77
+ #
78
+ # Passing nil for either username or password will skip HTTP authentication
79
+ #
80
+ # This is followed by the response code, the payload size and the time taken.
81
+ def invoke
82
+ response = nil
83
+ setup_connection!
84
+
85
+ response = execute_request(response)
86
+
87
+ execute_callback_if_any(response)
105
88
 
106
- #:nodoc:
107
- def build_request(request_klass, uri, parameters, headers)
108
- if(!uri.query.empty?)
109
- request_klass.new(parameters.empty? ? "#{uri.uri_path}?#{uri.query}" : "#{uri.uri_path}?#{uri.query}&#{parameters.to_query}", headers)
110
- else
111
- request_klass.new(parameters.empty? ? "#{uri.uri_path}" : "#{uri.uri_path}?#{parameters.to_query}", headers)
89
+ @follow_redirects ? response.follow(@options) : response
90
+ rescue Timeout::Error => e
91
+ raise Wrest::Exceptions::Timeout, e
112
92
  end
113
- end
114
93
 
115
- #:nodoc:
116
- def do_request
117
- @connection.request(@http_request, @body)
118
- end
94
+ # :nodoc:
95
+ def build_request(request_klass, uri, parameters, headers)
96
+ if uri.query.empty?
97
+ request_klass.new(parameters.empty? ? uri.uri_path.to_s : "#{uri.uri_path}?#{Utils.hash_to_param(parameters)}", headers)
98
+ else
99
+ request_klass.new(
100
+ parameters.empty? ? "#{uri.uri_path}?#{uri.query}" : "#{uri.uri_path}?#{uri.query}&#{Utils.hash_to_param(parameters)}", headers
101
+ )
102
+ end
103
+ end
104
+
105
+ # :nodoc:
106
+ def do_request
107
+ @connection.request(@http_request, @body)
108
+ end
109
+
110
+ # :nodoc:
111
+ def execute_callback_if_any(actual_response)
112
+ @callback.execute(actual_response)
113
+ end
119
114
 
120
- #:nodoc:
121
- def execute_callback_if_any(actual_response)
122
- @callback.execute(actual_response)
115
+ private
116
+
117
+ def setup_connection!
118
+ @connection ||= @uri.create_connection(timeout: timeout, verify_mode: verify_mode, ca_path: ca_path)
119
+ @connection.set_debug_output @detailed_http_logging
120
+ http_request.basic_auth(username, password) unless username.nil? || password.nil?
121
+ end
122
+
123
+ def execute_request(response)
124
+ prefix = "#{http_request.method} #{hash} #{@connection.hash} #{Thread.current.object_id}"
125
+
126
+ log_before_request(prefix)
127
+ time = Benchmark.realtime { response = Wrest::Native::Response.new(do_request) }
128
+ log_after_request(prefix, time)
129
+
130
+ response
131
+ end
132
+
133
+ def log_after_request(prefix, time)
134
+ Wrest.logger.debug "<- (#{prefix}) Time: #{time}"
135
+ end
136
+
137
+ def log_before_request(prefix)
138
+ Wrest.logger.debug "<- (#{prefix}) #{@uri.protocol}://#{@uri.host}:#{@uri.port}#{@http_request.path}"
139
+ Wrest.logger.debug "<- (#{prefix}) Body: #{@body}"
140
+ end
141
+
142
+ def setup_request_state!(body, headers, parameters, wrest_uri)
143
+ @uri = wrest_uri
144
+ @headers = headers.transform_keys(&:to_s)
145
+ @parameters = parameters
146
+ @body = body
147
+ end
148
+
149
+ def setup_options_state!(options)
150
+ @options = options.clone
151
+ @username = @options[:username]
152
+ @password = @options[:password]
153
+ @timeout = @options[:timeout]
154
+ @connection = @options[:connection]
155
+ @cache_store = @options[:cache_store]
156
+ @verify_mode = @options[:verify_mode]
157
+ @ca_path = @options[:ca_path]
158
+ end
123
159
  end
124
160
  end
125
161
  end
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Copyright 2009 Sidu Ponnappa
2
4
 
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
5
7
  # You may obtain a copy of the License at Http://www.apache.org/licenses/LICENSE-2.0
6
- # Unless required by applicable law or agreed to in writing, software distributed under the License
7
- # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8
- # See the License for the specific language governing permissions and limitations under the License.
9
- require "rexml/document"
10
- module Wrest #:nodoc:
11
- module Native #:nodoc:
8
+ # Unless required by applicable law or agreed to in writing, software distributed under the License
9
+ # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the License for the specific language governing permissions and limitations under the License.
11
+ require 'rexml/document'
12
+ module Wrest # :nodoc:
13
+ module Native # :nodoc:
12
14
  # Decorates a response providing support for deserialisation.
13
15
  #
14
16
  # The following methods are also available (unlisted by rdoc because they're forwarded to Net::HTTP::Response):
@@ -25,11 +27,12 @@ module Wrest #:nodoc:
25
27
  class Response
26
28
  attr_reader :http_response
27
29
  attr_accessor :deserialised_body
30
+
28
31
  include HttpCodes
29
-
32
+
30
33
  extend Forwardable
31
- def_delegators :@http_response, :code, :message, :body, :http_version,
32
- :content_length, :content_type
34
+ def_delegators :@http_response, :code, :message, :body, :http_version,
35
+ :content_length, :content_type
33
36
 
34
37
  def_delegators :headers, :[]
35
38
 
@@ -42,7 +45,7 @@ module Wrest #:nodoc:
42
45
  # on the response code.
43
46
  def self.new(http_response)
44
47
  code = http_response.code.to_i
45
- instance = ((300..303).include?(code) || (305..399).include?(code) ? Wrest::Native::Redirection : self).allocate
48
+ instance = ((300..303).include?(code) || (305..399).include?(code) ? Wrest::Native::Redirection : self).allocate
46
49
  instance.send :initialize, http_response
47
50
  instance
48
51
  end
@@ -57,32 +60,29 @@ module Wrest #:nodoc:
57
60
 
58
61
  # Checks equality between two Wrest::Native::Response objects.
59
62
  def ==(other)
60
- return true if self.equal?(other)
63
+ return true if equal?(other)
61
64
  return false unless other.class == self.class
62
- return true if self.code == other.code and
63
- self.headers == other.headers and
64
- self.http_version == other.http_version and
65
- self.message == other.message and
66
- self.body == other.body
65
+ return true if these_fields_are_equal(other)
66
+
67
67
  false
68
68
  end
69
69
 
70
70
  # Return the hash of a Wrest::Native::Response object.
71
71
  def hash
72
- self.code.hash + self.message.hash + self.headers.hash + self.http_version.hash + self.body.hash
72
+ [code, message, headers, http_version, body].hash
73
73
  end
74
74
 
75
-
76
75
  def deserialise(options = {})
77
- @deserialised_body ||= deserialise_using(Wrest::Components::Translators.lookup(@http_response.content_type),options)
76
+ @deserialised_body ||= deserialise_using(Wrest::Components::Translators.lookup(@http_response.content_type),
77
+ options)
78
78
  end
79
79
 
80
80
  def deserialize(options = {})
81
81
  deserialise(options)
82
82
  end
83
83
 
84
- def deserialise_using(translator,options = {})
85
- translator.deserialise(@http_response,options)
84
+ def deserialise_using(translator, options = {})
85
+ translator.deserialise(@http_response, options)
86
86
  end
87
87
 
88
88
  def deserialize_using(options = {})
@@ -93,13 +93,11 @@ module Wrest #:nodoc:
93
93
  def headers
94
94
  return @headers if @headers
95
95
 
96
- nethttp_headers_with_string_values=@http_response.to_hash.inject({}) {|new_headers, (old_key, old_value)|
97
- new_headers[old_key] = old_value.is_a?(Array) ? old_value.join(",") : old_value
98
- new_headers
99
- }
100
-
101
- @headers=Wrest::HashWithCaseInsensitiveAccess.new(nethttp_headers_with_string_values)
96
+ nethttp_headers_with_string_values = @http_response.to_hash.transform_values do |old_value|
97
+ old_value.is_a?(Array) ? old_value.join(',') : old_value
98
+ end
102
99
 
100
+ @headers = Wrest::HashWithCaseInsensitiveAccess.new(nethttp_headers_with_string_values)
103
101
  end
104
102
 
105
103
  # A null object implementation - invoking this method on
@@ -107,7 +105,7 @@ module Wrest #:nodoc:
107
105
  # the response is Redirection (code 3xx), in which case a
108
106
  # get is invoked on the url stored in the response headers
109
107
  # under the key 'location' and the new Response is returned.
110
- def follow(redirect_request_options = {})
108
+ def follow(_redirect_request_options = {})
111
109
  self
112
110
  end
113
111
 
@@ -115,77 +113,74 @@ module Wrest #:nodoc:
115
113
  self[Native::StandardHeaders::Connection].downcase == Native::StandardTokens::Close.downcase
116
114
  end
117
115
 
118
- # Returns whether this response is cacheable.
116
+ # Returns whether this response is cacheable.
119
117
  def cacheable?
120
- code_cacheable? && no_cache_flag_not_set? && no_store_flag_not_set? &&
121
- (not max_age.nil? or (expires_not_in_our_past? && expires_not_in_its_past?)) && pragma_nocache_not_set? &&
122
- vary_header_valid?
118
+ cache_configs_set? &&
119
+ (!max_age.nil? or (expires_not_in_our_past? && expires_not_in_its_past?)) && pragma_nocache_not_set? &&
120
+ vary_header_valid?
123
121
  end
124
122
 
125
- #:nodoc:
123
+ # :nodoc:
126
124
  def code_cacheable?
127
- !code.nil? && ([200, 203, 300, 301, 302, 304, 307].include?(code.to_i))
125
+ !code.nil? && [200, 203, 300, 301, 302, 304, 307].include?(code.to_i)
128
126
  end
129
127
 
130
- #:nodoc:
128
+ # :nodoc:
131
129
  def vary_header_valid?
132
130
  headers['vary'] != '*'
133
131
  end
134
132
 
135
- #:nodoc:
133
+ # :nodoc:
136
134
  def max_age
137
135
  return @max_age if @max_age
138
136
 
139
- max_age =cache_control_headers.grep(/max-age/)
137
+ max_age = cache_control_headers.grep(/max-age/)
140
138
 
141
- @max_age = unless max_age.empty?
142
- max_age.first.split('=').last.to_i
143
- else
144
- nil
145
- end
139
+ @max_age = (max_age.first.split('=').last.to_i unless max_age.empty?)
146
140
  end
147
141
 
148
142
  def no_cache_flag_not_set?
149
- not cache_control_headers.include?('no-cache')
143
+ !cache_control_headers.include?('no-cache')
150
144
  end
151
145
 
152
146
  def no_store_flag_not_set?
153
- not cache_control_headers.include?('no-store')
147
+ !cache_control_headers.include?('no-store')
154
148
  end
155
149
 
156
150
  def pragma_nocache_not_set?
157
- headers['pragma'].nil? || (not headers['pragma'].include? 'no-cache')
151
+ headers['pragma'].nil? || (!headers['pragma'].include? 'no-cache')
158
152
  end
159
153
 
160
154
  # Returns the Date from the response headers.
161
155
  def response_date
162
156
  return @response_date if @response_date
163
- @response_date = parse_datefield(headers, "date")
164
- end
165
157
 
158
+ @response_date = parse_datefield(headers, 'date')
159
+ end
166
160
 
167
161
  # Returns the Expires date from the response headers.
168
162
  def expires
169
163
  return @expires if @expires
170
- @expires = parse_datefield(headers, "expires")
164
+
165
+ @expires = parse_datefield(headers, 'expires')
171
166
  end
172
167
 
173
- # Returns whether the Expires header of this response is earlier than current time.
168
+ # Returns whether the Expires header of this response is earlier than current time.
174
169
  def expires_not_in_our_past?
175
170
  if expires.nil?
176
171
  false
177
172
  else
178
- expires.to_i > Time.now.to_i
173
+ Utils.datetime_to_i(expires) > Time.now.to_i
179
174
  end
180
175
  end
181
176
 
182
177
  # Is the Expires of this response earlier than its Date header.
183
178
  def expires_not_in_its_past?
184
179
  # Invalid header value for Date or Expires means the response is not cacheable
185
- if expires.nil? || response_date.nil?
180
+ if expires.nil? || response_date.nil?
186
181
  false
187
182
  else
188
- expires > response_date
183
+ expires > response_date
189
184
  end
190
185
  end
191
186
 
@@ -194,10 +189,14 @@ module Wrest #:nodoc:
194
189
  current_time = Time.now.to_i
195
190
 
196
191
  # 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.
197
- date_value = DateTime.parse(headers['date']).to_i rescue current_time
198
- age_value = headers['age'].to_i || 0
192
+ date_value = begin
193
+ Utils.datetime_to_i(DateTime.parse(headers['date']))
194
+ rescue StandardError
195
+ current_time
196
+ end
197
+ age_value = headers['age'].to_i || 0
199
198
 
200
- apparent_age = current_time - date_value
199
+ apparent_age = current_time - date_value
201
200
 
202
201
  [apparent_age, age_value].max
203
202
  end
@@ -207,9 +206,11 @@ module Wrest #:nodoc:
207
206
  @cache_control_headers ||= recalculate_cache_control_headers
208
207
  end
209
208
 
210
- #:nodoc:
209
+ # :nodoc:
211
210
  def recalculate_cache_control_headers
212
- headers['cache-control'].split(",").collect {|cc| cc.strip } rescue []
211
+ headers['cache-control'].split(',').collect(&:strip)
212
+ rescue StandardError
213
+ []
213
214
  end
214
215
 
215
216
  # How long (in seconds) is this response expected to be fresh
@@ -217,22 +218,20 @@ module Wrest #:nodoc:
217
218
  @freshness_lifetime ||= recalculate_freshness_lifetime
218
219
  end
219
220
 
220
- #:nodoc:
221
+ # :nodoc:
221
222
  def recalculate_freshness_lifetime
222
223
  return max_age if max_age
223
224
 
224
- response_date = DateTime.parse(headers['date']).to_i
225
- expires_date = DateTime.parse(headers['expires']).to_i
225
+ response_date = Utils.datetime_to_i(DateTime.parse(headers['date']))
226
+ expires_date = Utils.datetime_to_i(DateTime.parse(headers['expires']))
226
227
 
227
- return (expires_date - response_date)
228
+ (expires_date - response_date)
228
229
  end
229
230
 
230
231
  # Has this response expired? The expiry is calculated from the Max-Age/Expires header.
231
232
  def expired?
232
- freshness=freshness_lifetime
233
- if freshness <= 0
234
- return true
235
- end
233
+ freshness = freshness_lifetime
234
+ return true if freshness <= 0
236
235
 
237
236
  freshness <= current_age
238
237
  end
@@ -244,26 +243,36 @@ module Wrest #:nodoc:
244
243
  # Can this response be validated by sending a validation request to the server. The response need to have either
245
244
  # Last-Modified or ETag header (or both) for it to be validatable.
246
245
  def can_be_validated?
247
- not (last_modified.nil? and headers['etag'].nil?)
246
+ !(last_modified.nil? and headers['etag'].nil?)
248
247
  end
249
248
 
250
-
251
- #:nodoc:
249
+ # :nodoc:
252
250
  # helper function. Used to parse date fields.
253
251
  # this function is used and tested by the expires and response_date methods
254
252
  def parse_datefield(hash, key)
255
- if hash[key]
256
- # Can't trust external input. Do not crash even if invalid dates are passed.
257
- begin
258
- DateTime.parse(hash[key].to_s)
259
- rescue ArgumentError
260
- nil
261
- end
262
- else
253
+ return unless hash[key]
254
+
255
+ # Can't trust external input. Do not crash even if invalid dates are passed.
256
+ begin
257
+ DateTime.parse(hash[key].to_s)
258
+ rescue ArgumentError
263
259
  nil
264
260
  end
265
261
  end
266
262
 
263
+ private
264
+
265
+ def cache_configs_set?
266
+ code_cacheable? && no_cache_flag_not_set? && no_store_flag_not_set?
267
+ end
268
+
269
+ def these_fields_are_equal(other)
270
+ (code == other.code) &&
271
+ (headers == other.headers) &&
272
+ (http_version == other.http_version) &&
273
+ (message == other.message) &&
274
+ (body == other.body)
275
+ end
267
276
  end
268
277
  end
269
278
  end