wrest 4.0.0-universal-java-18

Sign up to get free protection for your applications and to get access to all the features.
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