123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- require 'faraday'
- require 'faraday_middleware'
- module WebRequestConcern
- module DoNotEncoder
- def self.encode(params)
- params.map do |key, value|
- value.nil? ? "#{key}" : "#{key}=#{value}"
- end.join('&')
- end
- def self.decode(val)
- [val]
- end
- end
- class CharacterEncoding < Faraday::Middleware
- def initialize(app, force_encoding: nil, default_encoding: nil, unzip: nil)
- super(app)
- @force_encoding = force_encoding
- @default_encoding = default_encoding
- @unzip = unzip
- end
- def call(env)
- @app.call(env).on_complete do |env|
- body = env[:body]
- case @unzip
- when 'gzip'.freeze
- body.replace(ActiveSupport::Gzip.decompress(body))
- end
- case
- when @force_encoding
- encoding = @force_encoding
- when body.encoding == Encoding::ASCII_8BIT
- # Not all Faraday adapters support automatic charset
- # detection, so we do that.
- case env[:response_headers][:content_type]
- when /;\s*charset\s*=\s*([^()<>@,;:\\\"\/\[\]?={}\s]+)/i
- encoding = Encoding.find($1) rescue nil
- when /\A\s*(?:text\/[^\s;]+|application\/(?:[^\s;]+\+)?(?:xml|json))\s*(?:;|\z)/i
- encoding = @default_encoding
- else
- # Never try to transcode a binary content
- next
- end
- end
- body.encode!(Encoding::UTF_8, encoding) unless body.encoding == Encoding::UTF_8
- end
- end
- end
- Faraday::Response.register_middleware character_encoding: CharacterEncoding
- extend ActiveSupport::Concern
- def validate_web_request_options!
- if options['user_agent'].present?
- errors.add(:base, "user_agent must be a string") unless options['user_agent'].is_a?(String)
- end
- if options['disable_ssl_verification'].present? && boolify(options['disable_ssl_verification']).nil?
- errors.add(:base, "if provided, disable_ssl_verification must be true or false")
- end
- unless headers(options['headers']).is_a?(Hash)
- errors.add(:base, "if provided, headers must be a hash")
- end
- begin
- basic_auth_credentials(options['basic_auth'])
- rescue ArgumentError => e
- errors.add(:base, e.message)
- end
- if (encoding = options['force_encoding']).present?
- case encoding
- when String
- begin
- Encoding.find(encoding)
- rescue ArgumentError
- errors.add(:base, "Unknown encoding: #{encoding.inspect}")
- end
- else
- errors.add(:base, "force_encoding must be a string")
- end
- end
- end
- def default_encoding
- Encoding::UTF_8
- end
- def faraday
- faraday_options = {
- ssl: {
- verify: !boolify(options['disable_ssl_verification'])
- }
- }
- @faraday ||= Faraday.new(faraday_options) { |builder|
- builder.response :character_encoding,
- force_encoding: interpolated['force_encoding'].presence,
- default_encoding: default_encoding,
- unzip: interpolated['unzip'].presence
- builder.headers = headers if headers.length > 0
- builder.headers[:user_agent] = user_agent
- builder.use FaradayMiddleware::FollowRedirects
- builder.request :url_encoded
- if boolify(interpolated['disable_url_encoding'])
- builder.options.params_encoder = DoNotEncoder
- end
- if userinfo = basic_auth_credentials
- builder.request :basic_auth, *userinfo
- end
- builder.use FaradayMiddleware::Gzip
- case backend = faraday_backend
- when :typhoeus
- require 'typhoeus/adapters/faraday'
- end
- builder.adapter backend
- }
- end
- def headers(value = interpolated['headers'])
- value.presence || {}
- end
- def basic_auth_credentials(value = interpolated['basic_auth'])
- case value
- when nil, ''
- return nil
- when Array
- return value if value.size == 2
- when /:/
- return value.split(/:/, 2)
- end
- raise ArgumentError.new("bad value for basic_auth: #{value.inspect}")
- end
- def faraday_backend
- ENV.fetch('FARADAY_HTTP_BACKEND', 'typhoeus').to_sym
- end
- def user_agent
- interpolated['user_agent'].presence || self.class.default_user_agent
- end
- module ClassMethods
- def default_user_agent
- ENV.fetch('DEFAULT_HTTP_USER_AGENT', "Huginn - https://github.com/cantino/huginn")
- end
- end
- end
|