Module: Auth0::Mixins::HTTPProxy

Included in:
Auth0::Mixins, Validation::Algorithm::RS256
Defined in:
lib/auth0/mixins/httpproxy.rb

Overview

here’s the proxy for Rest calls based on rest-client, we’re building all request on that gem for now, if you want to feel free to use your own http client

Constant Summary collapse

DEFAULT_RETRIES =
3
MAX_ALLOWED_RETRIES =
10
MAX_REQUEST_RETRY_JITTER =
250
MAX_REQUEST_RETRY_DELAY =
1000
MIN_REQUEST_RETRY_DELAY =
250
BASE_DELAY =
100

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#base_uriObject

Returns the value of attribute base_uri.


10
11
12
# File 'lib/auth0/mixins/httpproxy.rb', line 10

def base_uri
  @base_uri
end

#headersObject

Returns the value of attribute headers.


10
11
12
# File 'lib/auth0/mixins/httpproxy.rb', line 10

def headers
  @headers
end

#retry_countObject

Returns the value of attribute retry_count.


10
11
12
# File 'lib/auth0/mixins/httpproxy.rb', line 10

def retry_count
  @retry_count
end

#timeoutObject

Returns the value of attribute timeout.


10
11
12
# File 'lib/auth0/mixins/httpproxy.rb', line 10

def timeout
  @timeout
end

Instance Method Details

#add_headers(h = {}) ⇒ Object

Raises:

  • (ArgumentError)
[View source]

56
57
58
59
60
# File 'lib/auth0/mixins/httpproxy.rb', line 56

def add_headers(h = {})
  raise ArgumentError, 'Headers must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
  @headers ||= {}
  @headers.merge!(h.to_hash)
end

#call(method, url, timeout, headers, body = nil) ⇒ Object

[View source]

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/auth0/mixins/httpproxy.rb', line 110

def call(method, url, timeout, headers, body = nil)
  RestClient::Request.execute(
    method: method,
    url: url,
    timeout: timeout,
    headers: headers,
    payload: body
  )
rescue RestClient::Exception => e
  case e
  when RestClient::RequestTimeout
    raise Auth0::RequestTimeout.new(e.message)
  else
    return e.response
  end
end

#encode_uri(uri) ⇒ Object

[View source]

46
47
48
49
50
# File 'lib/auth0/mixins/httpproxy.rb', line 46

def encode_uri(uri)
  # if a base_uri is set then the uri can be encoded as a path
  path = base_uri ? Addressable::URI.new(path: uri).normalized_path : Addressable::URI.escape(uri)
  url(path)
end

#request(method, uri, body = {}, extra_headers = {}) ⇒ Object

[View source]

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/auth0/mixins/httpproxy.rb', line 74

def request(method, uri, body = {}, extra_headers = {})
  result = if method == :get
    @headers ||= {}
    get_headers = @headers.merge({params: body}).merge(extra_headers)
    call(:get, encode_uri(uri), timeout, get_headers)
  elsif method == :delete
    @headers ||= {}
    delete_headers = @headers.merge({ params: body })
    call(:delete, encode_uri(uri), timeout, delete_headers)
  elsif method == :delete_with_body
    call(:delete, encode_uri(uri), timeout, headers, body.to_json)
  elsif method == :post_file
    body.merge!(multipart: true)
    # Ignore the default Content-Type headers and let the HTTP client define them
    post_file_headers = headers.except('Content-Type') if headers != nil
    # Actual call with the altered headers
    call(:post, encode_uri(uri), timeout, post_file_headers, body)
  elsif method == :post_form
    form_post_headers = headers.except('Content-Type') if headers != nil
    call(:post, encode_uri(uri), timeout, form_post_headers, body.compact)
  else
    call(method, encode_uri(uri), timeout, headers, body.to_json)
  end

  case result.code
  when 200...226 then safe_parse_json(result.body)
  when 400       then raise Auth0::BadRequest.new(result.body, code: result.code, headers: result.headers)
  when 401       then raise Auth0::Unauthorized.new(result.body, code: result.code, headers: result.headers)
  when 403       then raise Auth0::AccessDenied.new(result.body, code: result.code, headers: result.headers)
  when 404       then raise Auth0::NotFound.new(result.body, code: result.code, headers: result.headers)
  when 429       then raise Auth0::RateLimitEncountered.new(result.body, code: result.code, headers: result.headers)
  when 500       then raise Auth0::ServerError.new(result.body, code: result.code, headers: result.headers)
  else           raise Auth0::Unsupported.new(result.body, code: result.code, headers: result.headers)
  end
end

#request_with_retry(method, uri, body = {}, extra_headers = {}) ⇒ Object

[View source]

68
69
70
71
72
# File 'lib/auth0/mixins/httpproxy.rb', line 68

def request_with_retry(method, uri, body = {}, extra_headers = {})
  Retryable.retryable(retry_options) do
    request(method, uri, body, extra_headers)
  end
end

#retry_optionsObject

[View source]

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/auth0/mixins/httpproxy.rb', line 28

def retry_options
  sleep_timer = lambda do |attempt|
    wait = BASE_DELAY * (2**attempt-1) # Exponential delay with each subsequent request attempt.
    wait += rand(wait+1..wait+MAX_REQUEST_RETRY_JITTER) # Add jitter to the delay window.
    wait = [MAX_REQUEST_RETRY_DELAY, wait].min # Cap delay at MAX_REQUEST_RETRY_DELAY.
    wait = [MIN_REQUEST_RETRY_DELAY, wait].max # Ensure delay is no less than MIN_REQUEST_RETRY_DELAY.
    wait / 1000.to_f.round(2) # convert ms to seconds
  end

  tries = 1 + [Integer(retry_count || DEFAULT_RETRIES), MAX_ALLOWED_RETRIES].min # Cap retries at MAX_ALLOWED_RETRIES

  {
    tries: tries,
    sleep: sleep_timer,
    on: Auth0::RateLimitEncountered
  }
end

#safe_parse_json(body) ⇒ Object

[View source]

62
63
64
65
66
# File 'lib/auth0/mixins/httpproxy.rb', line 62

def safe_parse_json(body)
  JSON.parse(body.to_s)
rescue JSON::ParserError
  body
end

#url(path) ⇒ Object

[View source]

52
53
54
# File 'lib/auth0/mixins/httpproxy.rb', line 52

def url(path)
  "#{base_uri}#{path}"
end