Class: Gitlab::HTTP

Inherits:
Object
  • Object
show all
Includes:
HTTParty
Defined in:
lib/gitlab/http.rb

Direct Known Subclasses

Atlassian::JiraConnect::Client

Constant Summary collapse

BlockedUrlError =
Class.new(StandardError)
RedirectionTooDeep =
Class.new(StandardError)
ReadTotalTimeout =
Class.new(Net::ReadTimeout)
HeaderReadTimeout =
Class.new(Net::ReadTimeout)
SilentModeBlockedError =
Class.new(StandardError)
HTTP_TIMEOUT_ERRORS =
[
  Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout, Gitlab::HTTP::ReadTotalTimeout
].freeze
HTTP_ERRORS =
HTTP_TIMEOUT_ERRORS + [
  EOFError, SocketError, OpenSSL::SSL::SSLError, OpenSSL::OpenSSLError,
  Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH,
  Gitlab::HTTP::BlockedUrlError, Gitlab::HTTP::RedirectionTooDeep,
  Net::HTTPBadResponse
].freeze
DEFAULT_TIMEOUT_OPTIONS =
{
  open_timeout: 10,
  read_timeout: 20,
  write_timeout: 30
}.freeze
DEFAULT_READ_TOTAL_TIMEOUT =
30.seconds
SILENT_MODE_ALLOWED_METHODS =
[
  Net::HTTP::Get,
  Net::HTTP::Head,
  Net::HTTP::Options,
  Net::HTTP::Trace
].freeze

Class Method Summary collapse

Class Method Details

.blocked_by_silent_mode?(http_method) ⇒ Boolean

Returns:

  • (Boolean)


105
106
107
# File 'lib/gitlab/http.rb', line 105

def self.blocked_by_silent_mode?(http_method)
  ::Gitlab::SilentMode.enabled? && SILENT_MODE_ALLOWED_METHODS.exclude?(http_method)
end

.httparty_perform_requestObject



46
# File 'lib/gitlab/http.rb', line 46

alias_method :httparty_perform_request, :perform_request

.perform_request(http_method, path, options, &block) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/gitlab/http.rb', line 51

def self.perform_request(http_method, path, options, &block)
  raise_if_blocked_by_silent_mode(http_method)

  log_info = options.delete(:extra_log_info)
  options_with_timeouts =
    if !options.has_key?(:timeout)
      options.with_defaults(DEFAULT_TIMEOUT_OPTIONS)
    else
      options
    end

  if options[:stream_body]
    return httparty_perform_request(http_method, path, options_with_timeouts, &block)
  end

  start_time = nil
  read_total_timeout = options.fetch(:timeout, DEFAULT_READ_TOTAL_TIMEOUT)

  httparty_perform_request(http_method, path, options_with_timeouts) do |fragment|
    start_time ||= Gitlab::Metrics::System.monotonic_time
    elapsed = Gitlab::Metrics::System.monotonic_time - start_time

    if elapsed > read_total_timeout
      raise ReadTotalTimeout, "Request timed out after #{elapsed} seconds"
    end

    yield fragment if block
  end
rescue HTTParty::RedirectionTooDeep
  raise RedirectionTooDeep
rescue *HTTP_ERRORS => e
  extra_info = log_info || {}
  extra_info = log_info.call(e, path, options) if log_info.respond_to?(:call)
  Gitlab::ErrorTracking.log_exception(e, extra_info)
  raise e
end

.raise_if_blocked_by_silent_mode(http_method) ⇒ Object



94
95
96
97
98
99
100
101
102
103
# File 'lib/gitlab/http.rb', line 94

def self.raise_if_blocked_by_silent_mode(http_method)
  return unless blocked_by_silent_mode?(http_method)

  ::Gitlab::SilentMode.log_info(
    message: 'Outbound HTTP request blocked',
    outbound_http_request_method: http_method.to_s
  )

  raise SilentModeBlockedError, 'only get, head, options, and trace methods are allowed in silent mode'
end

.try_get(path, options = {}, &block) ⇒ Object



88
89
90
91
92
# File 'lib/gitlab/http.rb', line 88

def self.try_get(path, options = {}, &block)
  self.get(path, options, &block)
rescue *HTTP_ERRORS
  nil
end