rb-net_http-client 0.0.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 43106fa08999d370c0d5d28bdf9dc5ce1fecd7ecb32b72ee96d7b12ed63a7259
4
+ data.tar.gz: 773fba38a078d87ab259dfa8c7a575d68e4cf2307dfed0d7affbacbb09dd2040
5
+ SHA512:
6
+ metadata.gz: e7867815e0b13eefc9b15d35ab29af789879849f8d2d3eca4853cd273e5196764b2cd849a8ec0ff32ddb29b6b33712d76d1a5c80ee9db93ddb413e7ce3c58f22
7
+ data.tar.gz: d278c746b537012f7767f429a1554059db30771ee9348dd7acbabd1620ff6a5c8f074a3771e1bd6ead4cd3e24583ce499334f52cda924e28603f8cd024f911f8
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/https'
4
+ require_relative 'ext'
5
+ require_relative 'schema'
6
+ require_relative '../core/core'
7
+ require_relative '../request/ext'
8
+ require_relative '../response/ext'
9
+
10
+ module NetHTTP
11
+ module_function
12
+
13
+ def client(opts)
14
+ logger = Core.assign_logger(opts[:logger])
15
+
16
+ Core.schema_validation(opts, NetHTTP::Client::Schema, logger) unless opts[:enforce_schema_validation] == false
17
+
18
+ if !(opts[:uri] ||= opts[:url] ||= nil).nil?
19
+ uri = Core.parse_uri((opts[:uri] ||= opts[:url]))
20
+ else
21
+ uri = Core.parse_uri(Core.construct_uri(opts[:scheme], opts[:host], opts[:port], opts[:path]))
22
+ end
23
+
24
+ # Instantiate client:
25
+ client = Net::HTTP.new(uri.host, uri.port)
26
+
27
+ # client config:
28
+ client.logger = logger
29
+ client.uri = uri
30
+ client.host = uri.host
31
+ client.port = uri.port
32
+ client.path = uri.path
33
+ client.use_proxy = Client.use_proxy(opts[:use_proxy])
34
+ client.proxy_uri = Client.proxy_uri((opts[:proxy_uri] ||= opts[:proxy_url]), client.use_proxy)
35
+ client.open_timeout = Client.open_timeout(opts[:open_timeout])
36
+ client.read_timeout = Client.read_timeout(opts[:read_timeout])
37
+
38
+ # SSL config:
39
+ client.use_ssl = Client.use_ssl(opts[:use_ssl], uri.scheme)
40
+
41
+ if client.use_ssl
42
+ pkcs12 = Client.pkcs12(opts[:ssl_path], opts[:pkcs12_file], opts[:pkcs12_passphrase])
43
+ client.cert = Client.cert(pkcs12)
44
+ client.key = Client.key(pkcs12)
45
+ client.ca_file = Client.ca_file(opts[:ssl_path], opts[:ca_file])
46
+ client.verify_mode = Client.verify_mode(opts[:verify_mode])
47
+ end
48
+
49
+ client
50
+ end
51
+ end
data/lib/client/ext.rb ADDED
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../core/core'
4
+
5
+ module NetHTTP
6
+ module Client
7
+ module_function
8
+
9
+ def proxy_uri(proxy_uri, use_proxy)
10
+ return nil if use_proxy == false
11
+
12
+ Core.parse_uri(proxy_uri ||= ENV['http_proxy'] ||= ENV['HTTP_PROXY'] ||= ENV['https_proxy'] ||= ENV['HTTPS_PROXY'])
13
+ end
14
+
15
+ def use_proxy(use_proxy)
16
+ return false if use_proxy == false
17
+
18
+ true
19
+ end
20
+
21
+ def use_ssl(use_ssl, scheme)
22
+ if use_ssl.nil? || use_ssl.to_s.empty?
23
+ return false if scheme == 'http'
24
+ return true if scheme == 'https'
25
+ end
26
+ return false if use_ssl == false
27
+
28
+ true
29
+ end
30
+
31
+ def open_timeout(open_timeout)
32
+ (open_timeout ||= 60).to_s.to_i
33
+ end
34
+
35
+ def read_timeout(read_timeout)
36
+ (read_timeout ||= 60).to_s.to_i
37
+ end
38
+
39
+ def pkcs12(ssl_path, pkcs12_file, pkcs12_passphrase)
40
+ return nil if ssl_path.nil?
41
+ return nil if ssl_path.to_s.empty?
42
+ return nil if pkcs12_file.nil?
43
+ return nil if pkcs12_file.to_s.empty?
44
+ return nil if pkcs12_passphrase.nil?
45
+ return nil if pkcs12_passphrase.to_s.empty?
46
+
47
+ OpenSSL::PKCS12.new(File.binread(ssl_path + '/' + pkcs12_file), pkcs12_passphrase)
48
+ end
49
+
50
+ def cert(pkcs12)
51
+ return nil if pkcs12.nil?
52
+ return nil if pkcs12.to_s.empty?
53
+
54
+ OpenSSL::X509::Certificate.new(pkcs12.certificate)
55
+ end
56
+
57
+ def key(pkcs12)
58
+ return nil if pkcs12.nil?
59
+ return nil if pkcs12.to_s.empty?
60
+
61
+ OpenSSL::PKey::RSA.new(pkcs12.key)
62
+ end
63
+
64
+ def ca_file(ssl_path, ca_file)
65
+ return nil if ssl_path.nil?
66
+ return nil if ssl_path.to_s.empty?
67
+ return nil if ca_file.nil?
68
+ return nil if ca_file.to_s.empty?
69
+
70
+ File.binread(ssl_path + '/' + ca_file)
71
+ end
72
+
73
+ def verify_mode(verify_mode)
74
+ return OpenSSL::SSL::VERIFY_NONE if verify_mode.nil?
75
+ return OpenSSL::SSL::VERIFY_NONE if verify_mode.to_s.empty?
76
+
77
+ verify_mode
78
+ end
79
+
80
+ module Ext
81
+ # TODO: Define public / private
82
+ # Also look into module_function and how that impacts attr_reader / attr_writer
83
+ attr_reader :host,
84
+ :path,
85
+ :logger,
86
+ :uri,
87
+ :url,
88
+ :use_proxy,
89
+ :use_ssl
90
+
91
+ attr_writer :host,
92
+ :port,
93
+ :path,
94
+ :logger,
95
+ :uri,
96
+ :url,
97
+ :use_proxy,
98
+ :use_ssl
99
+
100
+ def proxy_uri=(proxy_uri)
101
+ if proxy_uri.class.ancestors.include? URI
102
+ @proxy_address = URI(proxy_uri)
103
+ @proxy_port = URI(proxy_uri).port
104
+ @proxy_uri = URI(proxy_uri)
105
+ else
106
+ @proxy_address = nil
107
+ @proxy_port = nil
108
+ @proxy_uri = nil
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ module Net
116
+ class HTTP
117
+ include NetHTTP::Core
118
+ include NetHTTP::Client::Ext
119
+ end
120
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-validation'
4
+
5
+ module NetHTTP
6
+ module Client
7
+ Schema = Dry::Validation.Schema do
8
+ configure do
9
+ def true_or_false
10
+ [true, false]
11
+ end
12
+ end
13
+
14
+ optional(:logger).filled
15
+ optional(:uri).maybe(type?: String)
16
+ optional(:url).maybe(type?: String)
17
+ optional(:scheme).maybe(type?: String)
18
+ optional(:host).maybe(type?: String)
19
+ optional(:port).maybe(type?: Integer)
20
+ optional(:path).maybe(type?: String)
21
+ optional(:proxy_uri).filled(type?: String)
22
+ optional(:proxy_url).filled(type?: String)
23
+ optional(:use_proxy).filled(included_in?: true_or_false)
24
+ optional(:use_ssl).filled(included_in?: true_or_false)
25
+ optional(:open_timeout).filled(type?: Integer)
26
+ optional(:read_timeout).filled(type?: Integer)
27
+
28
+ rule(if_url_and_uri_are_nil_must_provide_host: [:uri, :url, :host]) do |uri, url, host|
29
+ uri.empty?.then(url.empty?.then(host.filled?))
30
+ end
31
+
32
+ rule(if_url_and_uri_are_nil_must_provide_scheme_or_port: [:uri, :url, :scheme, :port]) do |uri, url, scheme, port|
33
+ uri.empty?.then(url.empty?.then(scheme.empty?.then(port.filled?)))
34
+ uri.empty?.then(url.empty?.then(port.empty?.then(scheme.filled?)))
35
+ end
36
+ end
37
+ end
38
+ end
data/lib/core/core.rb ADDED
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require 'nokogiri'
5
+ require 'uri'
6
+
7
+ module NetHTTP
8
+ module Core
9
+ def logger
10
+ @logger || send('logger=', nil)
11
+ end
12
+
13
+ def logger=(logger = nil)
14
+ @logger = assign_logger(logger)
15
+ end
16
+
17
+ module_function
18
+
19
+ def assign_logger(logger = nil)
20
+ return logger if logger.class == Logger
21
+
22
+ if logger.nil? || logger.to_s.empty?
23
+ logger = Logger.new(STDOUT)
24
+ logger.level = Logger::INFO
25
+ end
26
+ logger
27
+ end
28
+
29
+ def construct_uri(scheme, host, port, path)
30
+ return nil if host.nil?
31
+
32
+ uri_scheme = case scheme
33
+ when 'http', 'https'
34
+ "#{scheme}://"
35
+ end
36
+ uri_port = if port.nil? || port.to_s.empty?
37
+ nil
38
+ else
39
+ ":#{port.to_i}"
40
+ end
41
+ "#{uri_scheme}#{host}#{uri_port}#{path}"
42
+ end
43
+
44
+ def parse_uri(uri)
45
+ return if uri.nil?
46
+ return if uri.to_s.empty?
47
+
48
+ parsed_uri = URI(uri)
49
+
50
+ scheme = parsed_uri.to_s.scan(%r{(https|http):\/\/}).flatten[0]
51
+ port = parsed_uri.to_s.scan(%r{:(\d+)\/}).flatten[0] ||= parsed_uri.port
52
+
53
+ return URI(parsed_uri) if scheme == 'http'
54
+ return URI(parsed_uri) if scheme == 'https'
55
+
56
+ case port
57
+ when 80, '80'
58
+ URI("http://#{parsed_uri.to_s.gsub("#{scheme}://", '')}")
59
+ else
60
+ URI("https://#{parsed_uri.to_s.gsub("#{scheme}://", '')}")
61
+ end
62
+ end
63
+
64
+ def schema_validation(opts, schema, logger = nil)
65
+ results = schema.call(opts)
66
+ return if results.success?
67
+
68
+ if logger.nil? || logger.to_s.empty?
69
+ else
70
+ logger.debug("NetHTTP::Core::Error - schema input validation failed due to => #{results.messages}")
71
+ end
72
+ raise 'NetHTTP::Core::Error - schema input validation failed.'
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,243 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'nokogiri'
5
+ require 'yaml'
6
+
7
+ module NetHTTP
8
+ module Core
9
+ module Utilities
10
+ module_function
11
+
12
+ # CamelCase to snake_case
13
+ def camel_2_snake(key, type = nil)
14
+ new_key = key.to_s
15
+ .tr('::', '/')
16
+ .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
17
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
18
+ .tr('-', '_')
19
+ .downcase
20
+
21
+ case type.downcase
22
+ when 'string'
23
+ return new_key.to_s
24
+ when 'symbol'
25
+ return new_key.to_sym
26
+ end
27
+
28
+ new_key
29
+ end
30
+
31
+ # snake_case to CamelCase
32
+ def snake_2_camel(key, type = nil)
33
+ new_key = key.to_s.split('_')
34
+ new_key = new_key[0].downcase + new_key[1..-1].map(&:capitalize).join('')
35
+
36
+ case type.downcase
37
+ when 'string'
38
+ return new_key.to_s
39
+ when 'symbol'
40
+ return new_key.to_sym
41
+ end
42
+
43
+ new_key
44
+ end
45
+
46
+ # convert hash / array / nested object keys to either snake_case or CamelCase
47
+ # format -> 'snake' or 'camel'
48
+ # type -> 'string' or 'symbol'
49
+ def convert_hash_keys(request = {})
50
+ return request[:object] if request[:format].nil? && request[:type].nil?
51
+
52
+ case request[:object]
53
+ when Hash
54
+ new_hash = {}
55
+ request[:object].each do |key, value|
56
+ value = convert_hash_keys(
57
+ object: value,
58
+ format: request[:format],
59
+ type: request[:type]
60
+ )
61
+ case request[:format].downcase
62
+ when 'snake'
63
+ new_key = camel_2_snake(key, request[:type])
64
+ when 'camel'
65
+ new_key = snake_2_camel(key, request[:type])
66
+ end
67
+ new_hash[new_key] = value
68
+ end
69
+ return new_hash
70
+ when Array
71
+ return request[:object].map { |value| convert_hash_keys(object: value, format: request[:format], type: request[:type]) }
72
+ end
73
+
74
+ request[:object]
75
+ end
76
+
77
+ # Convert JSON doc to a Ruby Hash.
78
+ def json_2_hash(json_doc, type = 'symbol', logger = nil)
79
+ msg = "Invalid 'type' => #{type}. Use either 'string' or 'symbol' (default)."
80
+ unless ['string', 'symbol'].include?(type.downcase)
81
+ if logger.nil? || logger.to_s.empty?
82
+ puts msg
83
+ else
84
+ logger.debug(msg)
85
+ end
86
+ raise msg
87
+ end
88
+
89
+ json_doc = JSON.parse(json_doc) if json_doc.class == String
90
+
91
+ begin
92
+ convert_hash_keys(
93
+ object: json_doc,
94
+ format: 'snake',
95
+ type: type.downcase
96
+ )
97
+ rescue RuntimeError => err
98
+ raise err
99
+ end
100
+ end
101
+
102
+ # Convert XML doc to a Ruby Hash.
103
+ def xml_2_hash(xml_doc, type = 'symbol', logger = nil)
104
+ msg = "Invalid 'type' => #{type}. Use either 'string' or 'symbol' (default)."
105
+ unless ['string', 'symbol'].include?(type.downcase)
106
+ if logger.nil? || logger.to_s.empty?
107
+ puts msg
108
+ else
109
+ logger.debug(msg)
110
+ end
111
+ raise msg
112
+ end
113
+
114
+ xml_doc = Hash.from_xml(format_xml_doc(xml_doc))
115
+ begin
116
+ convert_hash_keys(
117
+ object: xml_doc,
118
+ format: 'snake',
119
+ type: type.downcase
120
+ )
121
+ rescue RuntimeError => err
122
+ raise err
123
+ end
124
+ end
125
+
126
+ def format_xml_doc(xml_doc)
127
+ case xml_doc
128
+ when String
129
+ formatted_xml_doc = Nokogiri::XML(xml_doc) { |c| c.options = Nokogiri::XML::ParseOptions::STRICT }
130
+ formatted_xml_doc = formatted_xml_doc.remove_namespaces!.to_s
131
+ when Nokogiri::XML::Document
132
+ formatted_xml_doc = xml_doc.remove_namespaces!.to_s
133
+ else
134
+ raise "Unrecognized 'xml_doc' class => '#{xml_doc.class}'"
135
+ end
136
+
137
+ formatted_xml_doc
138
+ end
139
+
140
+ # Convert YAML doc to a Ruby Hash.
141
+ def yaml_2_hash(yaml_doc, type = 'symbol', logger = nil)
142
+ msg = "Invalid 'type' => #{type}. Use either 'string' or 'symbol' (default)."
143
+ unless ['string', 'symbol'].include?(type.downcase)
144
+ if logger.nil? || logger.to_s.empty?
145
+ puts msg
146
+ else
147
+ logger.debug(msg)
148
+ end
149
+ raise msg
150
+ end
151
+
152
+ case yaml
153
+ when Hash
154
+ yaml_doc = yaml_doc.to_hash
155
+ when String
156
+ yaml_doc = YAML.safe_load(yaml_doc).to_hash
157
+ end
158
+
159
+ begin
160
+ convert_hash_keys(
161
+ object: yaml_doc,
162
+ format: 'snake',
163
+ type: type.downcase
164
+ )
165
+ rescue RuntimeError => err
166
+ raise err
167
+ end
168
+ end
169
+
170
+ def valid_json?(json_doc, logger = nil)
171
+ begin
172
+ return false if json_doc.nil?
173
+ return false if json_doc.empty?
174
+
175
+ JSON.parse(json_doc)
176
+ rescue JSON::ParserError => err
177
+ if logger.nil? || logger.to_s.empty?
178
+ puts 'WARNING - JSON syntax / parsing errors detected:'
179
+ puts err
180
+ else
181
+ logger.debug('WARNING - JSON syntax / parsing errors detected:')
182
+ logger.debug(err)
183
+ end
184
+ return false
185
+ end
186
+
187
+ true
188
+ end
189
+
190
+ def valid_xml?(xml_doc, logger = nil)
191
+ begin
192
+ return false if xml_doc.nil?
193
+ return false if xml_doc.empty?
194
+
195
+ begin
196
+ parse_errors = Nokogiri::XML(xml_doc).errors { |c| c.options = Nokogiri::XML::ParseOptions::STRICT }
197
+ Nokogiri::XML(xml_doc) { |c| c.options = Nokogiri::XML::ParseOptions::STRICT }
198
+ rescue Nokogiri::XML::SyntaxError
199
+ if logger.nil? || logger.to_s.empty?
200
+ puts 'WARNING - XML syntax / parsing errors detected:'
201
+ puts parse_errors
202
+ else
203
+ logger.debug('WARNING - XML parsing / syntax errors detected:')
204
+ logger.debug(parse_errors)
205
+ end
206
+ return false
207
+ end
208
+ end
209
+
210
+ true
211
+ end
212
+
213
+ def valid_html?(html_doc, logger = nil)
214
+ begin
215
+ return false if html_doc.nil?
216
+ return false if html_doc.empty?
217
+ return false unless html_doc.include?('<html>')
218
+ return false unless html_doc.include?('</html>')
219
+ return false unless html_doc.include?('<body>')
220
+ return false unless html_doc.include?('</body>')
221
+ return false unless Nokogiri::HTML(html_doc).errors.empty?
222
+
223
+ begin
224
+ parse_errors = Nokogiri::HTML.parse(html_doc).validate
225
+ rescue Nokogiri::XML::SyntaxError
226
+ if logger.nil? || logger.to_s.empty?
227
+ puts 'WARNING - HTML syntax / parsing errors detected:'
228
+ puts parse_errors
229
+ else
230
+ logger.debug('WARNING - HTML syntax / parsing errors detected:')
231
+ logger.debug(parse_errors)
232
+ end
233
+ return true
234
+ end
235
+ rescue RuntimeError => err
236
+ raise err
237
+ end
238
+
239
+ true
240
+ end
241
+ end
242
+ end
243
+ end