mirror of
https://github.com/lostisland/faraday.git
synced 2025-10-16 00:03:37 -04:00
224 lines
6.2 KiB
Ruby
224 lines
6.2 KiB
Ruby
require 'addressable/uri'
|
|
require 'set'
|
|
require 'base64'
|
|
|
|
module Faraday
|
|
class Connection
|
|
include Addressable, Faraday::Utils
|
|
|
|
METHODS = Set.new [:get, :post, :put, :delete, :head]
|
|
METHODS_WITH_BODIES = Set.new [:post, :put]
|
|
|
|
attr_accessor :host, :port, :scheme, :params, :headers, :parallel_manager
|
|
attr_reader :path_prefix, :builder, :options, :ssl
|
|
|
|
# :url
|
|
# :params
|
|
# :headers
|
|
# :request
|
|
# :ssl
|
|
def initialize(url = nil, options = {}, &block)
|
|
if url.is_a?(Hash)
|
|
options = url
|
|
url = options[:url]
|
|
end
|
|
@headers = HeaderHash.new
|
|
@params = {}
|
|
@options = options[:request] || {}
|
|
@ssl = options[:ssl] || {}
|
|
@parallel_manager = options[:parallel]
|
|
self.url_prefix = url if url
|
|
proxy(options[:proxy])
|
|
merge_params @params, options[:params] if options[:params]
|
|
merge_headers @headers, options[:headers] if options[:headers]
|
|
|
|
if block
|
|
@builder = Builder.new
|
|
@builder.build { block.call(self) }
|
|
else
|
|
@builder = options[:builder] || Builder.new
|
|
end
|
|
end
|
|
|
|
def use(klass, *args, &block)
|
|
@builder.use(klass, *args, &block)
|
|
end
|
|
|
|
def request(key, *args, &block)
|
|
@builder.request(key, *args, &block)
|
|
end
|
|
|
|
def response(key, *args, &block)
|
|
@builder.response(key, *args, &block)
|
|
end
|
|
|
|
def adapter(key, *args, &block)
|
|
@builder.adapter(key, *args, &block)
|
|
end
|
|
|
|
def build(options = {}, &block)
|
|
@builder.build(options, &block)
|
|
end
|
|
|
|
def get(url = nil, headers = nil, &block)
|
|
run_request(:get, url, nil, headers, &block)
|
|
end
|
|
|
|
def post(url = nil, body = nil, headers = nil, &block)
|
|
run_request(:post, url, body, headers, &block)
|
|
end
|
|
|
|
def put(url = nil, body = nil, headers = nil, &block)
|
|
run_request(:put, url, body, headers, &block)
|
|
end
|
|
|
|
def head(url = nil, headers = nil, &block)
|
|
run_request(:head, url, nil, headers, &block)
|
|
end
|
|
|
|
def delete(url = nil, headers = nil, &block)
|
|
run_request(:delete, url, nil, headers, &block)
|
|
end
|
|
|
|
def basic_auth(login, pass)
|
|
@headers['authorization'] = "Basic #{Base64.encode64("#{login}:#{pass}").strip}"
|
|
end
|
|
|
|
def token_auth(token, options = {})
|
|
values = ["token=#{token.to_s.inspect}"]
|
|
options.each do |key, value|
|
|
values << "#{key}=#{value.to_s.inspect}"
|
|
end
|
|
# 21 = "Authorization: Token ".size
|
|
comma = ",\n#{' ' * 21}"
|
|
@headers['authorization'] = "Token #{values * comma}"
|
|
end
|
|
|
|
def in_parallel?
|
|
!!@parallel_manager
|
|
end
|
|
|
|
def in_parallel(manager)
|
|
@parallel_manager = manager
|
|
yield
|
|
@parallel_manager && @parallel_manager.run
|
|
ensure
|
|
@parallel_manager = nil
|
|
end
|
|
|
|
def proxy(arg = nil)
|
|
return @proxy if arg.nil?
|
|
|
|
@proxy =
|
|
case arg
|
|
when String then {:uri => proxy_arg_to_uri(arg)}
|
|
when URI then {:uri => arg}
|
|
when Hash then arg
|
|
if arg[:uri] = proxy_arg_to_uri(arg[:uri])
|
|
arg
|
|
else
|
|
raise ArgumentError, "no :uri option."
|
|
end
|
|
end
|
|
end
|
|
|
|
# Parses the giving url with Addressable::URI and stores the individual
|
|
# components in this connection. These components serve as defaults for
|
|
# requests made by this connection.
|
|
#
|
|
# conn = Faraday::Connection.new { ... }
|
|
# conn.url_prefix = "https://sushi.com/api"
|
|
# conn.scheme # => https
|
|
# conn.path_prefix # => "/api"
|
|
#
|
|
# conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri
|
|
#
|
|
def url_prefix=(url)
|
|
uri = URI.parse(url)
|
|
self.scheme = uri.scheme
|
|
self.host = uri.host
|
|
self.port = uri.port
|
|
self.path_prefix = uri.path
|
|
if uri.query && !uri.query.empty?
|
|
merge_params @params, parse_query(uri.query)
|
|
end
|
|
if uri.user && uri.password
|
|
basic_auth(uri.user, uri.password)
|
|
end
|
|
end
|
|
|
|
# Ensures that the path prefix always has a leading / and no trailing /
|
|
def path_prefix=(value)
|
|
if value
|
|
value.chomp! "/"
|
|
value.replace "/#{value}" if value !~ /^\//
|
|
end
|
|
@path_prefix = value
|
|
end
|
|
|
|
# return the assembled Rack application for this instance.
|
|
def to_app
|
|
@builder.to_app
|
|
end
|
|
|
|
def run_request(method, url, body, headers)
|
|
if !METHODS.include?(method)
|
|
raise ArgumentError, "unknown http method: #{method}"
|
|
end
|
|
|
|
Request.run(self, method) do |req|
|
|
req.url(url) if url
|
|
req.headers.update(headers) if headers
|
|
req.body = body if body
|
|
yield req if block_given?
|
|
end
|
|
end
|
|
|
|
# Takes a relative url for a request and combines it with the defaults
|
|
# set on the connection instance.
|
|
#
|
|
# conn = Faraday::Connection.new { ... }
|
|
# conn.url_prefix = "https://sushi.com/api?token=abc"
|
|
# conn.scheme # => https
|
|
# conn.path_prefix # => "/api"
|
|
#
|
|
# conn.build_url("nigiri?page=2") # => https://sushi.com/api/nigiri?token=abc&page=2
|
|
# conn.build_url("nigiri", :page => 2) # => https://sushi.com/api/nigiri?token=abc&page=2
|
|
#
|
|
def build_url(url, params = nil)
|
|
uri = URI.parse(url.to_s)
|
|
if @path_prefix && uri.path !~ /^\//
|
|
uri.path = "#{@path_prefix.size > 1 ? @path_prefix : nil}/#{uri.path}"
|
|
end
|
|
uri.host ||= @host
|
|
uri.port ||= @port
|
|
uri.scheme ||= @scheme
|
|
replace_query(uri, params)
|
|
uri
|
|
end
|
|
|
|
def dup
|
|
self.class.new(build_url(''), :headers => headers.dup, :params => params.dup, :builder => builder.dup)
|
|
end
|
|
|
|
def replace_query(uri, params)
|
|
url_params = @params.dup
|
|
if uri.query && !uri.query.empty?
|
|
merge_params(url_params, parse_query(uri.query))
|
|
end
|
|
if params && !params.empty?
|
|
merge_params(url_params, params)
|
|
end
|
|
uri.query = url_params.empty? ? nil : build_query(url_params)
|
|
uri
|
|
end
|
|
|
|
def proxy_arg_to_uri(arg)
|
|
case arg
|
|
when String then URI.parse(arg)
|
|
when URI then arg
|
|
end
|
|
end
|
|
end
|
|
end
|