skylight 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,438 +0,0 @@
1
- module Skylight
2
- module Vendor
3
- module Excon
4
- class Connection
5
- VALID_CONNECTION_KEYS = [:body, :family, :headers, :host, :path, :port, :query, :scheme, :user, :password,
6
- :instrumentor, :instrumentor_name, :ssl_ca_file, :ssl_verify_peer, :chunk_size,
7
- :nonblock, :retry_limit, :connect_timeout, :read_timeout, :write_timeout, :captures,
8
- :exception, :expects, :mock, :proxy, :method, :idempotent, :request_block, :response_block,
9
- :middlewares, :retries_remaining, :connection, :stack, :response, :pipeline]
10
- attr_reader :data
11
-
12
- def params
13
- $stderr.puts("Excon::Connection#params is deprecated use Excon::Connection#data instead (#{caller.first})")
14
- @data
15
- end
16
- def params=(new_params)
17
- $stderr.puts("Excon::Connection#params= is deprecated use Excon::Connection#data= instead (#{caller.first})")
18
- @data = new_params
19
- end
20
-
21
- def proxy
22
- $stderr.puts("Excon::Connection#proxy is deprecated use Excon::Connection#data[:proxy] instead (#{caller.first})")
23
- @data[:proxy]
24
- end
25
- def proxy=(new_proxy)
26
- $stderr.puts("Excon::Connection#proxy= is deprecated use Excon::Connection#data[:proxy]= instead (#{caller.first})")
27
- @data[:proxy] = new_proxy
28
- end
29
-
30
- def assert_valid_keys_for_argument!(argument, valid_keys)
31
- invalid_keys = argument.keys - valid_keys
32
- return true if invalid_keys.empty?
33
- raise ArgumentError, "The following keys are invalid: #{invalid_keys.map(&:inspect).join(', ')}"
34
- end
35
- private :assert_valid_keys_for_argument!
36
-
37
- # Initializes a new Connection instance
38
- # @param [String] url The destination URL
39
- # @param [Hash<Symbol, >] params One or more optional params
40
- # @option params [String] :body Default text to be sent over a socket. Only used if :body absent in Connection#request params
41
- # @option params [Hash<Symbol, String>] :headers The default headers to supply in a request. Only used if params[:headers] is not supplied to Connection#request
42
- # @option params [String] :host The destination host's reachable DNS name or IP, in the form of a String
43
- # @option params [String] :path Default path; appears after 'scheme://host:port/'. Only used if params[:path] is not supplied to Connection#request
44
- # @option params [Fixnum] :port The port on which to connect, to the destination host
45
- # @option params [Hash] :query Default query; appended to the 'scheme://host:port/path/' in the form of '?key=value'. Will only be used if params[:query] is not supplied to Connection#request
46
- # @option params [String] :scheme The protocol; 'https' causes OpenSSL to be used
47
- # @option params [String] :proxy Proxy server; e.g. 'http://myproxy.com:8888'
48
- # @option params [Fixnum] :retry_limit Set how many times we'll retry a failed request. (Default 4)
49
- # @option params [Class] :instrumentor Responds to #instrument as in ActiveSupport::Notifications
50
- # @option params [String] :instrumentor_name Name prefix for #instrument events. Defaults to 'excon'
51
- def initialize(url, params = {})
52
- assert_valid_keys_for_argument!(params, VALID_CONNECTION_KEYS)
53
- uri = URI.parse(url)
54
- @data = Excon.defaults.merge({
55
- :host => uri.host,
56
- :path => uri.path,
57
- :port => uri.port.to_s,
58
- :query => uri.query,
59
- :scheme => uri.scheme,
60
- :user => (URI.decode(uri.user) if uri.user),
61
- :password => (URI.decode(uri.password) if uri.password),
62
- }).merge!(params)
63
- # merge does not deep-dup, so make sure headers is not the original
64
- @data[:headers] = @data[:headers].dup
65
-
66
- if @data[:scheme] == HTTPS && (ENV.has_key?('https_proxy') || ENV.has_key?('HTTPS_PROXY'))
67
- @data[:proxy] = setup_proxy(ENV['https_proxy'] || ENV['HTTPS_PROXY'])
68
- elsif (ENV.has_key?('http_proxy') || ENV.has_key?('HTTP_PROXY'))
69
- @data[:proxy] = setup_proxy(ENV['http_proxy'] || ENV['HTTP_PROXY'])
70
- elsif @data.has_key?(:proxy)
71
- @data[:proxy] = setup_proxy(@data[:proxy])
72
- end
73
-
74
- if @data[:proxy]
75
- @data[:headers]['Proxy-Connection'] ||= 'Keep-Alive'
76
- # https credentials happen in handshake
77
- if @data[:scheme] == 'http' && (@data[:proxy][:user] || @data[:proxy][:password])
78
- auth = ['' << @data[:proxy][:user].to_s << ':' << @data[:proxy][:password].to_s].pack('m').delete(Excon::CR_NL)
79
- @data[:headers]['Proxy-Authorization'] = 'Basic ' << auth
80
- end
81
- end
82
-
83
- if ENV.has_key?('EXCON_DEBUG') || ENV.has_key?('EXCON_STANDARD_INSTRUMENTOR')
84
- @data[:instrumentor] = Excon::StandardInstrumentor
85
- end
86
-
87
- # Use Basic Auth if url contains a login
88
- if uri.user || uri.password
89
- @data[:headers]['Authorization'] ||= 'Basic ' << ['' << uri.user.to_s << ':' << uri.password.to_s].pack('m').delete(Excon::CR_NL)
90
- end
91
-
92
- @socket_key = '' << @data[:host] << ':' << @data[:port]
93
- reset
94
- end
95
-
96
- def request_call(datum)
97
- begin
98
- if datum.has_key?(:response)
99
- # we already have data from a middleware, so bail
100
- return datum
101
- else
102
- socket.data = datum
103
- # start with "METHOD /path"
104
- request = datum[:method].to_s.upcase << ' '
105
- if @data[:proxy]
106
- request << datum[:scheme] << '://' << @data[:host] << ':' << @data[:port].to_s
107
- end
108
- request << datum[:path]
109
-
110
- # add query to path, if there is one
111
- case datum[:query]
112
- when String
113
- request << '?' << datum[:query]
114
- when Hash
115
- request << '?'
116
- datum[:query].each do |key, values|
117
- if values.nil?
118
- request << key.to_s << '&'
119
- else
120
- [values].flatten.each do |value|
121
- request << key.to_s << '=' << CGI.escape(value.to_s) << '&'
122
- end
123
- end
124
- end
125
- request.chop! # remove trailing '&'
126
- end
127
-
128
- # finish first line with "HTTP/1.1\r\n"
129
- request << HTTP_1_1
130
-
131
- if datum.has_key?(:request_block)
132
- datum[:headers]['Transfer-Encoding'] = 'chunked'
133
- elsif ! (datum[:method].to_s.casecmp('GET') == 0 && datum[:body].nil?)
134
- # The HTTP spec isn't clear on it, but specifically, GET requests don't usually send bodies;
135
- # if they don't, sending Content-Length:0 can cause issues.
136
- datum[:headers]['Content-Length'] = detect_content_length(datum[:body])
137
- end
138
-
139
- # add headers to request
140
- datum[:headers].each do |key, values|
141
- [values].flatten.each do |value|
142
- request << key.to_s << ': ' << value.to_s << CR_NL
143
- end
144
- end
145
-
146
- # add additional "\r\n" to indicate end of headers
147
- request << CR_NL
148
-
149
- # write out the request, sans body
150
- socket.write(request)
151
-
152
- # write out the body
153
- if datum.has_key?(:request_block)
154
- while true
155
- chunk = datum[:request_block].call
156
- if FORCE_ENC
157
- chunk.force_encoding('BINARY')
158
- end
159
- if chunk.length > 0
160
- socket.write(chunk.length.to_s(16) << CR_NL << chunk << CR_NL)
161
- else
162
- socket.write('0' << CR_NL << CR_NL)
163
- break
164
- end
165
- end
166
- elsif !datum[:body].nil?
167
- if datum[:body].is_a?(String)
168
- unless datum[:body].empty?
169
- socket.write(datum[:body])
170
- end
171
- else
172
- if datum[:body].respond_to?(:binmode)
173
- datum[:body].binmode
174
- end
175
- if datum[:body].respond_to?(:pos=)
176
- datum[:body].pos = 0
177
- end
178
- while chunk = datum[:body].read(datum[:chunk_size])
179
- socket.write(chunk)
180
- end
181
- end
182
- end
183
- end
184
- rescue => error
185
- case error
186
- when Excon::Errors::StubNotFound, Excon::Errors::Timeout
187
- raise(error)
188
- else
189
- raise(Excon::Errors::SocketError.new(error))
190
- end
191
- end
192
-
193
- datum
194
- end
195
-
196
- def response_call(datum)
197
- datum
198
- end
199
-
200
- # Sends the supplied request to the destination host.
201
- # @yield [chunk] @see Response#self.parse
202
- # @param [Hash<Symbol, >] params One or more optional params, override defaults set in Connection.new
203
- # @option params [String] :body text to be sent over a socket
204
- # @option params [Hash<Symbol, String>] :headers The default headers to supply in a request
205
- # @option params [String] :host The destination host's reachable DNS name or IP, in the form of a String
206
- # @option params [String] :path appears after 'scheme://host:port/'
207
- # @option params [Fixnum] :port The port on which to connect, to the destination host
208
- # @option params [Hash] :query appended to the 'scheme://host:port/path/' in the form of '?key=value'
209
- # @option params [String] :scheme The protocol; 'https' causes OpenSSL to be used
210
- def request(params, &block)
211
- # @data has defaults, merge in new params to override
212
- datum = @data.merge(params)
213
- assert_valid_keys_for_argument!(params, VALID_CONNECTION_KEYS)
214
- datum[:headers] = @data[:headers].merge(datum[:headers] || {})
215
- datum[:headers]['Host'] ||= '' << datum[:host] << ':' << datum[:port]
216
- datum[:retries_remaining] ||= datum[:retry_limit]
217
-
218
- # if path is empty or doesn't start with '/', insert one
219
- unless datum[:path][0, 1] == '/'
220
- datum[:path].insert(0, '/')
221
- end
222
-
223
- if block_given?
224
- $stderr.puts("Excon requests with a block are deprecated, pass :response_block instead (#{caller.first})")
225
- datum[:response_block] = Proc.new
226
- end
227
-
228
- datum[:connection] = self
229
-
230
- datum[:stack] = datum[:middlewares].map do |middleware|
231
- lambda {|stack| middleware.new(stack)}
232
- end.reverse.inject(self) do |middlewares, middleware|
233
- middleware.call(middlewares)
234
- end
235
- datum = datum[:stack].request_call(datum)
236
-
237
- unless datum[:pipeline]
238
- datum = response(datum)
239
-
240
- if datum[:response][:headers]['Connection'] == 'close'
241
- reset
242
- end
243
-
244
- Excon::Response.new(datum[:response])
245
- else
246
- datum
247
- end
248
- rescue => request_error
249
- reset
250
- if datum[:idempotent] && [Excon::Errors::Timeout, Excon::Errors::SocketError,
251
- Excon::Errors::HTTPStatusError].any? {|ex| request_error.kind_of? ex } && datum[:retries_remaining] > 1
252
- datum[:retries_remaining] -= 1
253
- request(datum, &block)
254
- else
255
- if datum.has_key?(:instrumentor)
256
- datum[:instrumentor].instrument("#{datum[:instrumentor_name]}.error", :error => request_error)
257
- end
258
- raise(request_error)
259
- end
260
- end
261
-
262
- # Sends the supplied requests to the destination host using pipelining.
263
- # @pipeline_params [Array<Hash>] pipeline_params An array of one or more optional params, override defaults set in Connection.new, see #request for details
264
- def requests(pipeline_params)
265
- pipeline_params.map do |params|
266
- request(params.merge!(:pipeline => true))
267
- end.map do |datum|
268
- Excon::Response.new(response(datum)[:response])
269
- end
270
- end
271
-
272
- def reset
273
- (old_socket = sockets.delete(@socket_key)) && old_socket.close
274
- end
275
-
276
- # Generate HTTP request verb methods
277
- Excon::HTTP_VERBS.each do |method|
278
- class_eval <<-DEF, __FILE__, __LINE__ + 1
279
- def #{method}(params={}, &block)
280
- request(params.merge!(:method => :#{method}), &block)
281
- end
282
- DEF
283
- end
284
-
285
- def retry_limit=(new_retry_limit)
286
- $stderr.puts("Excon::Connection#retry_limit= is deprecated, pass :retry_limit to the initializer (#{caller.first})")
287
- @data[:retry_limit] = new_retry_limit
288
- end
289
-
290
- def retry_limit
291
- $stderr.puts("Excon::Connection#retry_limit is deprecated, pass :retry_limit to the initializer (#{caller.first})")
292
- @data[:retry_limit] ||= DEFAULT_RETRY_LIMIT
293
- end
294
-
295
- def inspect
296
- vars = instance_variables.inject({}) do |accum, var|
297
- accum.merge!(var.to_sym => instance_variable_get(var))
298
- end
299
- if vars[:'@data'][:headers].has_key?('Authorization')
300
- vars[:'@data'] = vars[:'@data'].dup
301
- vars[:'@data'][:headers] = vars[:'@data'][:headers].dup
302
- vars[:'@data'][:headers]['Authorization'] = REDACTED
303
- end
304
- inspection = '#<Excon::Connection:'
305
- inspection << (object_id << 1).to_s(16)
306
- vars.each do |key, value|
307
- inspection << ' ' << key.to_s << '=' << value.inspect
308
- end
309
- inspection << '>'
310
- inspection
311
- end
312
-
313
- private
314
-
315
- def detect_content_length(body)
316
- if body.is_a?(String)
317
- if FORCE_ENC
318
- body.force_encoding('BINARY')
319
- end
320
- body.length
321
- elsif body.respond_to?(:size)
322
- # IO object: File, Tempfile, etc.
323
- body.size
324
- else
325
- begin
326
- File.size(body) # for 1.8.7 where file does not have size
327
- rescue
328
- 0
329
- end
330
- end
331
- end
332
-
333
- def response(datum={})
334
- unless datum.has_key?(:response)
335
- datum[:response] = {
336
- :body => '',
337
- :headers => {},
338
- :status => socket.read(12)[9, 11].to_i,
339
- :remote_ip => socket.remote_ip
340
- }
341
- socket.readline # read the rest of the status line and CRLF
342
-
343
- until ((data = socket.readline).chop!).empty?
344
- key, value = data.split(/:\s*/, 2)
345
- datum[:response][:headers][key] = ([*datum[:response][:headers][key]] << value).compact.join(', ')
346
- if key.casecmp('Content-Length') == 0
347
- content_length = value.to_i
348
- elsif (key.casecmp('Transfer-Encoding') == 0) && (value.casecmp('chunked') == 0)
349
- transfer_encoding_chunked = true
350
- end
351
- end
352
-
353
- unless (['HEAD', 'CONNECT'].include?(datum[:method].to_s.upcase)) || NO_ENTITY.include?(datum[:response][:status])
354
-
355
- # check to see if expects was set and matched
356
- expected_status = !datum.has_key?(:expects) || [*datum[:expects]].include?(datum[:response][:status])
357
-
358
- # if expects matched and there is a block, use it
359
- if expected_status && datum.has_key?(:response_block)
360
- if transfer_encoding_chunked
361
- # 2 == "/r/n".length
362
- while (chunk_size = socket.readline.chop!.to_i(16)) > 0
363
- datum[:response_block].call(socket.read(chunk_size + 2).chop!, nil, nil)
364
- end
365
- socket.read(2)
366
- elsif remaining = content_length
367
- while remaining > 0
368
- datum[:response_block].call(socket.read([datum[:chunk_size], remaining].min), [remaining - datum[:chunk_size], 0].max, content_length)
369
- remaining -= datum[:chunk_size]
370
- end
371
- else
372
- while remaining = socket.read(datum[:chunk_size])
373
- datum[:response_block].call(remaining, remaining.length, content_length)
374
- end
375
- end
376
- else # no block or unexpected status
377
- if transfer_encoding_chunked
378
- while (chunk_size = socket.readline.chop!.to_i(16)) > 0
379
- datum[:response][:body] << socket.read(chunk_size + 2).chop! # 2 == "/r/n".length
380
- end
381
- socket.read(2) # 2 == "/r/n".length
382
- elsif remaining = content_length
383
- while remaining > 0
384
- datum[:response][:body] << socket.read([datum[:chunk_size], remaining].min)
385
- remaining -= datum[:chunk_size]
386
- end
387
- else
388
- datum[:response][:body] << socket.read
389
- end
390
- end
391
- end
392
- end
393
-
394
- datum[:stack].response_call(datum)
395
- rescue => error
396
- case error
397
- when Excon::Errors::HTTPStatusError, Excon::Errors::Timeout
398
- raise(error)
399
- else
400
- raise(Excon::Errors::SocketError.new(error))
401
- end
402
- end
403
-
404
- def socket
405
- sockets[@socket_key] ||= if @data[:scheme] == HTTPS
406
- Excon::SSLSocket.new(@data)
407
- else
408
- Excon::Socket.new(@data)
409
- end
410
- end
411
-
412
- def sockets
413
- Thread.current[:_excon_sockets] ||= {}
414
- end
415
-
416
- def setup_proxy(proxy)
417
- case proxy
418
- when String
419
- uri = URI.parse(proxy)
420
- unless uri.host and uri.port and uri.scheme
421
- raise Excon::Errors::ProxyParseError, "Proxy is invalid"
422
- end
423
- {
424
- :host => uri.host,
425
- :password => uri.password,
426
- :port => uri.port.to_s,
427
- :scheme => uri.scheme,
428
- :user => uri.user
429
- }
430
- else
431
- proxy
432
- end
433
- end
434
-
435
- end
436
- end
437
- end
438
- end
@@ -1,50 +0,0 @@
1
- module Skylight
2
- module Vendor
3
- module Excon
4
-
5
- CR_NL = "\r\n"
6
-
7
- DEFAULT_CA_FILE = File.expand_path("../cacert.pem", __FILE__)
8
-
9
- DEFAULT_CHUNK_SIZE = 1048576 # 1 megabyte
10
-
11
- # avoid overwrite if somebody has redefined
12
- unless const_defined?(:CHUNK_SIZE)
13
- CHUNK_SIZE = DEFAULT_CHUNK_SIZE
14
- end
15
-
16
- DEFAULT_NONBLOCK = OpenSSL::SSL::SSLSocket.public_method_defined?(:connect_nonblock) &&
17
- OpenSSL::SSL::SSLSocket.public_method_defined?(:read_nonblock) &&
18
- OpenSSL::SSL::SSLSocket.public_method_defined?(:write_nonblock)
19
-
20
- DEFAULT_RETRY_LIMIT = 4
21
-
22
- FORCE_ENC = CR_NL.respond_to?(:force_encoding)
23
-
24
- HTTP_1_1 = " HTTP/1.1\r\n"
25
-
26
- HTTP_VERBS = %w{connect delete get head options post put trace patch}
27
-
28
- HTTPS = 'https'
29
-
30
- NO_ENTITY = [204, 205, 304].freeze
31
-
32
- REDACTED = 'REDACTED'
33
-
34
- VERSION = '0.18.5'
35
-
36
- unless ::IO.const_defined?(:WaitReadable)
37
- class ::IO
38
- module WaitReadable; end
39
- end
40
- end
41
-
42
- unless ::IO.const_defined?(:WaitWritable)
43
- class ::IO
44
- module WaitWritable; end
45
- end
46
- end
47
-
48
- end
49
- end
50
- end