class Twingly::HTTP::Client
Constants
- DEFAULT_FOLLOW_REDIRECTS_LIMIT
- DEFAULT_HTTP_OPEN_TIMEOUT
- DEFAULT_HTTP_TIMEOUT
- DEFAULT_MAX_URL_SIZE_BYTES
- DEFAULT_NUMBER_OF_RETRIES
- DEFAULT_RETRYABLE_EXCEPTIONS
- DEFAULT_RETRY_INTERVAL
- TIMEOUT_EXCEPTIONS
Attributes
follow_redirects[W]
follow_redirects_limit[RW]
http_open_timeout[W]
http_timeout[W]
logger[RW]
max_url_size_bytes[W]
number_of_retries[W]
on_retry_callback[W]
request_id[W]
retry_interval[W]
retryable_exceptions[RW]
Public Class Methods
new(base_user_agent:, logger: default_logger)
click to toggle source
# File lib/twingly/http.rb, line 49 def initialize(base_user_agent:, logger: default_logger) @base_user_agent = base_user_agent @logger = logger initialize_defaults end
Public Instance Methods
get(url, params: {}, headers: {})
click to toggle source
# File lib/twingly/http.rb, line 56 def get(url, params: {}, headers: {}) http_response_for(:get, url: url, params: params, headers: headers) end
post(url, body:, headers: {})
click to toggle source
# File lib/twingly/http.rb, line 60 def post(url, body:, headers: {}) http_response_for(:post, url: url, body: body, headers: headers) end
Private Instance Methods
app_metadata()
click to toggle source
# File lib/twingly/http.rb, line 192 def app_metadata { "dyno_id": Heroku.dyno_id, "release": Heroku.release_version, "git_head": Heroku.slug_commit, } end
create_http_client()
click to toggle source
# File lib/twingly/http.rb, line 134 def create_http_client # rubocop:disable Metrics/MethodLength Faraday.new do |faraday| faraday.request :url_size_limit, max_size_bytes: @max_url_size_bytes faraday.request :retry, max: @number_of_retries, interval: @retry_interval, exceptions: @retryable_exceptions, methods: [], # empty [] forces Faraday to run retry_if retry_if: retry_if faraday.response :logfmt_logger, @logger.dup, headers: true, bodies: true, request_id: @request_id if @follow_redirects faraday.use FaradayMiddleware::FollowRedirects, limit: @follow_redirects_limit end faraday.adapter Faraday.default_adapter faraday.headers[:user_agent] = user_agent end end
default_headers()
click to toggle source
# File lib/twingly/http.rb, line 200 def default_headers { "X-Request-Id": @request_id, }.delete_if { |_name, value| value.to_s.strip.empty? } end
default_logger()
click to toggle source
# File lib/twingly/http.rb, line 66 def default_logger Logger.new(File::NULL) end
http_get_response(url:, params:, headers:)
click to toggle source
rubocop:enable all
# File lib/twingly/http.rb, line 104 def http_get_response(url:, params:, headers:) binary_url = url.dup.force_encoding(Encoding::BINARY) http_client = create_http_client headers = default_headers.merge(headers) http_client.get do |request| request.url(binary_url) request.params.merge!(params) request.headers.merge!(headers) request.options.timeout = @http_timeout request.options.open_timeout = @http_open_timeout end end
http_post_response(url:, body:, headers:)
click to toggle source
# File lib/twingly/http.rb, line 119 def http_post_response(url:, body:, headers:) binary_url = url.dup.force_encoding(Encoding::BINARY) http_client = create_http_client headers = default_headers.merge(headers) http_client.post do |request| request.url(binary_url) request.headers.merge!(headers) request.body = body request.options.timeout = @http_timeout request.options.open_timeout = @http_open_timeout end end
http_response_for(method, **args)
click to toggle source
rubocop:disable Metrics/MethodLength
# File lib/twingly/http.rb, line 84 def http_response_for(method, **args) response = case method when :get http_get_response(**args) when :post http_post_response(**args) end Response.new(headers: response.headers.to_h, status: response.status, body: response.body) rescue *(@retryable_exceptions + TIMEOUT_EXCEPTIONS) raise ConnectionError rescue Faraday::UrlSizeLimit::LimitExceededError => error raise UrlSizeLimitExceededError, error.message rescue FaradayMiddleware::RedirectLimitReached => error raise RedirectLimitReachedError, error.message end
initialize_defaults()
click to toggle source
# File lib/twingly/http.rb, line 70 def initialize_defaults @request_id = nil @http_timeout = DEFAULT_HTTP_TIMEOUT @http_open_timeout = DEFAULT_HTTP_OPEN_TIMEOUT @retryable_exceptions = DEFAULT_RETRYABLE_EXCEPTIONS @number_of_retries = DEFAULT_NUMBER_OF_RETRIES @retry_interval = DEFAULT_RETRY_INTERVAL @on_retry_callback = nil @follow_redirects = false @follow_redirects_limit = DEFAULT_FOLLOW_REDIRECTS_LIMIT @max_url_size_bytes = DEFAULT_MAX_URL_SIZE_BYTES end
retry_if()
click to toggle source
# File lib/twingly/http.rb, line 157 def retry_if lambda do |env, exception| unwrapped_exception = unwrap_exception(exception) # we do not retry on timeouts due to our request time budget if timeout_error?(unwrapped_exception) false else @on_retry_callback&.call(env, unwrapped_exception) true end end end
timeout_error?(error)
click to toggle source
# File lib/twingly/http.rb, line 179 def timeout_error?(error) TIMEOUT_EXCEPTIONS.include?(error.class) end
unwrap_exception(exception)
click to toggle source
# File lib/twingly/http.rb, line 171 def unwrap_exception(exception) if exception.respond_to?(:wrapped_exception) exception.wrapped_exception else exception end end
user_agent()
click to toggle source
# File lib/twingly/http.rb, line 183 def user_agent format( "%<base>s (Release/%<release>s; Commit/%<commit>s)", base: @base_user_agent, release: Heroku.release_version, commit: Heroku.slug_commit ) end