embark-journey 0.0.20 → 0.0.21

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0d0674e156d1762795bd1ce22e56e4bc30873ae8
4
- data.tar.gz: c09c498cb961accad66bb24489b6f569793be451
3
+ metadata.gz: a5787f183545667833aa70931e85b09333bed067
4
+ data.tar.gz: 52ca2385cd5805ac574a76913539afddab4dafcc
5
5
  SHA512:
6
- metadata.gz: ba9f9ec74f97df6ee03fffb6e5a5ac913dd27ecbae74be32e5164c6076a5c76f8b55d330bd75dfe39b474e1998c0de9b490f1095f3dd894705e7a89d023b586d
7
- data.tar.gz: 0f841fce49fc92b25e5515f829c3a78360575e9307275dc94603339ce66ca6ee2fa71a65d29cc9ea02c7a292fe6d52a999b251b5096831623579effb16ad7617
6
+ metadata.gz: 56f34fb17571bcd21a5cdde76b1f19e2ff07bb711d059f736405d1d5c327edda811cecc3357b139c5553245f452bb3f9018d7c39f10820db1c8fa55d77cc17e8
7
+ data.tar.gz: 10255614494e016c5f896adddc998849fe8fb67ad86b68e60bc7a8fdd8a744ae9b0c78f024aba16fe15f88fe16ea12719c234f04069f158ea064889639d6f780
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ v0.0.21
2
+ - stomped out Rails load order bug by copying over entire Connection class (hacky)
3
+
1
4
  v0.0.20
2
5
  - fixes Rails load order bug with Connection (related to gzip patch)
3
6
 
@@ -1,47 +1,294 @@
1
- require 'active_resource/connection'
2
- ActiveResource::Connection
1
+ require 'active_support/core_ext/benchmark'
2
+ require 'active_support/core_ext/uri'
3
+ require 'active_support/core_ext/object/inclusion'
4
+ require 'net/https'
5
+ require 'date'
6
+ require 'time'
7
+ require 'uri'
3
8
 
4
9
  module ActiveResource
10
+ # Class to handle connections to remote web services.
11
+ # This class is used by ActiveResource::Base to interface with REST
12
+ # services.
5
13
  class Connection
6
14
 
7
- def handle_response(response)
8
- if response.respond_to?(:header) && (response.header["content-encoding"] == 'gzip')
9
- begin
10
- response.instance_variable_set('@body', ActiveSupport::Gzip.decompress(response.body))
11
- rescue Exception => e
12
- raise(BadRequest.new(response))
13
- end
14
- end
15
-
16
- case response.code.to_i
17
- when 301, 302, 303, 307
18
- raise(Redirection.new(response))
19
- when 200...400
20
- response
21
- when 400
22
- raise(BadRequest.new(response))
23
- when 401
24
- raise(UnauthorizedAccess.new(response))
25
- when 403
26
- raise(ForbiddenAccess.new(response))
27
- when 404
28
- raise(ResourceNotFound.new(response))
29
- when 405
30
- raise(MethodNotAllowed.new(response))
31
- when 409
32
- raise(ResourceConflict.new(response))
33
- when 410
34
- raise(ResourceGone.new(response))
35
- when 422
36
- raise(ResourceInvalid.new(response))
37
- when 401...500
38
- raise(ClientError.new(response))
39
- when 500...600
40
- raise(ServerError.new(response))
41
- else
42
- raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
15
+ HTTP_FORMAT_HEADER_NAMES = { :get => 'Accept',
16
+ :put => 'Content-Type',
17
+ :post => 'Content-Type',
18
+ :patch => 'Content-Type',
19
+ :delete => 'Accept',
20
+ :head => 'Accept'
21
+ }
22
+
23
+ attr_reader :site, :user, :password, :auth_type, :timeout, :proxy, :ssl_options
24
+ attr_accessor :format
25
+
26
+ class << self
27
+ def requests
28
+ @@requests ||= []
43
29
  end
44
30
  end
45
31
 
32
+ # The +site+ parameter is required and will set the +site+
33
+ # attribute to the URI for the remote resource service.
34
+ def initialize(site, format = ActiveResource::Formats::JsonFormat)
35
+ raise ArgumentError, 'Missing site URI' unless site
36
+ @proxy = @user = @password = nil
37
+ self.site = site
38
+ self.format = format
39
+ end
40
+
41
+ # Set URI for remote service.
42
+ def site=(site)
43
+ @site = site.is_a?(URI) ? site : URI.parse(site)
44
+ @ssl_options ||= {} if @site.is_a?(URI::HTTPS)
45
+ @user = URI.parser.unescape(@site.user) if @site.user
46
+ @password = URI.parser.unescape(@site.password) if @site.password
47
+ end
48
+
49
+ # Set the proxy for remote service.
50
+ def proxy=(proxy)
51
+ @proxy = proxy.is_a?(URI) ? proxy : URI.parse(proxy)
52
+ end
53
+
54
+ # Sets the user for remote service.
55
+ def user=(user)
56
+ @user = user
57
+ end
58
+
59
+ # Sets the password for remote service.
60
+ def password=(password)
61
+ @password = password
62
+ end
63
+
64
+ # Sets the auth type for remote service.
65
+ def auth_type=(auth_type)
66
+ @auth_type = legitimize_auth_type(auth_type)
67
+ end
68
+
69
+ # Sets the number of seconds after which HTTP requests to the remote service should time out.
70
+ def timeout=(timeout)
71
+ @timeout = timeout
72
+ end
73
+
74
+ # Hash of options applied to Net::HTTP instance when +site+ protocol is 'https'.
75
+ def ssl_options=(options)
76
+ @ssl_options = options
77
+ end
78
+
79
+ # Executes a GET request.
80
+ # Used to get (find) resources.
81
+ def get(path, headers = {})
82
+ with_auth { request(:get, path, build_request_headers(headers, :get, self.site.merge(path))) }
83
+ end
84
+
85
+ # Executes a DELETE request (see HTTP protocol documentation if unfamiliar).
86
+ # Used to delete resources.
87
+ def delete(path, headers = {})
88
+ with_auth { request(:delete, path, build_request_headers(headers, :delete, self.site.merge(path))) }
89
+ end
90
+
91
+ # Executes a PATCH request (see HTTP protocol documentation if unfamiliar).
92
+ # Used to update resources.
93
+ def patch(path, body = '', headers = {})
94
+ with_auth { request(:patch, path, body.to_s, build_request_headers(headers, :patch, self.site.merge(path))) }
95
+ end
96
+
97
+ # Executes a PUT request (see HTTP protocol documentation if unfamiliar).
98
+ # Used to update resources.
99
+ def put(path, body = '', headers = {})
100
+ with_auth { request(:put, path, body.to_s, build_request_headers(headers, :put, self.site.merge(path))) }
101
+ end
102
+
103
+ # Executes a POST request.
104
+ # Used to create new resources.
105
+ def post(path, body = '', headers = {})
106
+ with_auth { request(:post, path, body.to_s, build_request_headers(headers, :post, self.site.merge(path))) }
107
+ end
108
+
109
+ # Executes a HEAD request.
110
+ # Used to obtain meta-information about resources, such as whether they exist and their size (via response headers).
111
+ def head(path, headers = {})
112
+ with_auth { request(:head, path, build_request_headers(headers, :head, self.site.merge(path))) }
113
+ end
114
+
115
+ private
116
+ # Makes a request to the remote service.
117
+ def request(method, path, *arguments)
118
+ result = ActiveSupport::Notifications.instrument("request.active_resource") do |payload|
119
+ payload[:method] = method
120
+ payload[:request_uri] = "#{site.scheme}://#{site.host}:#{site.port}#{path}"
121
+ payload[:result] = http.send(method, path, *arguments)
122
+ end
123
+ handle_response(result)
124
+ rescue Timeout::Error => e
125
+ raise TimeoutError.new(e.message)
126
+ rescue OpenSSL::SSL::SSLError => e
127
+ raise SSLError.new(e.message)
128
+ end
129
+
130
+ # Handles response and error codes from the remote service.
131
+ def handle_response(response)
132
+ if response.respond_to?(:header) && (response.header["content-encoding"] == 'gzip')
133
+ begin
134
+ response.instance_variable_set('@body', ActiveSupport::Gzip.decompress(response.body))
135
+ rescue Exception => e
136
+ raise(BadRequest.new(response))
137
+ end
138
+ end
139
+
140
+
141
+ case response.code.to_i
142
+ when 301, 302, 303, 307
143
+ raise(Redirection.new(response))
144
+ when 200...400
145
+ response
146
+ when 400
147
+ raise(BadRequest.new(response))
148
+ when 401
149
+ raise(UnauthorizedAccess.new(response))
150
+ when 403
151
+ raise(ForbiddenAccess.new(response))
152
+ when 404
153
+ raise(ResourceNotFound.new(response))
154
+ when 405
155
+ raise(MethodNotAllowed.new(response))
156
+ when 409
157
+ raise(ResourceConflict.new(response))
158
+ when 410
159
+ raise(ResourceGone.new(response))
160
+ when 422
161
+ raise(ResourceInvalid.new(response))
162
+ when 401...500
163
+ raise(ClientError.new(response))
164
+ when 500...600
165
+ raise(ServerError.new(response))
166
+ else
167
+ raise(ConnectionError.new(response, "Unknown response code: #{response.code}"))
168
+ end
169
+ end
170
+
171
+ # Creates new Net::HTTP instance for communication with the
172
+ # remote service and resources.
173
+ def http
174
+ configure_http(new_http)
175
+ end
176
+
177
+ def new_http
178
+ if @proxy
179
+ Net::HTTP.new(@site.host, @site.port, @proxy.host, @proxy.port, @proxy.user, @proxy.password)
180
+ else
181
+ Net::HTTP.new(@site.host, @site.port)
182
+ end
183
+ end
184
+
185
+ def configure_http(http)
186
+ apply_ssl_options(http).tap do |https|
187
+ # Net::HTTP timeouts default to 60 seconds.
188
+ if defined? @timeout
189
+ https.open_timeout = @timeout
190
+ https.read_timeout = @timeout
191
+ end
192
+ end
193
+ end
194
+
195
+ def apply_ssl_options(http)
196
+ http.tap do |https|
197
+ # Skip config if site is already a https:// URI.
198
+ if defined? @ssl_options
199
+ http.use_ssl = true
200
+
201
+ # Default to no cert verification (WTF? FIXME)
202
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
203
+
204
+ # All the SSL options have corresponding http settings.
205
+ @ssl_options.each { |key, value| http.send "#{key}=", value }
206
+ end
207
+ end
208
+ end
209
+
210
+ def default_header
211
+ @default_header ||= {}
212
+ end
213
+
214
+ # Builds headers for request to remote service.
215
+ def build_request_headers(headers, http_method, uri)
216
+ authorization_header(http_method, uri).update(default_header).update(http_format_header(http_method)).update(headers)
217
+ end
218
+
219
+ def response_auth_header
220
+ @response_auth_header ||= ""
221
+ end
222
+
223
+ def with_auth
224
+ retried ||= false
225
+ yield
226
+ rescue UnauthorizedAccess => e
227
+ raise if retried || auth_type != :digest
228
+ @response_auth_header = e.response['WWW-Authenticate']
229
+ retried = true
230
+ retry
231
+ end
232
+
233
+ def authorization_header(http_method, uri)
234
+ if @user || @password
235
+ if auth_type == :digest
236
+ { 'Authorization' => digest_auth_header(http_method, uri) }
237
+ else
238
+ { 'Authorization' => 'Basic ' + ["#{@user}:#{@password}"].pack('m').delete("\r\n") }
239
+ end
240
+ else
241
+ {}
242
+ end
243
+ end
244
+
245
+ def digest_auth_header(http_method, uri)
246
+ params = extract_params_from_response
247
+
248
+ request_uri = uri.path
249
+ request_uri << "?#{uri.query}" if uri.query
250
+
251
+ ha1 = Digest::MD5.hexdigest("#{@user}:#{params['realm']}:#{@password}")
252
+ ha2 = Digest::MD5.hexdigest("#{http_method.to_s.upcase}:#{request_uri}")
253
+
254
+ params.merge!('cnonce' => client_nonce)
255
+ request_digest = Digest::MD5.hexdigest([ha1, params['nonce'], "0", params['cnonce'], params['qop'], ha2].join(":"))
256
+ "Digest #{auth_attributes_for(uri, request_digest, params)}"
257
+ end
258
+
259
+ def client_nonce
260
+ Digest::MD5.hexdigest("%x" % (Time.now.to_i + rand(65535)))
261
+ end
262
+
263
+ def extract_params_from_response
264
+ params = {}
265
+ if response_auth_header =~ /^(\w+) (.*)/
266
+ $2.gsub(/(\w+)="(.*?)"/) { params[$1] = $2 }
267
+ end
268
+ params
269
+ end
270
+
271
+ def auth_attributes_for(uri, request_digest, params)
272
+ [
273
+ %Q(username="#{@user}"),
274
+ %Q(realm="#{params['realm']}"),
275
+ %Q(qop="#{params['qop']}"),
276
+ %Q(uri="#{uri.path}"),
277
+ %Q(nonce="#{params['nonce']}"),
278
+ %Q(nc="0"),
279
+ %Q(cnonce="#{params['cnonce']}"),
280
+ %Q(opaque="#{params['opaque']}"),
281
+ %Q(response="#{request_digest}")].join(", ")
282
+ end
283
+
284
+ def http_format_header(http_method)
285
+ {HTTP_FORMAT_HEADER_NAMES[http_method] => format.mime_type}
286
+ end
287
+
288
+ def legitimize_auth_type(auth_type)
289
+ return :basic if auth_type.nil?
290
+ auth_type = auth_type.to_sym
291
+ auth_type.in?([:basic, :digest]) ? auth_type : :basic
292
+ end
46
293
  end
47
294
  end
@@ -2,7 +2,7 @@ module Journey
2
2
  module VERSION
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- TINY = 20
5
+ TINY = 21
6
6
  PRE = nil
7
7
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embark-journey
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.20
4
+ version: 0.0.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Davey