skylight 0.0.5 → 0.0.6

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.
@@ -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