rb-net_http-client 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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