wrest 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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