]> git.donarmstrong.com Git - dsa-puppet.git/blob - 3rdparty/modules/aviator/feature/faraday/connection.rb
add aimonb/aviator to 3rdparty
[dsa-puppet.git] / 3rdparty / modules / aviator / feature / faraday / connection.rb
1 module Faraday
2   # Public: Connection objects manage the default properties and the middleware
3   # stack for fulfilling an HTTP request.
4   #
5   # Examples
6   #
7   #   conn = Faraday::Connection.new 'http://sushi.com'
8   #
9   #   # GET http://sushi.com/nigiri
10   #   conn.get 'nigiri'
11   #   # => #<Faraday::Response>
12   #
13   class Connection
14     # A Set of allowed HTTP verbs.
15     METHODS = Set.new [:get, :post, :put, :delete, :head, :patch, :options]
16
17     # Public: Returns a Hash of URI query unencoded key/value pairs.
18     attr_reader :params
19
20     # Public: Returns a Hash of unencoded HTTP header key/value pairs.
21     attr_reader :headers
22
23     # Public: Returns a URI with the prefix used for all requests from this
24     # Connection.  This includes a default host name, scheme, port, and path.
25     attr_reader :url_prefix
26
27     # Public: Returns the Faraday::Builder for this Connection.
28     attr_reader :builder
29
30     # Public: Returns a Hash of the request options.
31     attr_reader :options
32
33     # Public: Returns a Hash of the SSL options.
34     attr_reader :ssl
35
36     # Public: Returns the parallel manager for this Connection.
37     attr_reader :parallel_manager
38
39     # Public: Sets the default parallel manager for this connection.
40     attr_writer :default_parallel_manager
41
42     # Public: Initializes a new Faraday::Connection.
43     #
44     # url     - URI or String base URL to use as a prefix for all
45     #           requests (optional).
46     # options - Hash or Faraday::ConnectionOptions.
47     #           :url     - URI or String base URL (default: "http:/").
48     #           :params  - Hash of URI query unencoded key/value pairs.
49     #           :headers - Hash of unencoded HTTP header key/value pairs.
50     #           :request - Hash of request options.
51     #           :ssl     - Hash of SSL options.
52     #           :proxy   - URI, String or Hash of HTTP proxy options
53     #                     (default: "http_proxy" environment variable).
54     #                     :uri      - URI or String
55     #                     :user     - String (optional)
56     #                     :password - String (optional)
57     def initialize(url = nil, options = nil)
58       if url.is_a?(Hash)
59         options = ConnectionOptions.from(url)
60         url     = options.url
61       else
62         options = ConnectionOptions.from(options)
63       end
64
65       @parallel_manager = nil
66       @headers = Utils::Headers.new
67       @params  = Utils::ParamsHash.new
68       @options = options.request
69       @ssl = options.ssl
70       @default_parallel_manager = options.parallel_manager
71
72       @builder = options.builder || begin
73         # pass an empty block to Builder so it doesn't assume default middleware
74         options.new_builder(block_given? ? Proc.new { |b| } : nil)
75       end
76
77       self.url_prefix = url || 'http:/'
78
79       @params.update(options.params)   if options.params
80       @headers.update(options.headers) if options.headers
81
82       @proxy = nil
83       proxy(options.fetch(:proxy) {
84         uri = ENV['http_proxy']
85         if uri && !uri.empty?
86           uri = 'http://' + uri if uri !~ /^http/i
87           uri
88         end
89       })
90
91       yield(self) if block_given?
92
93       @headers[:user_agent] ||= "Faraday v#{VERSION}"
94     end
95
96     # Public: Sets the Hash of URI query unencoded key/value pairs.
97     def params=(hash)
98       @params.replace hash
99     end
100
101     # Public: Sets the Hash of unencoded HTTP header key/value pairs.
102     def headers=(hash)
103       @headers.replace hash
104     end
105
106     extend Forwardable
107
108     def_delegators :builder, :build, :use, :request, :response, :adapter, :app
109
110     # Public: Makes an HTTP request without a body.
111     #
112     # url     - The optional String base URL to use as a prefix for all
113     #           requests.  Can also be the options Hash.
114     # params  - Hash of URI query unencoded key/value pairs.
115     # headers - Hash of unencoded HTTP header key/value pairs.
116     #
117     # Examples
118     #
119     #   conn.get '/items', {:page => 1}, :accept => 'application/json'
120     #   conn.head '/items/1'
121     #
122     #   # ElasticSearch example sending a body with GET.
123     #   conn.get '/twitter/tweet/_search' do |req|
124     #     req.headers[:content_type] = 'application/json'
125     #     req.params[:routing] = 'kimchy'
126     #     req.body = JSON.generate(:query => {...})
127     #   end
128     #
129     # Yields a Faraday::Response for further request customizations.
130     # Returns a Faraday::Response.
131     #
132     # Signature
133     #
134     #   <verb>(url = nil, params = nil, headers = nil)
135     #
136     # verb - An HTTP verb: get, head, or delete.
137     %w[get head delete].each do |method|
138       class_eval <<-RUBY, __FILE__, __LINE__ + 1
139         def #{method}(url = nil, params = nil, headers = nil)
140           run_request(:#{method}, url, nil, headers) { |request|
141             request.params.update(params) if params
142             yield(request) if block_given?
143           }
144         end
145       RUBY
146     end
147
148     # Public: Makes an HTTP request with a body.
149     #
150     # url     - The optional String base URL to use as a prefix for all
151     #           requests.  Can also be the options Hash.
152     # body    - The String body for the request.
153     # headers - Hash of unencoded HTTP header key/value pairs.
154     #
155     # Examples
156     #
157     #   conn.post '/items', data, :content_type => 'application/json'
158     #
159     #   # Simple ElasticSearch indexing sample.
160     #   conn.post '/twitter/tweet' do |req|
161     #     req.headers[:content_type] = 'application/json'
162     #     req.params[:routing] = 'kimchy'
163     #     req.body = JSON.generate(:user => 'kimchy', ...)
164     #   end
165     #
166     # Yields a Faraday::Response for further request customizations.
167     # Returns a Faraday::Response.
168     #
169     # Signature
170     #
171     #   <verb>(url = nil, body = nil, headers = nil)
172     #
173     # verb - An HTTP verb: post, put, or patch.
174     %w[post put patch].each do |method|
175       class_eval <<-RUBY, __FILE__, __LINE__ + 1
176         def #{method}(url = nil, body = nil, headers = nil, &block)
177           run_request(:#{method}, url, body, headers, &block)
178         end
179       RUBY
180     end
181
182     # Public: Sets up the Authorization header with these credentials, encoded
183     # with base64.
184     #
185     # login - The authentication login.
186     # pass  - The authentication password.
187     #
188     # Examples
189     #
190     #   conn.basic_auth 'Aladdin', 'open sesame'
191     #   conn.headers['Authorization']
192     #   # => "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
193     #
194     # Returns nothing.
195     def basic_auth(login, pass)
196       set_authorization_header(:basic_auth, login, pass)
197     end
198
199     # Public: Sets up the Authorization header with the given token.
200     #
201     # token   - The String token.
202     # options - Optional Hash of extra token options.
203     #
204     # Examples
205     #
206     #   conn.token_auth 'abcdef', :foo => 'bar'
207     #   conn.headers['Authorization']
208     #   # => "Token token=\"abcdef\",
209     #               foo=\"bar\""
210     #
211     # Returns nothing.
212     def token_auth(token, options = nil)
213       set_authorization_header(:token_auth, token, options)
214     end
215
216     # Public: Sets up a custom Authorization header.
217     #
218     # type  - The String authorization type.
219     # token - The String or Hash token.  A String value is taken literally, and
220     #         a Hash is encoded into comma separated key/value pairs.
221     #
222     # Examples
223     #
224     #   conn.authorization :Bearer, 'mF_9.B5f-4.1JqM'
225     #   conn.headers['Authorization']
226     #   # => "Bearer mF_9.B5f-4.1JqM"
227     #
228     #   conn.authorization :Token, :token => 'abcdef', :foo => 'bar'
229     #   conn.headers['Authorization']
230     #   # => "Token token=\"abcdef\",
231     #               foo=\"bar\""
232     #
233     # Returns nothing.
234     def authorization(type, token)
235       set_authorization_header(:authorization, type, token)
236     end
237
238     # Internal: Traverse the middleware stack in search of a
239     # parallel-capable adapter.
240     #
241     # Yields in case of not found.
242     #
243     # Returns a parallel manager or nil if not found.
244     def default_parallel_manager
245       @default_parallel_manager ||= begin
246         handler = @builder.handlers.detect do |h|
247           h.klass.respond_to?(:supports_parallel?) and h.klass.supports_parallel?
248         end
249
250         if handler
251           handler.klass.setup_parallel_manager
252         elsif block_given?
253           yield
254         end
255       end
256     end
257
258     # Public: Determine if this Faraday::Connection can make parallel requests.
259     #
260     # Returns true or false.
261     def in_parallel?
262       !!@parallel_manager
263     end
264
265     # Public: Sets up the parallel manager to make a set of requests.
266     #
267     # manager - The parallel manager that this Connection's Adapter uses.
268     #
269     # Yields a block to execute multiple requests.
270     # Returns nothing.
271     def in_parallel(manager = nil)
272       @parallel_manager = manager || default_parallel_manager {
273         warn "Warning: `in_parallel` called but no parallel-capable adapter on Faraday stack"
274         warn caller[2,10].join("\n")
275         nil
276       }
277       yield
278       @parallel_manager && @parallel_manager.run
279     ensure
280       @parallel_manager = nil
281     end
282
283     # Public: Gets or Sets the Hash proxy options.
284     def proxy(arg = nil)
285       return @proxy if arg.nil?
286       @proxy = ProxyOptions.from(arg)
287     end
288
289     def_delegators :url_prefix, :scheme, :scheme=, :host, :host=, :port, :port=
290     def_delegator :url_prefix, :path, :path_prefix
291
292     # Public: Parses the giving url with URI and stores the individual
293     # components in this connection.  These components serve as defaults for
294     # requests made by this connection.
295     #
296     # url - A String or URI.
297     #
298     # Examples
299     #
300     #   conn = Faraday::Connection.new { ... }
301     #   conn.url_prefix = "https://sushi.com/api"
302     #   conn.scheme      # => https
303     #   conn.path_prefix # => "/api"
304     #
305     #   conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri
306     #
307     # Returns the parsed URI from teh given input..
308     def url_prefix=(url, encoder = nil)
309       uri = @url_prefix = Utils.URI(url)
310       self.path_prefix = uri.path
311
312       params.merge_query(uri.query, encoder)
313       uri.query = nil
314
315       with_uri_credentials(uri) do |user, password|
316         basic_auth user, password
317         uri.user = uri.password = nil
318       end
319
320       uri
321     end
322
323     # Public: Sets the path prefix and ensures that it always has a leading
324     # slash.
325     #
326     # value - A String.
327     #
328     # Returns the new String path prefix.
329     def path_prefix=(value)
330       url_prefix.path = if value
331         value = '/' + value unless value[0,1] == '/'
332         value
333       end
334     end
335
336     # Public: Takes a relative url for a request and combines it with the defaults
337     # set on the connection instance.
338     #
339     #   conn = Faraday::Connection.new { ... }
340     #   conn.url_prefix = "https://sushi.com/api?token=abc"
341     #   conn.scheme      # => https
342     #   conn.path_prefix # => "/api"
343     #
344     #   conn.build_url("nigiri?page=2")      # => https://sushi.com/api/nigiri?token=abc&page=2
345     #   conn.build_url("nigiri", :page => 2) # => https://sushi.com/api/nigiri?token=abc&page=2
346     #
347     def build_url(url = nil, extra_params = nil)
348       uri = build_exclusive_url(url)
349
350       query_values = params.dup.merge_query(uri.query, options.params_encoder)
351       query_values.update extra_params if extra_params
352       uri.query = query_values.empty? ? nil : query_values.to_query(options.params_encoder)
353
354       uri
355     end
356
357     # Builds and runs the Faraday::Request.
358     #
359     # method  - The Symbol HTTP method.
360     # url     - The String or URI to access.
361     # body    - The String body
362     # headers - Hash of unencoded HTTP header key/value pairs.
363     #
364     # Returns a Faraday::Response.
365     def run_request(method, url, body, headers)
366       if !METHODS.include?(method)
367         raise ArgumentError, "unknown http method: #{method}"
368       end
369
370       request = build_request(method) do |req|
371         req.url(url)                if url
372         req.headers.update(headers) if headers
373         req.body = body             if body
374         yield(req) if block_given?
375       end
376
377       builder.build_response(self, request)
378     end
379
380     # Creates and configures the request object.
381     #
382     # Returns the new Request.
383     def build_request(method)
384       Request.create(method) do |req|
385         req.params  = self.params.dup
386         req.headers = self.headers.dup
387         req.options = self.options.merge(:proxy => self.proxy)
388         yield(req) if block_given?
389       end
390     end
391
392     # Internal: Build an absolute URL based on url_prefix.
393     #
394     # url    - A String or URI-like object
395     # params - A Faraday::Utils::ParamsHash to replace the query values
396     #          of the resulting url (default: nil).
397     #
398     # Returns the resulting URI instance.
399     def build_exclusive_url(url = nil, params = nil)
400       url = nil if url.respond_to?(:empty?) and url.empty?
401       base = url_prefix
402       if url and base.path and base.path !~ /\/$/
403         base = base.dup
404         base.path = base.path + '/'  # ensure trailing slash
405       end
406       uri = url ? base + url : base
407       uri.query = params.to_query(options.params_encoder) if params
408       uri.query = nil if uri.query and uri.query.empty?
409       uri
410     end
411
412     # Internal: Creates a duplicate of this Faraday::Connection.
413     #
414     # Returns a Faraday::Connection.
415     def dup
416       self.class.new(build_exclusive_url, :headers => headers.dup, :params => params.dup, :builder => builder.dup, :ssl => ssl.dup)
417     end
418
419     # Internal: Yields username and password extracted from a URI if they both exist.
420     def with_uri_credentials(uri)
421       if uri.user and uri.password
422         yield(Utils.unescape(uri.user), Utils.unescape(uri.password))
423       end
424     end
425
426     def set_authorization_header(header_type, *args)
427       header = Faraday::Request.lookup_middleware(header_type).
428         header(*args)
429       headers[Faraday::Request::Authorization::KEY] = header
430     end
431   end
432 end