wrest 4.0.0-universal-java-18

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 (66) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +169 -0
  3. data/LICENCE +7 -0
  4. data/README.md +436 -0
  5. data/bin/wrest +4 -0
  6. data/bin/wrest_shell.rb +23 -0
  7. data/lib/wrest/async_request/event_machine_backend.rb +32 -0
  8. data/lib/wrest/async_request/thread_backend.rb +34 -0
  9. data/lib/wrest/async_request/thread_pool.rb +29 -0
  10. data/lib/wrest/async_request.rb +51 -0
  11. data/lib/wrest/cache_proxy.rb +119 -0
  12. data/lib/wrest/caching/memcached.rb +37 -0
  13. data/lib/wrest/caching/redis.rb +38 -0
  14. data/lib/wrest/caching.rb +57 -0
  15. data/lib/wrest/callback.rb +70 -0
  16. data/lib/wrest/components/container/alias_accessors.rb +70 -0
  17. data/lib/wrest/components/container/typecaster.rb +178 -0
  18. data/lib/wrest/components/container.rb +204 -0
  19. data/lib/wrest/components/mutators/base.rb +65 -0
  20. data/lib/wrest/components/mutators/camel_to_snake_case.rb +26 -0
  21. data/lib/wrest/components/mutators/xml_type_caster.rb +56 -0
  22. data/lib/wrest/components/mutators.rb +42 -0
  23. data/lib/wrest/components/translators/content_types.rb +25 -0
  24. data/lib/wrest/components/translators/json.rb +36 -0
  25. data/lib/wrest/components/translators/txt.rb +35 -0
  26. data/lib/wrest/components/translators/xml/conversions.rb +56 -0
  27. data/lib/wrest/components/translators/xml.rb +77 -0
  28. data/lib/wrest/components/translators.rb +30 -0
  29. data/lib/wrest/components.rb +22 -0
  30. data/lib/wrest/core_ext/hash/conversions.rb +45 -0
  31. data/lib/wrest/core_ext/hash.rb +7 -0
  32. data/lib/wrest/core_ext/string/conversions.rb +38 -0
  33. data/lib/wrest/core_ext/string.rb +7 -0
  34. data/lib/wrest/exceptions.rb +38 -0
  35. data/lib/wrest/hash_with_case_insensitive_access.rb +52 -0
  36. data/lib/wrest/hash_with_indifferent_access.rb +442 -0
  37. data/lib/wrest/http_codes.rb +83 -0
  38. data/lib/wrest/http_shared/headers.rb +345 -0
  39. data/lib/wrest/http_shared/standard_headers.rb +22 -0
  40. data/lib/wrest/http_shared/standard_tokens.rb +21 -0
  41. data/lib/wrest/http_shared.rb +25 -0
  42. data/lib/wrest/multipart.rb +84 -0
  43. data/lib/wrest/native/connection_factory.rb +28 -0
  44. data/lib/wrest/native/delete.rb +27 -0
  45. data/lib/wrest/native/get.rb +83 -0
  46. data/lib/wrest/native/options.rb +27 -0
  47. data/lib/wrest/native/patch.rb +27 -0
  48. data/lib/wrest/native/post.rb +27 -0
  49. data/lib/wrest/native/post_multipart.rb +36 -0
  50. data/lib/wrest/native/put.rb +27 -0
  51. data/lib/wrest/native/put_multipart.rb +36 -0
  52. data/lib/wrest/native/redirection.rb +39 -0
  53. data/lib/wrest/native/request.rb +161 -0
  54. data/lib/wrest/native/response.rb +278 -0
  55. data/lib/wrest/native/session.rb +66 -0
  56. data/lib/wrest/native.rb +36 -0
  57. data/lib/wrest/test/request_patches.rb +12 -0
  58. data/lib/wrest/test.rb +3 -0
  59. data/lib/wrest/uri/builders.rb +48 -0
  60. data/lib/wrest/uri.rb +312 -0
  61. data/lib/wrest/uri_template.rb +63 -0
  62. data/lib/wrest/utils.rb +129 -0
  63. data/lib/wrest/version.rb +14 -0
  64. data/lib/wrest.rb +77 -0
  65. data/lib/wrest_no_ext.rb +7 -0
  66. metadata +286 -0
@@ -0,0 +1,278 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2009 Sidu Ponnappa
4
+
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at Http://www.apache.org/licenses/LICENSE-2.0
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:
14
+ # Decorates a response providing support for deserialisation.
15
+ #
16
+ # The following methods are also available (unlisted by rdoc because they're forwarded to Net::HTTP::Response):
17
+ #
18
+ # <tt>:@Http_response, :code, :message, :body, :Http_version,
19
+ # :[], :content_length, :content_type, :each_header, :each_name, :each_value, :fetch,
20
+ # :get_fields, :key?, :type_params</tt>
21
+ #
22
+ # They behave exactly like their Net::HttpResponse equivalents.
23
+ #
24
+ # Also provides set of HTTP response code checkers. For instance, the method ok? checks if the response was
25
+ # successful with HTTP code 200.
26
+ # See HttpCodes for a list of all such response checkers.
27
+ class Response
28
+ attr_reader :http_response
29
+ attr_accessor :deserialised_body
30
+
31
+ include HttpCodes
32
+
33
+ extend Forwardable
34
+ def_delegators :@http_response, :code, :message, :body, :http_version,
35
+ :content_length, :content_type
36
+
37
+ def_delegators :headers, :[]
38
+
39
+ # TODO : Are these needed in the Response namespace itself? Can be accessed from the headers method.
40
+ def_delegators :@http_response, :each_header, :each_name, :each_value, :fetch,
41
+ :get_fields, :key?, :type_params
42
+
43
+ # We're overriding :new to act as a factory so
44
+ # we can build the appropriate Response instance based
45
+ # on the response code.
46
+ def self.new(http_response)
47
+ code = http_response.code.to_i
48
+ instance = ((300..303).include?(code) || (305..399).include?(code) ? Wrest::Native::Redirection : self).allocate
49
+ instance.send :initialize, http_response
50
+ instance
51
+ end
52
+
53
+ def initialize(http_response)
54
+ @http_response = http_response
55
+ end
56
+
57
+ def initialize_copy(source)
58
+ @headers = source.headers.clone
59
+ end
60
+
61
+ # Checks equality between two Wrest::Native::Response objects.
62
+ def ==(other)
63
+ return true if equal?(other)
64
+ return false unless other.class == self.class
65
+ return true if these_fields_are_equal(other)
66
+
67
+ false
68
+ end
69
+
70
+ # Return the hash of a Wrest::Native::Response object.
71
+ def hash
72
+ [code, message, headers, http_version, body].hash
73
+ end
74
+
75
+ def deserialise(options = {})
76
+ @deserialised_body ||= deserialise_using(Wrest::Components::Translators.lookup(@http_response.content_type),
77
+ options)
78
+ end
79
+
80
+ def deserialize(options = {})
81
+ deserialise(options)
82
+ end
83
+
84
+ def deserialise_using(translator, options = {})
85
+ translator.deserialise(@http_response, options)
86
+ end
87
+
88
+ def deserialize_using(options = {})
89
+ deserialise_using(options)
90
+ end
91
+
92
+ # Gives a hash of the response headers. The keys of the hash are case-insensitive.
93
+ def headers
94
+ return @headers if @headers
95
+
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
99
+
100
+ @headers = Wrest::HashWithCaseInsensitiveAccess.new(nethttp_headers_with_string_values)
101
+ end
102
+
103
+ # A null object implementation - invoking this method on
104
+ # a response simply returns the same response unless
105
+ # the response is Redirection (code 3xx), in which case a
106
+ # get is invoked on the url stored in the response headers
107
+ # under the key 'location' and the new Response is returned.
108
+ def follow(_redirect_request_options = {})
109
+ self
110
+ end
111
+
112
+ def connection_closed?
113
+ self[Native::StandardHeaders::Connection].downcase == Native::StandardTokens::Close.downcase
114
+ end
115
+
116
+ # Returns whether this response is cacheable.
117
+ def cacheable?
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?
121
+ end
122
+
123
+ # :nodoc:
124
+ def code_cacheable?
125
+ !code.nil? && [200, 203, 300, 301, 302, 304, 307].include?(code.to_i)
126
+ end
127
+
128
+ # :nodoc:
129
+ def vary_header_valid?
130
+ headers['vary'] != '*'
131
+ end
132
+
133
+ # :nodoc:
134
+ def max_age
135
+ return @max_age if @max_age
136
+
137
+ max_age = cache_control_headers.grep(/max-age/)
138
+
139
+ @max_age = (max_age.first.split('=').last.to_i unless max_age.empty?)
140
+ end
141
+
142
+ def no_cache_flag_not_set?
143
+ !cache_control_headers.include?('no-cache')
144
+ end
145
+
146
+ def no_store_flag_not_set?
147
+ !cache_control_headers.include?('no-store')
148
+ end
149
+
150
+ def pragma_nocache_not_set?
151
+ headers['pragma'].nil? || (!headers['pragma'].include? 'no-cache')
152
+ end
153
+
154
+ # Returns the Date from the response headers.
155
+ def response_date
156
+ return @response_date if @response_date
157
+
158
+ @response_date = parse_datefield(headers, 'date')
159
+ end
160
+
161
+ # Returns the Expires date from the response headers.
162
+ def expires
163
+ return @expires if @expires
164
+
165
+ @expires = parse_datefield(headers, 'expires')
166
+ end
167
+
168
+ # Returns whether the Expires header of this response is earlier than current time.
169
+ def expires_not_in_our_past?
170
+ if expires.nil?
171
+ false
172
+ else
173
+ Utils.datetime_to_i(expires) > Time.now.to_i
174
+ end
175
+ end
176
+
177
+ # Is the Expires of this response earlier than its Date header.
178
+ def expires_not_in_its_past?
179
+ # Invalid header value for Date or Expires means the response is not cacheable
180
+ if expires.nil? || response_date.nil?
181
+ false
182
+ else
183
+ expires > response_date
184
+ end
185
+ end
186
+
187
+ # Age of the response calculated according to RFC 2616 13.2.3
188
+ def current_age
189
+ current_time = Time.now.to_i
190
+
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.
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
198
+
199
+ apparent_age = current_time - date_value
200
+
201
+ [apparent_age, age_value].max
202
+ end
203
+
204
+ # The values in Cache-Control header as an array.
205
+ def cache_control_headers
206
+ @cache_control_headers ||= recalculate_cache_control_headers
207
+ end
208
+
209
+ # :nodoc:
210
+ def recalculate_cache_control_headers
211
+ headers['cache-control'].split(',').collect(&:strip)
212
+ rescue StandardError
213
+ []
214
+ end
215
+
216
+ # How long (in seconds) is this response expected to be fresh
217
+ def freshness_lifetime
218
+ @freshness_lifetime ||= recalculate_freshness_lifetime
219
+ end
220
+
221
+ # :nodoc:
222
+ def recalculate_freshness_lifetime
223
+ return max_age if max_age
224
+
225
+ response_date = Utils.datetime_to_i(DateTime.parse(headers['date']))
226
+ expires_date = Utils.datetime_to_i(DateTime.parse(headers['expires']))
227
+
228
+ (expires_date - response_date)
229
+ end
230
+
231
+ # Has this response expired? The expiry is calculated from the Max-Age/Expires header.
232
+ def expired?
233
+ freshness = freshness_lifetime
234
+ return true if freshness <= 0
235
+
236
+ freshness <= current_age
237
+ end
238
+
239
+ def last_modified
240
+ headers['last-modified']
241
+ end
242
+
243
+ # Can this response be validated by sending a validation request to the server. The response need to have either
244
+ # Last-Modified or ETag header (or both) for it to be validatable.
245
+ def can_be_validated?
246
+ !(last_modified.nil? and headers['etag'].nil?)
247
+ end
248
+
249
+ # :nodoc:
250
+ # helper function. Used to parse date fields.
251
+ # this function is used and tested by the expires and response_date methods
252
+ def parse_datefield(hash, key)
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
259
+ nil
260
+ end
261
+ end
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
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2009 Sidu Ponnappa
4
+
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
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
+
12
+ module Wrest
13
+ module Native
14
+ # This class is a wrapper for a keep-alive HTTP connection. It simply passes the
15
+ # same connection instance as an option to all Wrest::Native::Request instances created using it.
16
+ #
17
+ # If at any point the server closes an existing connection during a Session by returning a
18
+ # Connection: Close header the current connection is destroyed and a fresh one created for the next
19
+ # request.
20
+ #
21
+ # The Session constructor can accept either a String URI or a Wrest::Uri as a parameter. If you
22
+ # need HTTP authentication, you should use a Wrest::Uri.
23
+ class Session
24
+ attr_reader :uri
25
+
26
+ def initialize(uri)
27
+ @uri = Wrest::Uri.new(uri)
28
+ @default_headers = { Wrest::Native::StandardHeaders::Connection => Wrest::Native::StandardTokens::KeepAlive }
29
+
30
+ yield(self) if block_given?
31
+ end
32
+
33
+ def connection
34
+ @connection ||= @uri.create_connection
35
+ end
36
+
37
+ def get(path = '', parameters = {}, headers = {})
38
+ maybe_destroy_connection @uri[path, { connection: connection }].get(parameters,
39
+ headers.merge(@default_headers))
40
+ end
41
+
42
+ def post(path = '', body = '', headers = {}, params = {})
43
+ maybe_destroy_connection @uri[path, { connection: connection }].post(body, headers.merge(@default_headers),
44
+ params)
45
+ end
46
+
47
+ def put(path = '', body = '', headers = {}, params = {})
48
+ maybe_destroy_connection @uri[path, { connection: connection }].put(body, headers.merge(@default_headers),
49
+ params)
50
+ end
51
+
52
+ def delete(path = '', parameters = {}, headers = {})
53
+ maybe_destroy_connection @uri[path, { connection: connection }].delete(parameters,
54
+ headers.merge(@default_headers))
55
+ end
56
+
57
+ def maybe_destroy_connection(response)
58
+ if response.connection_closed?
59
+ Wrest.logger.warn "Connection #{@connection.hash} has been closed by the server"
60
+ @connection = nil
61
+ end
62
+ response
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2009 Sidu Ponnappa
4
+
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at native://www.apache.org/licenses/LICENSE-2.0
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
+
12
+ module Wrest
13
+ # Contains all native protocol related classes such as
14
+ # Get, Post, Request, Response etc. and uses the native
15
+ # Ruby Net::HTTP libraries.
16
+ #
17
+ # Wrest::Http points to this module by default.
18
+ module Native
19
+ include Wrest::HttpShared
20
+ end
21
+ end
22
+
23
+ require 'wrest/native/connection_factory'
24
+ require 'wrest/native/response'
25
+ require 'wrest/native/redirection'
26
+ require 'wrest/native/request'
27
+ require 'wrest/native/get'
28
+ require 'wrest/native/put'
29
+ require 'wrest/native/patch'
30
+ require 'wrest/native/post'
31
+ require 'wrest/native/delete'
32
+ require 'wrest/native/options'
33
+ require 'wrest/native/session'
34
+
35
+ # default to using Native libs
36
+ Wrest::Http = Wrest::Native
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wrest
4
+ module Native
5
+ class Request
6
+ def invoke
7
+ raise Wrest::Exceptions::RealRequestMadeInTestEnvironmet,
8
+ 'A real HTTP request was made while running tests. Please avoid using live HTTP connections while testing and replace them with mocks.'
9
+ end
10
+ end
11
+ end
12
+ end
data/lib/wrest/test.rb ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'wrest/test/request_patches'
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Wrest
4
+ class Uri
5
+ # Contains methods that depend on Uri#clone to build
6
+ # new Uris configured in particular ways.
7
+ module Builders
8
+ # Returns a Uri object that uses threads to perform asynchronous requests.
9
+ def using_threads
10
+ clone(asynchronous_backend: Wrest::AsyncRequest::ThreadBackend.new)
11
+ end
12
+
13
+ # Returns a Uri object that uses eventmachine to perform asynchronous requests.
14
+ # Remember to do Wrest::AsyncRequest.enable_em first so that
15
+ # EventMachine is available for use.
16
+ def using_em
17
+ clone(asynchronous_backend: Wrest::AsyncRequest::EventMachineBackend.new)
18
+ end
19
+
20
+ # Returns a Uri object that uses hash for caching responses.
21
+ def using_hash
22
+ clone(cache_store: {})
23
+ end
24
+
25
+ # Returns a Uri object that uses memcached for caching responses.
26
+ # Remember to do Wrest::AsyncRequest.enable_memcached first so that
27
+ # memcached is available for use.
28
+ def using_memcached
29
+ clone(cache_store: Wrest::Caching::Memcached.new)
30
+ end
31
+
32
+ def using_redis
33
+ clone(cache_store: Wrest::Caching::Redis.new)
34
+ end
35
+
36
+ # Disables using the globally configured cache for GET requests
37
+ # made using the Uri returned by this method.
38
+ def disable_cache
39
+ clone(disable_cache: true)
40
+ end
41
+
42
+ # Sets the specified string as the cookie for the Uri
43
+ def using_cookie(cookie_string)
44
+ clone(default_headers: { Wrest::H::Cookie => cookie_string })
45
+ end
46
+ end
47
+ end
48
+ end