hearth 1.0.0.pre1 → 1.0.0.pre3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -4
- data/VERSION +1 -1
- data/lib/hearth/anonymous_auth_resolver.rb +11 -0
- data/lib/hearth/api_error.rb +15 -1
- data/lib/hearth/auth_option.rb +21 -0
- data/lib/hearth/auth_schemes/anonymous.rb +21 -0
- data/lib/hearth/auth_schemes/http_api_key.rb +16 -0
- data/lib/hearth/auth_schemes/http_basic.rb +16 -0
- data/lib/hearth/auth_schemes/http_bearer.rb +16 -0
- data/lib/hearth/auth_schemes/http_digest.rb +16 -0
- data/lib/hearth/auth_schemes.rb +32 -0
- data/lib/hearth/checksums.rb +31 -0
- data/lib/hearth/client.rb +66 -0
- data/lib/hearth/client_stubs.rb +128 -0
- data/lib/hearth/config/env_provider.rb +53 -0
- data/lib/hearth/config/resolver.rb +53 -0
- data/lib/hearth/configuration.rb +15 -0
- data/lib/hearth/connection_pool.rb +77 -0
- data/lib/hearth/context.rb +29 -4
- data/lib/hearth/dns/host_address.rb +27 -0
- data/lib/hearth/dns/host_resolver.rb +92 -0
- data/lib/hearth/dns.rb +48 -0
- data/lib/hearth/endpoint_rules.rb +154 -0
- data/lib/hearth/http/api_error.rb +4 -8
- data/lib/hearth/http/client.rb +206 -59
- data/lib/hearth/http/error_inspector.rb +85 -0
- data/lib/hearth/http/error_parser.rb +18 -20
- data/lib/hearth/http/field.rb +49 -0
- data/lib/hearth/http/fields.rb +117 -0
- data/lib/hearth/http/header_list_builder.rb +42 -0
- data/lib/hearth/http/header_list_parser.rb +92 -0
- data/lib/hearth/http/middleware/content_length.rb +7 -4
- data/lib/hearth/http/middleware/content_md5.rb +30 -0
- data/lib/hearth/http/middleware/request_compression.rb +154 -0
- data/lib/hearth/http/middleware.rb +12 -0
- data/lib/hearth/http/networking_error.rb +1 -14
- data/lib/hearth/http/request.rb +83 -56
- data/lib/hearth/http/response.rb +42 -13
- data/lib/hearth/http.rb +16 -5
- data/lib/hearth/identities/anonymous.rb +8 -0
- data/lib/hearth/identities/http_api_key.rb +16 -0
- data/lib/hearth/identities/http_bearer.rb +16 -0
- data/lib/hearth/identities/http_login.rb +20 -0
- data/lib/hearth/identities.rb +21 -0
- data/lib/hearth/identity_provider.rb +17 -0
- data/lib/hearth/interceptor.rb +506 -0
- data/lib/hearth/interceptor_context.rb +40 -0
- data/lib/hearth/interceptor_list.rb +48 -0
- data/lib/hearth/interceptors.rb +76 -0
- data/lib/hearth/json.rb +4 -4
- data/lib/hearth/middleware/auth.rb +103 -0
- data/lib/hearth/middleware/build.rb +32 -1
- data/lib/hearth/middleware/endpoint.rb +79 -0
- data/lib/hearth/middleware/host_prefix.rb +11 -8
- data/lib/hearth/middleware/initialize.rb +57 -0
- data/lib/hearth/middleware/parse.rb +45 -7
- data/lib/hearth/middleware/retry.rb +105 -24
- data/lib/hearth/middleware/send.rb +137 -26
- data/lib/hearth/middleware/sign.rb +65 -0
- data/lib/hearth/middleware/validate.rb +11 -1
- data/lib/hearth/middleware.rb +20 -8
- data/lib/hearth/middleware_stack.rb +2 -44
- data/lib/hearth/networking_error.rb +18 -0
- data/lib/hearth/number_helper.rb +3 -3
- data/lib/hearth/output.rb +8 -4
- data/lib/hearth/plugin_list.rb +53 -0
- data/lib/hearth/query/param.rb +56 -0
- data/lib/hearth/query/param_list.rb +54 -0
- data/lib/hearth/query/param_matcher.rb +31 -0
- data/lib/hearth/refreshing_identity_provider.rb +63 -0
- data/lib/hearth/request.rb +22 -0
- data/lib/hearth/response.rb +36 -0
- data/lib/hearth/retry/adaptive.rb +60 -0
- data/lib/hearth/retry/capacity_not_available_error.rb +9 -0
- data/lib/hearth/retry/client_rate_limiter.rb +145 -0
- data/lib/hearth/retry/exponential_backoff.rb +15 -0
- data/lib/hearth/retry/retry_quota.rb +56 -0
- data/lib/hearth/retry/standard.rb +46 -0
- data/lib/hearth/retry.rb +29 -0
- data/lib/hearth/signers/anonymous.rb +16 -0
- data/lib/hearth/signers/http_api_key.rb +29 -0
- data/lib/hearth/signers/http_basic.rb +23 -0
- data/lib/hearth/signers/http_bearer.rb +19 -0
- data/lib/hearth/signers/http_digest.rb +19 -0
- data/lib/hearth/signers.rb +23 -0
- data/lib/hearth/structure.rb +7 -3
- data/lib/hearth/stubs.rb +38 -0
- data/lib/hearth/time_helper.rb +6 -5
- data/lib/hearth/validator.rb +60 -5
- data/lib/hearth/waiters/poller.rb +10 -9
- data/lib/hearth/waiters/waiter.rb +23 -9
- data/lib/hearth/xml/formatter.rb +11 -2
- data/lib/hearth/xml/node.rb +2 -3
- data/lib/hearth/xml/node_matcher.rb +0 -1
- data/lib/hearth.rb +37 -6
- data/sig/lib/hearth/aliases.rbs +6 -0
- data/sig/lib/hearth/anonymous_auth_resolver.rbs +5 -0
- data/sig/lib/hearth/api_error.rbs +13 -0
- data/sig/lib/hearth/auth_option.rbs +11 -0
- data/sig/lib/hearth/auth_schemes/anonymous.rbs +7 -0
- data/sig/lib/hearth/auth_schemes/http_api_key.rbs +7 -0
- data/sig/lib/hearth/auth_schemes/http_basic.rbs +7 -0
- data/sig/lib/hearth/auth_schemes/http_bearer.rbs +7 -0
- data/sig/lib/hearth/auth_schemes/http_digest.rbs +7 -0
- data/sig/lib/hearth/auth_schemes.rbs +13 -0
- data/sig/lib/hearth/block_io.rbs +9 -0
- data/sig/lib/hearth/client.rbs +9 -0
- data/sig/lib/hearth/client_stubs.rbs +5 -0
- data/sig/lib/hearth/configuration.rbs +7 -0
- data/sig/lib/hearth/dns/host_address.rbs +11 -0
- data/sig/lib/hearth/dns/host_resolver.rbs +19 -0
- data/sig/lib/hearth/endpoint_rules.rbs +17 -0
- data/sig/lib/hearth/http/api_error.rbs +13 -0
- data/sig/lib/hearth/http/client.rbs +9 -0
- data/sig/lib/hearth/http/field.rbs +19 -0
- data/sig/lib/hearth/http/fields.rbs +43 -0
- data/sig/lib/hearth/http/header_list_builder.rbs +15 -0
- data/sig/lib/hearth/http/header_list_parser.rbs +19 -0
- data/sig/lib/hearth/http/networking_error.rbs +6 -0
- data/sig/lib/hearth/http/request.rbs +25 -0
- data/sig/lib/hearth/http/response.rbs +21 -0
- data/sig/lib/hearth/identities/anonymous.rbs +6 -0
- data/sig/lib/hearth/identities/http_api_key.rbs +9 -0
- data/sig/lib/hearth/identities/http_bearer.rbs +9 -0
- data/sig/lib/hearth/identities/http_login.rbs +11 -0
- data/sig/lib/hearth/identities.rbs +9 -0
- data/sig/lib/hearth/identity_provider.rbs +7 -0
- data/sig/lib/hearth/interceptor.rbs +9 -0
- data/sig/lib/hearth/interceptor_context.rbs +17 -0
- data/sig/lib/hearth/interceptor_list.rbs +16 -0
- data/sig/lib/hearth/interfaces.rbs +87 -0
- data/sig/lib/hearth/json/parse_error.rbs +9 -0
- data/sig/lib/hearth/networking_error.rbs +7 -0
- data/sig/lib/hearth/output.rbs +11 -0
- data/sig/lib/hearth/plugin_list.rbs +13 -0
- data/sig/lib/hearth/query/param.rbs +17 -0
- data/sig/lib/hearth/query/param_list.rbs +25 -0
- data/sig/lib/hearth/refreshing_identity_provider.rbs +10 -0
- data/sig/lib/hearth/request.rbs +9 -0
- data/sig/lib/hearth/response.rbs +11 -0
- data/sig/lib/hearth/retry/adaptive.rbs +13 -0
- data/sig/lib/hearth/retry/exponential_backoff.rbs +7 -0
- data/sig/lib/hearth/retry/standard.rbs +13 -0
- data/sig/lib/hearth/retry/strategy.rbs +11 -0
- data/sig/lib/hearth/retry.rbs +9 -0
- data/sig/lib/hearth/signers/anonymous.rbs +9 -0
- data/sig/lib/hearth/signers/http_api_key.rbs +9 -0
- data/sig/lib/hearth/signers/http_basic.rbs +9 -0
- data/sig/lib/hearth/signers/http_bearer.rbs +9 -0
- data/sig/lib/hearth/signers/http_digest.rbs +9 -0
- data/sig/lib/hearth/signers.rbs +9 -0
- data/sig/lib/hearth/structure.rbs +6 -0
- data/sig/lib/hearth/stubs.rbs +9 -0
- data/sig/lib/hearth/union.rbs +5 -0
- data/sig/lib/hearth/waiters/waiter.rbs +17 -0
- data/sig/lib/hearth/xml/parse_error.rbs +9 -0
- metadata +151 -25
- data/lib/hearth/http/headers.rb +0 -70
- data/lib/hearth/middleware/around_handler.rb +0 -24
- data/lib/hearth/middleware/request_handler.rb +0 -24
- data/lib/hearth/middleware/response_handler.rb +0 -25
- data/lib/hearth/middleware_builder.rb +0 -246
- data/lib/hearth/stubbing/client_stubs.rb +0 -115
- data/lib/hearth/stubbing/stubs.rb +0 -32
- data/lib/hearth/waiters/errors.rb +0 -15
- data/sig/lib/seahorse/api_error.rbs +0 -10
- data/sig/lib/seahorse/document.rbs +0 -2
- data/sig/lib/seahorse/http/api_error.rbs +0 -21
- data/sig/lib/seahorse/http/headers.rbs +0 -47
- data/sig/lib/seahorse/http/response.rbs +0 -21
- data/sig/lib/seahorse/simple_delegator.rbs +0 -3
- data/sig/lib/seahorse/structure.rbs +0 -18
- data/sig/lib/seahorse/stubbing/client_stubs.rbs +0 -103
- data/sig/lib/seahorse/stubbing/stubs.rbs +0 -14
- data/sig/lib/seahorse/union.rbs +0 -6
data/lib/hearth/context.rb
CHANGED
@@ -1,19 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'securerandom'
|
4
|
+
|
3
5
|
module Hearth
|
4
6
|
# Stores request and response objects, and other useful things used by
|
5
7
|
# multiple Middleware.
|
8
|
+
# @api private
|
6
9
|
class Context
|
7
10
|
def initialize(options = {})
|
11
|
+
@invocation_id = SecureRandom.uuid
|
8
12
|
@operation_name = options[:operation_name]
|
9
13
|
@request = options[:request]
|
10
14
|
@response = options[:response]
|
11
15
|
@logger = options[:logger]
|
12
|
-
@
|
16
|
+
@interceptors = options[:interceptors] || InterceptorList.new
|
17
|
+
@auth = options[:auth]
|
13
18
|
@metadata = options[:metadata] || {}
|
14
19
|
end
|
15
20
|
|
16
|
-
# @return [
|
21
|
+
# @return [String] The invocation ID for the request.
|
22
|
+
attr_reader :invocation_id
|
23
|
+
|
24
|
+
# @return [Symbol] The name of the API operation called.
|
17
25
|
attr_reader :operation_name
|
18
26
|
|
19
27
|
# @return [Hearth::HTTP::Request]
|
@@ -25,10 +33,27 @@ module Hearth
|
|
25
33
|
# @return [Logger] An instance of the logger configured for the Client.
|
26
34
|
attr_reader :logger
|
27
35
|
|
28
|
-
# @return [
|
29
|
-
attr_reader :
|
36
|
+
# @return [Array] An ordered list of interceptors
|
37
|
+
attr_reader :interceptors
|
38
|
+
|
39
|
+
# @return [ResolvedAuth, nil] The resolved auth for the request.
|
40
|
+
attr_accessor :auth
|
30
41
|
|
31
42
|
# @return [Hash]
|
32
43
|
attr_reader :metadata
|
44
|
+
|
45
|
+
# Returns the metadata for the given `key`.
|
46
|
+
# @param [Symbol] key
|
47
|
+
# @return [Object]
|
48
|
+
def [](key)
|
49
|
+
@metadata[key]
|
50
|
+
end
|
51
|
+
|
52
|
+
# Sets metadata for the given `key`.
|
53
|
+
# @param [Symbol] key
|
54
|
+
# @param [Object] value
|
55
|
+
def []=(key, value)
|
56
|
+
@metadata[key] = value
|
57
|
+
end
|
33
58
|
end
|
34
59
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
module DNS
|
5
|
+
# Address results from a DNS lookup in {HostResolver}.
|
6
|
+
# @!method initialize(*args)
|
7
|
+
# @option args [Symbol] :address_type The type of address. For example,
|
8
|
+
# :A or :AAAA.
|
9
|
+
# @option args [String] :address The IP address.
|
10
|
+
# @option args [String] :hostname The hostname that was resolved.
|
11
|
+
# @!attribute address_type
|
12
|
+
# The type of address. For example, :A or :AAAA.
|
13
|
+
# @return [Symbol]
|
14
|
+
# @!attribute address
|
15
|
+
# The IP address.
|
16
|
+
# @return [String]
|
17
|
+
# @!attribute hostname
|
18
|
+
# The hostname that was resolved.
|
19
|
+
# @return [String]
|
20
|
+
HostAddress = Struct.new(
|
21
|
+
:address_type,
|
22
|
+
:address,
|
23
|
+
:hostname,
|
24
|
+
keyword_init: true
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Hearth
|
4
|
+
module DNS
|
5
|
+
# Resolves a host name and service to an IP address. Can be used with the
|
6
|
+
# {HTTP::Client} host_resolver option. This implementation uses
|
7
|
+
# Addrinfo.getaddrinfo to resolve the host name.
|
8
|
+
#
|
9
|
+
# @see https://ruby-doc.org/stdlib-3.0.2/libdoc/socket/rdoc/Addrinfo.html
|
10
|
+
class HostResolver
|
11
|
+
# @param [Integer] service (443)
|
12
|
+
# @param [Integer] family (nil)
|
13
|
+
# @param [Symbol] socktype (:SOCK_STREAM)
|
14
|
+
# @param [Integer] protocol (nil)
|
15
|
+
# @param [Integer] flags (nil)
|
16
|
+
def initialize(service: 443, family: nil, socktype: :SOCK_STREAM,
|
17
|
+
protocol: nil, flags: nil)
|
18
|
+
@service = service
|
19
|
+
@family = family
|
20
|
+
@socktype = socktype
|
21
|
+
@protocol = protocol
|
22
|
+
@flags = flags
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Integer]
|
26
|
+
attr_reader :service
|
27
|
+
|
28
|
+
# @return [Integer]
|
29
|
+
attr_reader :family
|
30
|
+
|
31
|
+
# @return [Symbol]
|
32
|
+
attr_reader :socktype
|
33
|
+
|
34
|
+
# @return [Integer]
|
35
|
+
attr_reader :protocol
|
36
|
+
|
37
|
+
# @return [Integer]
|
38
|
+
attr_reader :flags
|
39
|
+
|
40
|
+
# @param [String] nodename
|
41
|
+
# @param (see Hearth::DNS::HostResolver#initialize)
|
42
|
+
def resolve_address(nodename:, **kwargs)
|
43
|
+
options = kwargs.merge(nodename: nodename)
|
44
|
+
addrinfo_list = addrinfo(options)
|
45
|
+
ipv6 = ipv6_addr(addrinfo_list, options) if use_ipv6?
|
46
|
+
ipv4 = ipv4_addr(addrinfo_list, options)
|
47
|
+
[ipv6, ipv4]
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def addrinfo(options)
|
53
|
+
Addrinfo.getaddrinfo(
|
54
|
+
options[:nodename],
|
55
|
+
options.fetch(:service, @service),
|
56
|
+
options.fetch(:family, @family),
|
57
|
+
options.fetch(:socktype, @socktype),
|
58
|
+
options.fetch(:protocol, @protocol),
|
59
|
+
options.fetch(:flags, @flags)
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
def ipv4_addr(addrinfo_list, options)
|
64
|
+
addr = addrinfo_list.find(&:ipv4?)
|
65
|
+
return unless addr
|
66
|
+
|
67
|
+
HostAddress.new(
|
68
|
+
address_type: :A,
|
69
|
+
address: addr.ip_address,
|
70
|
+
hostname: options[:nodename]
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
def ipv6_addr(addrinfo_list, options)
|
75
|
+
addr = addrinfo_list.find(&:ipv6?)
|
76
|
+
return unless addr
|
77
|
+
|
78
|
+
HostAddress.new(
|
79
|
+
address_type: :AAAA,
|
80
|
+
address: addr.ip_address,
|
81
|
+
hostname: options[:nodename]
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def use_ipv6?
|
86
|
+
Socket.ip_address_list.any? do |a|
|
87
|
+
a.ipv6? && !a.ipv6_loopback? && !a.ipv6_linklocal?
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/hearth/dns.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
require_relative 'dns/host_address'
|
6
|
+
require_relative 'dns/host_resolver'
|
7
|
+
|
8
|
+
# These patches are based on resolv-replace
|
9
|
+
# https://github.com/ruby/ruby/blob/master/lib/resolv-replace.rb
|
10
|
+
# We cannot require resolv-replace because it would change DNS resolution
|
11
|
+
# globally. When opening an HTTP request, we will set a thread local variable
|
12
|
+
# to enable custom DNS resolution, and then disable it after the request is
|
13
|
+
# complete. When the thread local variable is not set, we will use the default
|
14
|
+
# Ruby DNS resolution, which may be Resolv or the system resolver.
|
15
|
+
|
16
|
+
# Patch IPSocket
|
17
|
+
# @api private
|
18
|
+
class << IPSocket
|
19
|
+
alias original_hearth_getaddress getaddress
|
20
|
+
|
21
|
+
def getaddress(host)
|
22
|
+
unless (resolver = Thread.current[:net_http_hearth_dns_resolver])
|
23
|
+
return original_hearth_getaddress(host)
|
24
|
+
end
|
25
|
+
|
26
|
+
ipv6, ipv4 = resolver.resolve_address(nodename: host)
|
27
|
+
return ipv6.address if ipv6
|
28
|
+
|
29
|
+
ipv4.address
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Patch TCPSocket
|
34
|
+
# @api private
|
35
|
+
class TCPSocket < IPSocket
|
36
|
+
alias original_hearth_initialize initialize
|
37
|
+
|
38
|
+
# rubocop:disable Lint/MissingSuper
|
39
|
+
def initialize(host, serv, *rest)
|
40
|
+
if Thread.current[:net_http_hearth_dns_resolver]
|
41
|
+
rest[0] = IPSocket.getaddress(rest[0]) if rest[0]
|
42
|
+
original_hearth_initialize(IPSocket.getaddress(host), serv, *rest)
|
43
|
+
else
|
44
|
+
original_hearth_initialize(host, serv, *rest)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
# rubocop:enable Lint/MissingSuper
|
48
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
require 'ipaddr'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
module Hearth
|
8
|
+
# Functions in the Smithy rules engine are named routines that
|
9
|
+
# operate on a finite set of specified inputs, returning an output.
|
10
|
+
# The rules engine has a set of included functions that can be
|
11
|
+
# invoked without additional dependencies, called the standard library.
|
12
|
+
module EndpointRules
|
13
|
+
# An Authentication Scheme supported by an Endpoint
|
14
|
+
# @!attribute scheme_id
|
15
|
+
# The identifier of the authentication scheme.
|
16
|
+
# @return [String]
|
17
|
+
# @!attribute properties
|
18
|
+
# Additional properties of the authentication scheme.
|
19
|
+
# @return [Hash]
|
20
|
+
AuthScheme = Struct.new(
|
21
|
+
:scheme_id,
|
22
|
+
:properties,
|
23
|
+
keyword_init: true
|
24
|
+
) do
|
25
|
+
# @option args [String] :scheme_id
|
26
|
+
# @option args [Hash] :properties ({})
|
27
|
+
def initialize(*args)
|
28
|
+
super
|
29
|
+
self.properties ||= {}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# An Endpoint resolved by an EndpointProvider
|
34
|
+
# @!attribute uri
|
35
|
+
# The URI of the endpoint.
|
36
|
+
# @return [String]
|
37
|
+
# @!attribute auth_schemes
|
38
|
+
# The authentication schemes supported by the endpoint.
|
39
|
+
# @return [Array<AuthScheme>]
|
40
|
+
# @!attribute headers
|
41
|
+
# The headers to include in requests to the endpoint.
|
42
|
+
# @return [Hash]
|
43
|
+
Endpoint = Struct.new(
|
44
|
+
:uri,
|
45
|
+
:auth_schemes,
|
46
|
+
:headers,
|
47
|
+
keyword_init: true
|
48
|
+
) do
|
49
|
+
# @option args [String] :uri
|
50
|
+
# @option args [Array<AuthScheme>] :auth_schemes ([])
|
51
|
+
# @option args [Hash] :headers ({})
|
52
|
+
def initialize(*args)
|
53
|
+
super
|
54
|
+
self.auth_schemes ||= []
|
55
|
+
self.headers ||= {}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Evaluates whether the input string is a compliant RFC 1123 host segment.
|
60
|
+
# When allowSubDomains is true, evaluates whether the input string is
|
61
|
+
# composed of values that are each compliant RFC 1123 host segments
|
62
|
+
# joined by dot (.) characters.
|
63
|
+
# @api private
|
64
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
65
|
+
def self.valid_host_label?(value, allow_sub_domains = false)
|
66
|
+
return false if value.empty?
|
67
|
+
|
68
|
+
if allow_sub_domains
|
69
|
+
labels = value.split('.', -1)
|
70
|
+
return labels.all? { |l| valid_host_label?(l, false) }
|
71
|
+
end
|
72
|
+
|
73
|
+
!!(value =~ /\A(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\z/)
|
74
|
+
end
|
75
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
76
|
+
|
77
|
+
# Computes a URL structure given an input string.
|
78
|
+
# @api private
|
79
|
+
def self.parse_url(value)
|
80
|
+
URL.new(value).as_json
|
81
|
+
rescue ArgumentError, URI::InvalidURIError
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
|
85
|
+
# Computes a portion of a given string based on
|
86
|
+
# the provided start and end indices.
|
87
|
+
# @api private
|
88
|
+
def self.substring(input, start, stop, reverse)
|
89
|
+
return nil if start >= stop || input.size < stop
|
90
|
+
|
91
|
+
return nil if input.chars.any? { |c| c.ord > 127 }
|
92
|
+
|
93
|
+
return input[start...stop] unless reverse
|
94
|
+
|
95
|
+
r_start = input.size - stop
|
96
|
+
r_stop = input.size - start
|
97
|
+
input[r_start...r_stop]
|
98
|
+
end
|
99
|
+
|
100
|
+
# Performs RFC 3986#section-2.1 defined percent-encoding on the input value.
|
101
|
+
# @api private
|
102
|
+
def self.uri_encode(value)
|
103
|
+
CGI.escape(value.encode('UTF-8')).gsub('+', '%20').gsub('%7E', '~')
|
104
|
+
end
|
105
|
+
|
106
|
+
# @api private
|
107
|
+
class URL
|
108
|
+
def initialize(url)
|
109
|
+
uri = URI(url)
|
110
|
+
@scheme = uri.scheme
|
111
|
+
# only support http and https schemes
|
112
|
+
raise ArgumentError unless %w[https http].include?(@scheme)
|
113
|
+
|
114
|
+
# do not support query
|
115
|
+
raise ArgumentError if uri.query
|
116
|
+
|
117
|
+
@authority = _authority(url, uri)
|
118
|
+
@path = uri.path
|
119
|
+
@normalized_path = uri.path + (uri.path[-1] == '/' ? '' : '/')
|
120
|
+
@is_ip = _is_ip(uri.host)
|
121
|
+
end
|
122
|
+
|
123
|
+
attr_reader :scheme, :authority, :path, :normalized_path, :is_ip
|
124
|
+
|
125
|
+
def as_json(_options = {})
|
126
|
+
{
|
127
|
+
'scheme' => scheme,
|
128
|
+
'authority' => authority,
|
129
|
+
'path' => path,
|
130
|
+
'normalizedPath' => normalized_path,
|
131
|
+
'isIp' => is_ip
|
132
|
+
}
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def _authority(url, uri)
|
138
|
+
# don't include port if it's default and not parsed originally
|
139
|
+
if uri.default_port == uri.port && !url.include?(":#{uri.port}")
|
140
|
+
uri.host
|
141
|
+
else
|
142
|
+
"#{uri.host}:#{uri.port}"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def _is_ip(authority)
|
147
|
+
IPAddr.new(authority)
|
148
|
+
true
|
149
|
+
rescue IPAddr::InvalidAddressError
|
150
|
+
false
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -7,23 +7,19 @@ module Hearth
|
|
7
7
|
class ApiError < Hearth::ApiError
|
8
8
|
def initialize(http_resp:, **kwargs)
|
9
9
|
@http_status = http_resp.status
|
10
|
-
@
|
10
|
+
@http_fields = http_resp.fields
|
11
11
|
@http_body = http_resp.body
|
12
|
-
@request_id = http_resp.headers['x-request-id']
|
13
12
|
super(**kwargs)
|
14
13
|
end
|
15
14
|
|
16
15
|
# @return [Integer]
|
17
16
|
attr_reader :http_status
|
18
17
|
|
19
|
-
# @return [
|
20
|
-
attr_reader :
|
18
|
+
# @return [Fields]
|
19
|
+
attr_reader :http_fields
|
21
20
|
|
22
|
-
# @return [
|
21
|
+
# @return [IO]
|
23
22
|
attr_reader :http_body
|
24
|
-
|
25
|
-
# @return [String]
|
26
|
-
attr_reader :request_id
|
27
23
|
end
|
28
24
|
end
|
29
25
|
end
|