Skip to content

Commit 3d23336

Browse files
authored
Merge branch 'master' into dependabot/bundler/examples/ruby-api/rack-2.2.22
2 parents a0d5eaf + ce6896d commit 3d23336

3 files changed

Lines changed: 119 additions & 42 deletions

File tree

Gemfile.lock

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,24 +134,24 @@ GEM
134134
multi_json (1.15.0)
135135
nenv (0.3.0)
136136
netrc (0.11.0)
137-
nokogiri (1.18.9)
137+
nokogiri (1.19.1)
138138
mini_portile2 (~> 2.8.2)
139139
racc (~> 1.4)
140-
nokogiri (1.18.9-aarch64-linux-gnu)
140+
nokogiri (1.19.1-aarch64-linux-gnu)
141141
racc (~> 1.4)
142-
nokogiri (1.18.9-aarch64-linux-musl)
142+
nokogiri (1.19.1-aarch64-linux-musl)
143143
racc (~> 1.4)
144-
nokogiri (1.18.9-arm-linux-gnu)
144+
nokogiri (1.19.1-arm-linux-gnu)
145145
racc (~> 1.4)
146-
nokogiri (1.18.9-arm-linux-musl)
146+
nokogiri (1.19.1-arm-linux-musl)
147147
racc (~> 1.4)
148-
nokogiri (1.18.9-arm64-darwin)
148+
nokogiri (1.19.1-arm64-darwin)
149149
racc (~> 1.4)
150-
nokogiri (1.18.9-x86_64-darwin)
150+
nokogiri (1.19.1-x86_64-darwin)
151151
racc (~> 1.4)
152-
nokogiri (1.18.9-x86_64-linux-gnu)
152+
nokogiri (1.19.1-x86_64-linux-gnu)
153153
racc (~> 1.4)
154-
nokogiri (1.18.9-x86_64-linux-musl)
154+
nokogiri (1.19.1-x86_64-linux-musl)
155155
racc (~> 1.4)
156156
notiffany (0.1.3)
157157
nenv (~> 0.1)

lib/auth0/mixins/httpproxy.rb

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
require "addressable/uri"
2-
require "retryable"
3-
require_relative "../exception.rb"
1+
# frozen_string_literal: true
2+
3+
require 'addressable/uri'
4+
require 'retryable'
5+
require_relative '../exception'
46

57
module Auth0
68
module Mixins
79
# here's the proxy for Rest calls based on rest-client, we're building all request on that gem
810
# for now, if you want to feel free to use your own http client
911
module HTTPProxy
1012
attr_accessor :headers, :base_uri, :timeout, :retry_count
13+
1114
DEFAULT_RETRIES = 3
1215
MAX_ALLOWED_RETRIES = 10
1316
MAX_REQUEST_RETRY_JITTER = 250
@@ -16,19 +19,19 @@ module HTTPProxy
1619
BASE_DELAY = 100
1720

1821
# proxying requests from instance methods to HTTP class methods
19-
%i(get post post_file post_form put patch delete delete_with_body).each do |method|
22+
%i[get post post_file post_form put patch delete delete_with_body].each do |method|
2023
define_method(method) do |uri, body = {}, extra_headers = {}|
21-
body = body.delete_if { |_, v| v.nil? }
22-
token = get_token()
24+
body = safe_merge_body(body, extra_headers)
25+
token = get_token
2326
authorization_header(token) unless token.nil?
2427
request_with_retry(method, uri, body, extra_headers)
2528
end
2629
end
2730

2831
def retry_options
2932
sleep_timer = lambda do |attempt|
30-
wait = BASE_DELAY * (2**attempt-1) # Exponential delay with each subsequent request attempt.
31-
wait += rand(wait+1..wait+MAX_REQUEST_RETRY_JITTER) # Add jitter to the delay window.
33+
wait = BASE_DELAY * (2**attempt - 1) # Exponential delay with each subsequent request attempt.
34+
wait += rand(wait + 1..wait + MAX_REQUEST_RETRY_JITTER) # Add jitter to the delay window.
3235
wait = [MAX_REQUEST_RETRY_DELAY, wait].min # Cap delay at MAX_REQUEST_RETRY_DELAY.
3336
wait = [MIN_REQUEST_RETRY_DELAY, wait].max # Ensure delay is no less than MIN_REQUEST_RETRY_DELAY.
3437
wait / 1000.to_f.round(2) # convert ms to seconds
@@ -55,6 +58,7 @@ def url(path)
5558

5659
def add_headers(h = {})
5760
raise ArgumentError, 'Headers must be an object which responds to #to_hash' unless h.respond_to?(:to_hash)
61+
5862
@headers ||= {}
5963
@headers.merge!(h.to_hash)
6064
end
@@ -72,36 +76,38 @@ def request_with_retry(method, uri, body = {}, extra_headers = {})
7276
end
7377

7478
def request(method, uri, body = {}, extra_headers = {})
75-
result = if method == :get
76-
@headers ||= {}
77-
get_headers = @headers.merge({params: body}).merge(extra_headers)
78-
call(:get, encode_uri(uri), timeout, get_headers)
79-
elsif method == :delete
80-
@headers ||= {}
81-
delete_headers = @headers.merge({ params: body })
82-
call(:delete, encode_uri(uri), timeout, delete_headers)
83-
elsif method == :delete_with_body
84-
call(:delete, encode_uri(uri), timeout, headers, body.to_json)
85-
elsif method == :post_file
86-
body.merge!(multipart: true)
87-
# Ignore the default Content-Type headers and let the HTTP client define them
88-
post_file_headers = headers.except('Content-Type') if headers != nil
89-
# Actual call with the altered headers
90-
call(:post, encode_uri(uri), timeout, post_file_headers, body)
91-
elsif method == :post_form
92-
form_post_headers = headers.except('Content-Type') if headers != nil
93-
call(:post, encode_uri(uri), timeout, form_post_headers, body.compact)
94-
else
95-
call(method, encode_uri(uri), timeout, headers, body.to_json)
96-
end
79+
result = case method
80+
when :get
81+
@headers ||= {}
82+
get_headers = @headers.merge({ params: body }).merge(extra_headers)
83+
call(:get, encode_uri(uri), timeout, get_headers)
84+
when :delete
85+
@headers ||= {}
86+
delete_headers = @headers.merge({ params: body })
87+
call(:delete, encode_uri(uri), timeout, delete_headers)
88+
when :delete_with_body
89+
call(:delete, encode_uri(uri), timeout, headers, body.to_json)
90+
when :post_file
91+
body.merge!(multipart: true)
92+
# Ignore the default Content-Type headers and let the HTTP client define them
93+
post_file_headers = headers.except('Content-Type') unless headers.nil?
94+
# Actual call with the altered headers
95+
call(:post, encode_uri(uri), timeout, post_file_headers, body)
96+
when :post_form
97+
form_post_headers = headers.except('Content-Type') unless headers.nil?
98+
call(:post, encode_uri(uri), timeout, form_post_headers, body.compact)
99+
else
100+
call(method, encode_uri(uri), timeout, headers, body.to_json)
101+
end
97102

98103
case result.code
99104
when 200...226 then safe_parse_json(result.body)
100105
when 400 then raise Auth0::BadRequest.new(result.body, code: result.code, headers: result.headers)
101106
when 401 then raise Auth0::Unauthorized.new(result.body, code: result.code, headers: result.headers)
102107
when 403 then raise Auth0::AccessDenied.new(result.body, code: result.code, headers: result.headers)
103108
when 404 then raise Auth0::NotFound.new(result.body, code: result.code, headers: result.headers)
104-
when 429 then raise Auth0::RateLimitEncountered.new(result.body, code: result.code, headers: result.headers)
109+
when 429 then raise Auth0::RateLimitEncountered.new(result.body, code: result.code,
110+
headers: result.headers)
105111
when 500 then raise Auth0::ServerError.new(result.body, code: result.code, headers: result.headers)
106112
else raise Auth0::Unsupported.new(result.body, code: result.code, headers: result.headers)
107113
end
@@ -118,11 +124,19 @@ def call(method, url, timeout, headers, body = nil)
118124
rescue RestClient::Exception => e
119125
case e
120126
when RestClient::RequestTimeout
121-
raise Auth0::RequestTimeout.new(e.message)
127+
raise Auth0::RequestTimeout, e.message
122128
else
123-
return e.response
129+
e.response
124130
end
125131
end
132+
133+
private
134+
135+
def safe_merge_body(body, extra = {})
136+
return body unless body.is_a?(Hash)
137+
merged = extra.any? ? body.merge(extra) : body
138+
merged.compact
139+
end
126140
end
127141
end
128142
end

spec/lib/auth0/mixins/httpproxy_spec.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,13 +272,75 @@ def expected_payload(method, overrides = {})
272272

273273
%i(post post_form put patch).each do |http_method|
274274
context ".#{http_method}" do
275+
context 'when body is an Array' do
276+
let(:payload) { [{ permission_name: 'read:data', resource_server_identifier: 'https://api.example.com' }] }
277+
278+
if http_method == :post_form
279+
it 'sends the array as-is without wrapping in a Hash' do
280+
expect(RestClient::Request).to receive(:execute) do |args|
281+
expect(args[:payload]).to be_an(Array)
282+
expect(args[:payload]).to eq(payload)
283+
end.and_return(StubResponse.new('[]', true, 200))
284+
285+
@instance.send(http_method, '/test', payload)
286+
end
287+
else
288+
it 'sends the array as-is without wrapping in a Hash' do
289+
expect(RestClient::Request).to receive(:execute) do |args|
290+
parsed = JSON.parse(args[:payload], symbolize_names: true)
291+
expect(parsed).to be_an(Array)
292+
expect(parsed).to eq(payload)
293+
end.and_return(StubResponse.new('[]', true, 200))
294+
295+
@instance.send(http_method, '/test', payload)
296+
end
297+
end
298+
end
299+
300+
context 'when body is a Hash' do
301+
let(:payload) { { permission_name: 'read:data', resource_server_identifier: 'https://api.example.com' } }
302+
303+
if http_method == :post_form
304+
it 'sends the Hash without modification' do
305+
expect(RestClient::Request).to receive(:execute) do |args|
306+
expect(args[:payload]).to be_a(Hash)
307+
expect(args[:payload]).to include(payload)
308+
end.and_return(StubResponse.new('{}', true, 200))
309+
310+
@instance.send(http_method, '/test', payload)
311+
end
312+
else
313+
it 'sends the Hash as JSON without modification' do
314+
expect(RestClient::Request).to receive(:execute) do |args|
315+
parsed = JSON.parse(args[:payload], symbolize_names: true)
316+
expect(parsed).to be_a(Hash)
317+
expect(parsed).to eq(payload)
318+
end.and_return(StubResponse.new('{}', true, 200))
319+
320+
@instance.send(http_method, '/test', payload)
321+
end
322+
end
323+
end
275324
it { expect(@instance).to respond_to(http_method.to_sym) }
276325
it "should call send http #{http_method} method to path defined through HTTP"do
277326
expect(RestClient::Request).to receive(:execute).with(expected_payload(http_method))
278327
.and_return(StubResponse.new({}, true, 200))
279328
expect { @instance.send(http_method, '/test') }.not_to raise_error
280329
end
281330

331+
it "should handle array parameters for #{http_method} method" do
332+
array_data = ['param1', 'param2']
333+
if http_method == :post_form
334+
expected_params = expected_payload(http_method, { payload: array_data })
335+
else
336+
expected_params = expected_payload(http_method, { payload: array_data.to_json })
337+
end
338+
339+
expect(RestClient::Request).to receive(:execute).with(expected_params)
340+
.and_return(StubResponse.new({}, true, 200))
341+
expect { @instance.send(http_method, '/test', array_data) }.not_to raise_error
342+
end
343+
282344
it 'should not raise exception if data returned not in json format (should be fixed in v2)' do
283345
allow(RestClient::Request).to receive(:execute).with(expected_payload(http_method))
284346
.and_return(StubResponse.new('Some random text here', true, 200))
@@ -452,6 +514,7 @@ def expected_payload(method, overrides = {})
452514
end
453515
end
454516
end
517+
455518
end
456519
end
457520

0 commit comments

Comments
 (0)