raims 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +130 -0
- data/lib/raims/api_list.rb +98 -0
- data/lib/raims/api_resource.rb +31 -0
- data/lib/raims/api_response.rb +45 -0
- data/lib/raims/enum_values.rb +208 -0
- data/lib/raims/errors.rb +59 -0
- data/lib/raims/generated/contract.json +6982 -0
- data/lib/raims/http_client.rb +91 -0
- data/lib/raims/models.rb +1863 -0
- data/lib/raims/raims_client.rb +276 -0
- data/lib/raims/request_options.rb +47 -0
- data/lib/raims/schema.rb +104 -0
- data/lib/raims/services.rb +506 -0
- data/lib/raims/util.rb +141 -0
- data/lib/raims/version.rb +5 -0
- data/lib/raims/webhook.rb +72 -0
- data/lib/raims.rb +16 -0
- metadata +143 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'openssl'
|
|
5
|
+
require 'timeout'
|
|
6
|
+
require 'zlib'
|
|
7
|
+
|
|
8
|
+
module Raims
|
|
9
|
+
class NetHttpClient
|
|
10
|
+
def execute(method:, uri:, headers:, body:, timeout:, connect_timeout:, max_response_bytes:)
|
|
11
|
+
# An explicit nil proxy disables environment proxy discovery.
|
|
12
|
+
http = Net::HTTP.new(uri.hostname, uri.port, nil)
|
|
13
|
+
http.use_ssl = uri.scheme == 'https'
|
|
14
|
+
if http.use_ssl?
|
|
15
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
16
|
+
http.min_version = OpenSSL::SSL::TLS1_2_VERSION
|
|
17
|
+
end
|
|
18
|
+
http.open_timeout = [timeout, connect_timeout].min
|
|
19
|
+
http.read_timeout = timeout
|
|
20
|
+
http.write_timeout = timeout
|
|
21
|
+
http.max_retries = 0
|
|
22
|
+
request = Net::HTTPGenericRequest.new(method, !body.nil?, method != 'HEAD', uri.request_uri, headers)
|
|
23
|
+
request.body = body unless body.nil?
|
|
24
|
+
result = nil
|
|
25
|
+
metadata = nil
|
|
26
|
+
Timeout.timeout(timeout) do
|
|
27
|
+
http.start do |connection|
|
|
28
|
+
connection.request(request) do |response|
|
|
29
|
+
metadata = ApiResponse.new(response.code.to_i, response.each_header.to_h)
|
|
30
|
+
length = content_length(response, metadata)
|
|
31
|
+
validate_transfer_encoding(response, length, metadata)
|
|
32
|
+
response.ignore_eof = false
|
|
33
|
+
response.content_length = length unless length.nil?
|
|
34
|
+
has_body = method != 'HEAD' && response.class.body_permitted?
|
|
35
|
+
if has_body && length && length > max_response_bytes
|
|
36
|
+
raise UnexpectedResponseError.new('The API response exceeds the supported size.', last_response: metadata)
|
|
37
|
+
end
|
|
38
|
+
bytes = String.new(encoding: Encoding::BINARY)
|
|
39
|
+
begin
|
|
40
|
+
response.read_body do |chunk|
|
|
41
|
+
if bytes.bytesize + chunk.bytesize > max_response_bytes
|
|
42
|
+
raise UnexpectedResponseError.new('The API response exceeds the supported size.', last_response: metadata)
|
|
43
|
+
end
|
|
44
|
+
bytes << chunk
|
|
45
|
+
end
|
|
46
|
+
rescue EOFError
|
|
47
|
+
raise UnexpectedResponseError.new('The API response ended before the HTTP body was complete.', last_response: metadata), cause: nil
|
|
48
|
+
rescue Net::HTTPBadResponse
|
|
49
|
+
raise UnexpectedResponseError.new('The API returned invalid HTTP body framing.', last_response: metadata), cause: nil
|
|
50
|
+
end
|
|
51
|
+
result = HttpResponse.new(status: metadata.status_code, headers: metadata.headers, body: bytes)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
result
|
|
56
|
+
rescue Zlib::Error
|
|
57
|
+
raise UnexpectedResponseError.new('The API returned invalid compressed content.', last_response: metadata), cause: nil
|
|
58
|
+
rescue Net::HTTPHeaderSyntaxError
|
|
59
|
+
raise UnexpectedResponseError.new('The API returned invalid HTTP headers.', last_response: metadata), cause: nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def inspect
|
|
63
|
+
"#<#{self.class}>"
|
|
64
|
+
end
|
|
65
|
+
alias to_s inspect
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def content_length(response, metadata)
|
|
70
|
+
fields = response.get_fields('content-length')
|
|
71
|
+
return nil unless fields
|
|
72
|
+
values = fields.flat_map { |field| field.split(',', -1) }
|
|
73
|
+
unless !values.empty? && values.all? { |value| value.match?(/\A[ \t]*[0-9]+[ \t]*\z/) }
|
|
74
|
+
raise UnexpectedResponseError.new('The API returned an invalid Content-Length header.', last_response: metadata)
|
|
75
|
+
end
|
|
76
|
+
lengths = values.map(&:to_i).uniq
|
|
77
|
+
unless lengths.length == 1
|
|
78
|
+
raise UnexpectedResponseError.new('The API returned conflicting Content-Length headers.', last_response: metadata)
|
|
79
|
+
end
|
|
80
|
+
lengths.first
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def validate_transfer_encoding(response, length, metadata)
|
|
84
|
+
fields = response.get_fields('transfer-encoding')
|
|
85
|
+
return unless fields
|
|
86
|
+
unless length.nil? && fields.length == 1 && fields.first.match?(/\A[ \t]*chunked[ \t]*\z/i)
|
|
87
|
+
raise UnexpectedResponseError.new('The API returned unsupported or ambiguous HTTP transfer framing.', last_response: metadata)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|