nice_http 1.7.2 → 1.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +607 -581
- data/lib/nice_http/http_methods.rb +526 -526
- data/lib/nice_http/manage_request.rb +237 -237
- data/lib/nice_http/manage_response.rb +280 -280
- data/lib/nice_http/utils.rb +109 -109
- data/lib/nice_http.rb +414 -411
- metadata +2 -2
data/lib/nice_http.rb
CHANGED
@@ -1,411 +1,414 @@
|
|
1
|
-
require "logger"
|
2
|
-
require "nice_hash"
|
3
|
-
require_relative "nice_http/utils"
|
4
|
-
require_relative "nice_http/manage_request"
|
5
|
-
require_relative "nice_http/manage_response"
|
6
|
-
require_relative "nice_http/http_methods"
|
7
|
-
|
8
|
-
######################################################
|
9
|
-
# Attributes you can access using NiceHttp.the_attribute:
|
10
|
-
# :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port,
|
11
|
-
# :last_request, :last_response, :request_id, :use_mocks, :connections,
|
12
|
-
# :active, :auto_redirect, :values_for, :create_stats, :stats
|
13
|
-
#
|
14
|
-
# @attr [String] host The host to be accessed
|
15
|
-
# @attr [Integer] port The port number
|
16
|
-
# @attr [Boolean] ssl If you use ssl or not
|
17
|
-
# @attr [Hash] headers Contains the headers you will be using on your connection
|
18
|
-
# @attr [Boolean] debug In case true shows all the details of the communication with the host
|
19
|
-
# @attr [String, Symbol] log :fix_file, :no, :screen, :file, "path and file name".
|
20
|
-
# :fix_file, will log the communication on nice_http.log. (default).
|
21
|
-
# :no, will not generate any logs.
|
22
|
-
# :screen, will print the logs on the screen.
|
23
|
-
# :file, will be generated a log file with name: nice_http_YY-mm-dd-HHMMSS.log.
|
24
|
-
# :file_run, will generate a log file with the name where the object was created and extension .log, fex: myfile.rb.log
|
25
|
-
# String the path and file name where the logs will be stored.
|
26
|
-
# @attr [String] proxy_host the proxy host to be used
|
27
|
-
# @attr [Integer] proxy_port the proxy port to be used
|
28
|
-
# @attr [String] last_request The last request with all the content sent
|
29
|
-
# @attr [String] last_response Only in case :debug is true, the last response with all the content
|
30
|
-
# @attr [String] request_id If the response includes a requestId, will be stored here
|
31
|
-
# @attr [Boolean] use_mocks If true, in case the request hash includes a :mock_response key, it will be used as the response instead
|
32
|
-
# @attr [Array] connections It will include all the active connections (NiceHttp instances)
|
33
|
-
# @attr [Integer] active Number of active connections
|
34
|
-
# @attr [Boolean] auto_redirect If true, NiceHttp will take care of the auto redirections when required by the responses
|
35
|
-
# @attr [Hash] response Contains the full response hash
|
36
|
-
# @attr [Integer] num_redirects Number of consecutive redirections managed
|
37
|
-
# @attr [Hash] headers The updated headers of the communication
|
38
|
-
# @attr [Hash] cookies Cookies set. The key is the path (String) where cookies are set and the value a Hash with pairs of cookie keys and values, example:
|
39
|
-
# { '/' => { "cfid" => "d95adfas2550255", "amddom.settings" => "doom" } }
|
40
|
-
# @attr [Logger] logger An instance of the Logger class where logs will be stored. You can access on anytime to store specific data, for example:
|
41
|
-
# my_http.logger.info "add this to the log file"
|
42
|
-
# @see https://ruby-doc.org/stdlib-2.5.0/libdoc/logger/rdoc/Logger.html
|
43
|
-
# @attr [Hash] values_for The default values to set on the data in case not specified others
|
44
|
-
# @attr [Boolean] create_stats If true, NiceHttp will create stats of the http communication and store them on NiceHttp.stats hash
|
45
|
-
# @attr [Hash] stats It contains detailed stats of the http communication
|
46
|
-
######################################################
|
47
|
-
class NiceHttp
|
48
|
-
include NiceHttpManageRequest
|
49
|
-
include NiceHttpManageResponse
|
50
|
-
include NiceHttpHttpMethods
|
51
|
-
|
52
|
-
Error = Class.new StandardError
|
53
|
-
|
54
|
-
InfoMissing = Class.new Error do
|
55
|
-
attr_reader :attribute
|
56
|
-
|
57
|
-
def initialize(attribute)
|
58
|
-
@attribute = attribute
|
59
|
-
message = "It was not possible to create the http connection!!!\n"
|
60
|
-
message += "Wrong #{attribute}, remember to supply http:// or https:// in case you specify an url to create the http connection, for example:\n"
|
61
|
-
message += "http = NiceHttp.new('http://example.com')"
|
62
|
-
super message
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
class << self
|
67
|
-
attr_accessor :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port,
|
68
|
-
:last_request, :last_response, :request_id, :use_mocks, :connections,
|
69
|
-
:active, :auto_redirect, :log_files, :values_for, :create_stats, :stats
|
70
|
-
end
|
71
|
-
|
72
|
-
at_exit do
|
73
|
-
if self.create_stats
|
74
|
-
require 'yaml'
|
75
|
-
self.stats.keys.each do |key|
|
76
|
-
File.open("./nice_http_stats_#{key}.yaml", "w") { |file| file.write(self.stats[key].to_yaml) }
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
######################################################
|
82
|
-
# to reset to the original defaults
|
83
|
-
######################################################
|
84
|
-
def self.reset!
|
85
|
-
@host = nil
|
86
|
-
@port = 80
|
87
|
-
@ssl = false
|
88
|
-
@headers = {}
|
89
|
-
@values_for = {}
|
90
|
-
@debug = false
|
91
|
-
@log = :fix_file
|
92
|
-
@proxy_host = nil
|
93
|
-
@proxy_port = nil
|
94
|
-
@last_request = nil
|
95
|
-
@last_response = nil
|
96
|
-
@request_id = ""
|
97
|
-
@use_mocks = false
|
98
|
-
@connections = []
|
99
|
-
@active = 0
|
100
|
-
@auto_redirect = true
|
101
|
-
@log_files = {}
|
102
|
-
@create_stats = false
|
103
|
-
@stats = {
|
104
|
-
all: {
|
105
|
-
num_requests: 0,
|
106
|
-
time_elapsed: {
|
107
|
-
total: 0,
|
108
|
-
maximum: 0,
|
109
|
-
minimum: 100000,
|
110
|
-
average: 0,
|
111
|
-
},
|
112
|
-
method: {},
|
113
|
-
},
|
114
|
-
path: {},
|
115
|
-
name: {},
|
116
|
-
}
|
117
|
-
end
|
118
|
-
reset!
|
119
|
-
|
120
|
-
######################################################
|
121
|
-
# If inheriting from NiceHttp class
|
122
|
-
######################################################
|
123
|
-
def self.inherited(subclass)
|
124
|
-
subclass.reset!
|
125
|
-
end
|
126
|
-
|
127
|
-
attr_reader :host, :port, :ssl, :debug, :log, :proxy_host, :proxy_port, :response, :num_redirects
|
128
|
-
attr_accessor :headers, :cookies, :use_mocks, :auto_redirect, :logger, :values_for
|
129
|
-
|
130
|
-
######################################################
|
131
|
-
# Change the default values for NiceHttp supplying a Hash
|
132
|
-
#
|
133
|
-
# @param par [Hash] keys: :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port, :use_mocks, :auto_redirect, :values_for, :create_stats
|
134
|
-
######################################################
|
135
|
-
def self.defaults=(par = {})
|
136
|
-
@host = par[:host] if par.key?(:host)
|
137
|
-
@port = par[:port] if par.key?(:port)
|
138
|
-
@ssl = par[:ssl] if par.key?(:ssl)
|
139
|
-
@headers = par[:headers].dup if par.key?(:headers)
|
140
|
-
@values_for = par[:values_for].dup if par.key?(:values_for)
|
141
|
-
@debug = par[:debug] if par.key?(:debug)
|
142
|
-
@log = par[:log] if par.key?(:log)
|
143
|
-
@proxy_host = par[:proxy_host] if par.key?(:proxy_host)
|
144
|
-
@proxy_port = par[:proxy_port] if par.key?(:proxy_port)
|
145
|
-
@use_mocks = par[:use_mocks] if par.key?(:use_mocks)
|
146
|
-
@auto_redirect = par[:auto_redirect] if par.key?(:auto_redirect)
|
147
|
-
@create_stats = par[:create_stats] if par.key?(:create_stats)
|
148
|
-
end
|
149
|
-
|
150
|
-
######################################################
|
151
|
-
# To add specific stats
|
152
|
-
# The stats will be added to NiceHttp.stats[:specific]
|
153
|
-
#
|
154
|
-
# @param name [Symbol] name to group your specific stats
|
155
|
-
# @param state [Symbol] state of the name supplied to group your specific stats
|
156
|
-
# @param started [Time] when the process you want the stats started
|
157
|
-
# @param finished [Time] when the process you want the stats finished
|
158
|
-
#
|
159
|
-
# @example
|
160
|
-
# started = Time.now
|
161
|
-
# @http.send_request Requests::Customer.add_customer
|
162
|
-
# 30.times do
|
163
|
-
# resp = @http.get(Requests::Customer.get_customer)
|
164
|
-
# break if resp.code == 200
|
165
|
-
# sleep 0.5
|
166
|
-
# end
|
167
|
-
# NiceHttp.add_stats(:customer, :create, started, Time.now)
|
168
|
-
######################################################
|
169
|
-
def self.add_stats(name, state, started, finished)
|
170
|
-
self.stats[:specific] ||= {}
|
171
|
-
self.stats[:specific][name] ||= {num: 0, time_elapsed: {total:0, maximum:0, minimum:1000, average: 0}}
|
172
|
-
self.stats[:specific][name][:num] += 1
|
173
|
-
time_elapsed = self.stats[:specific][name][:time_elapsed]
|
174
|
-
time_elapsed[:total] += finished - started
|
175
|
-
time_elapsed[:maximum] = (finished - started) if time_elapsed[:maximum]<(finished-started)
|
176
|
-
time_elapsed[:minimum] = (finished - started) if time_elapsed[:minimum]>(finished-started)
|
177
|
-
time_elapsed[:average] = time_elapsed[:total]/self.stats[:specific][name][:num]
|
178
|
-
|
179
|
-
self.stats[:specific][name][state] ||= {num: 0, time_elapsed: {total:0, maximum:0, minimum:1000, average: 0}}
|
180
|
-
self.stats[:specific][name][state][:num] += 1
|
181
|
-
time_elapsed = self.stats[:specific][name][state][:time_elapsed]
|
182
|
-
time_elapsed[:total] += finished - started
|
183
|
-
time_elapsed[:maximum] = (finished - started) if time_elapsed[:maximum]<(finished-started)
|
184
|
-
time_elapsed[:minimum] = (finished - started) if time_elapsed[:minimum]>(finished-started)
|
185
|
-
time_elapsed[:average] = time_elapsed[:total]/self.stats[:specific][name][state][:num]
|
186
|
-
end
|
187
|
-
|
188
|
-
|
189
|
-
######################################################
|
190
|
-
# Creates a new http connection.
|
191
|
-
#
|
192
|
-
# @param args [] If no parameter supplied, by default will access how is setup on defaults
|
193
|
-
# @example
|
194
|
-
# http = NiceHttp.new()
|
195
|
-
# @param args [String]. The url to create the connection.
|
196
|
-
# @example
|
197
|
-
# http = NiceHttp.new("https://www.example.com")
|
198
|
-
# @example
|
199
|
-
# http = NiceHttp.new("example.com:8999")
|
200
|
-
# @example
|
201
|
-
# http = NiceHttp.new("localhost:8322")
|
202
|
-
# @param args [Hash] containing these possible keys:
|
203
|
-
#
|
204
|
-
# host -- example.com. (default blank screen)
|
205
|
-
#
|
206
|
-
# port -- port for the connection. 80 (default)
|
207
|
-
#
|
208
|
-
# ssl -- true, false (default)
|
209
|
-
#
|
210
|
-
# headers -- hash with the headers
|
211
|
-
#
|
212
|
-
# values_for -- hash with the values_for
|
213
|
-
#
|
214
|
-
# debug -- true, false (default)
|
215
|
-
#
|
216
|
-
# log -- :no, :screen, :file, :fix_file (default).
|
217
|
-
#
|
218
|
-
# A string with a path can be supplied.
|
219
|
-
#
|
220
|
-
# If :fix_file: nice_http.log
|
221
|
-
#
|
222
|
-
# In case :file it will be generated a log file with name: nice_http_YY-mm-dd-HHMMSS.log
|
223
|
-
#
|
224
|
-
# proxy_host
|
225
|
-
#
|
226
|
-
# proxy_port
|
227
|
-
# @example
|
228
|
-
# http2 = NiceHttp.new( host: "reqres.in", port: 443, ssl: true )
|
229
|
-
# @example
|
230
|
-
# my_server = {host: "example.com",
|
231
|
-
# port: 80,
|
232
|
-
# headers: {"api-key": "zdDDdjkck"}
|
233
|
-
# }
|
234
|
-
# http3 = NiceHttp.new my_server
|
235
|
-
######################################################
|
236
|
-
def initialize(args = {})
|
237
|
-
require "net/http"
|
238
|
-
require "net/https"
|
239
|
-
@host = self.class.host
|
240
|
-
@port = self.class.port
|
241
|
-
@prepath = ""
|
242
|
-
@ssl = self.class.ssl
|
243
|
-
@headers = self.class.headers.dup
|
244
|
-
@values_for = self.class.values_for.dup
|
245
|
-
@debug = self.class.debug
|
246
|
-
@log = self.class.log
|
247
|
-
@proxy_host = self.class.proxy_host
|
248
|
-
@proxy_port = self.class.proxy_port
|
249
|
-
@use_mocks = self.class.use_mocks
|
250
|
-
@auto_redirect = false #set it up at the end of initialize
|
251
|
-
auto_redirect = self.class.auto_redirect
|
252
|
-
@num_redirects = 0
|
253
|
-
@create_stats = self.class.create_stats
|
254
|
-
|
255
|
-
#todo: set only the cookies for the current domain
|
256
|
-
#key: path, value: hash with key is the name of the cookie and value the value
|
257
|
-
# we set the default value for non existing keys to empty Hash {} so in case of merge there is no problem
|
258
|
-
@cookies = Hash.new { |h, k| h[k] = {} }
|
259
|
-
|
260
|
-
if args.is_a?(String)
|
261
|
-
uri = URI.parse(args)
|
262
|
-
@host = uri.host unless uri.host.nil?
|
263
|
-
@port = uri.port unless uri.port.nil?
|
264
|
-
@ssl = true if !uri.scheme.nil? && (uri.scheme == "https")
|
265
|
-
@prepath = uri.path unless uri.path == "/"
|
266
|
-
elsif args.is_a?(Hash) && !args.keys.empty?
|
267
|
-
@host = args[:host] if args.keys.include?(:host)
|
268
|
-
@port = args[:port] if args.keys.include?(:port)
|
269
|
-
@ssl = args[:ssl] if args.keys.include?(:ssl)
|
270
|
-
@headers = args[:headers].dup if args.keys.include?(:headers)
|
271
|
-
@values_for = args[:values_for].dup if args.keys.include?(:values_for)
|
272
|
-
@debug = args[:debug] if args.keys.include?(:debug)
|
273
|
-
@log = args[:log] if args.keys.include?(:log)
|
274
|
-
@proxy_host = args[:proxy_host] if args.keys.include?(:proxy_host)
|
275
|
-
@proxy_port = args[:proxy_port] if args.keys.include?(:proxy_port)
|
276
|
-
@use_mocks = args[:use_mocks] if args.keys.include?(:use_mocks)
|
277
|
-
auto_redirect = args[:auto_redirect] if args.keys.include?(:auto_redirect)
|
278
|
-
end
|
279
|
-
|
280
|
-
begin
|
281
|
-
log_filename = ""
|
282
|
-
if @log.kind_of?(String) or @log == :fix_file or @log == :file or @log == :file_run
|
283
|
-
if @log.kind_of?(String)
|
284
|
-
log_filename = @log
|
285
|
-
elsif @log == :fix_file
|
286
|
-
log_filename = "nice_http.log"
|
287
|
-
elsif @log == :file
|
288
|
-
log_filename = "nice_http_#{Time.now.strftime("%Y-%m-%d-%H%M%S")}.log"
|
289
|
-
elsif @log == :file_run
|
290
|
-
log_filename = "#{caller.first[/[^:]+/]}.log"
|
291
|
-
end
|
292
|
-
if
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
@
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
raise InfoMissing, :
|
325
|
-
raise InfoMissing, :
|
326
|
-
raise InfoMissing, :
|
327
|
-
raise InfoMissing, :
|
328
|
-
raise InfoMissing, :
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
@http
|
336
|
-
@http.
|
337
|
-
|
338
|
-
@http =
|
339
|
-
@http.
|
340
|
-
|
341
|
-
@http
|
342
|
-
@http.
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
@
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
@http = nil
|
398
|
-
@logger.
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
end
|
1
|
+
require "logger"
|
2
|
+
require "nice_hash"
|
3
|
+
require_relative "nice_http/utils"
|
4
|
+
require_relative "nice_http/manage_request"
|
5
|
+
require_relative "nice_http/manage_response"
|
6
|
+
require_relative "nice_http/http_methods"
|
7
|
+
|
8
|
+
######################################################
|
9
|
+
# Attributes you can access using NiceHttp.the_attribute:
|
10
|
+
# :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port,
|
11
|
+
# :last_request, :last_response, :request_id, :use_mocks, :connections,
|
12
|
+
# :active, :auto_redirect, :values_for, :create_stats, :stats
|
13
|
+
#
|
14
|
+
# @attr [String] host The host to be accessed
|
15
|
+
# @attr [Integer] port The port number
|
16
|
+
# @attr [Boolean] ssl If you use ssl or not
|
17
|
+
# @attr [Hash] headers Contains the headers you will be using on your connection
|
18
|
+
# @attr [Boolean] debug In case true shows all the details of the communication with the host
|
19
|
+
# @attr [String, Symbol] log :fix_file, :no, :screen, :file, "path and file name".
|
20
|
+
# :fix_file, will log the communication on nice_http.log. (default).
|
21
|
+
# :no, will not generate any logs.
|
22
|
+
# :screen, will print the logs on the screen.
|
23
|
+
# :file, will be generated a log file with name: nice_http_YY-mm-dd-HHMMSS.log.
|
24
|
+
# :file_run, will generate a log file with the name where the object was created and extension .log, fex: myfile.rb.log
|
25
|
+
# String the path and file name where the logs will be stored.
|
26
|
+
# @attr [String] proxy_host the proxy host to be used
|
27
|
+
# @attr [Integer] proxy_port the proxy port to be used
|
28
|
+
# @attr [String] last_request The last request with all the content sent
|
29
|
+
# @attr [String] last_response Only in case :debug is true, the last response with all the content
|
30
|
+
# @attr [String] request_id If the response includes a requestId, will be stored here
|
31
|
+
# @attr [Boolean] use_mocks If true, in case the request hash includes a :mock_response key, it will be used as the response instead
|
32
|
+
# @attr [Array] connections It will include all the active connections (NiceHttp instances)
|
33
|
+
# @attr [Integer] active Number of active connections
|
34
|
+
# @attr [Boolean] auto_redirect If true, NiceHttp will take care of the auto redirections when required by the responses
|
35
|
+
# @attr [Hash] response Contains the full response hash
|
36
|
+
# @attr [Integer] num_redirects Number of consecutive redirections managed
|
37
|
+
# @attr [Hash] headers The updated headers of the communication
|
38
|
+
# @attr [Hash] cookies Cookies set. The key is the path (String) where cookies are set and the value a Hash with pairs of cookie keys and values, example:
|
39
|
+
# { '/' => { "cfid" => "d95adfas2550255", "amddom.settings" => "doom" } }
|
40
|
+
# @attr [Logger] logger An instance of the Logger class where logs will be stored. You can access on anytime to store specific data, for example:
|
41
|
+
# my_http.logger.info "add this to the log file"
|
42
|
+
# @see https://ruby-doc.org/stdlib-2.5.0/libdoc/logger/rdoc/Logger.html
|
43
|
+
# @attr [Hash] values_for The default values to set on the data in case not specified others
|
44
|
+
# @attr [Boolean] create_stats If true, NiceHttp will create stats of the http communication and store them on NiceHttp.stats hash
|
45
|
+
# @attr [Hash] stats It contains detailed stats of the http communication
|
46
|
+
######################################################
|
47
|
+
class NiceHttp
|
48
|
+
include NiceHttpManageRequest
|
49
|
+
include NiceHttpManageResponse
|
50
|
+
include NiceHttpHttpMethods
|
51
|
+
|
52
|
+
Error = Class.new StandardError
|
53
|
+
|
54
|
+
InfoMissing = Class.new Error do
|
55
|
+
attr_reader :attribute
|
56
|
+
|
57
|
+
def initialize(attribute)
|
58
|
+
@attribute = attribute
|
59
|
+
message = "It was not possible to create the http connection!!!\n"
|
60
|
+
message += "Wrong #{attribute}, remember to supply http:// or https:// in case you specify an url to create the http connection, for example:\n"
|
61
|
+
message += "http = NiceHttp.new('http://example.com')"
|
62
|
+
super message
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class << self
|
67
|
+
attr_accessor :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port,
|
68
|
+
:last_request, :last_response, :request_id, :use_mocks, :connections,
|
69
|
+
:active, :auto_redirect, :log_files, :values_for, :create_stats, :stats
|
70
|
+
end
|
71
|
+
|
72
|
+
at_exit do
|
73
|
+
if self.create_stats
|
74
|
+
require 'yaml'
|
75
|
+
self.stats.keys.each do |key|
|
76
|
+
File.open("./nice_http_stats_#{key}.yaml", "w") { |file| file.write(self.stats[key].to_yaml) }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
######################################################
|
82
|
+
# to reset to the original defaults
|
83
|
+
######################################################
|
84
|
+
def self.reset!
|
85
|
+
@host = nil
|
86
|
+
@port = 80
|
87
|
+
@ssl = false
|
88
|
+
@headers = {}
|
89
|
+
@values_for = {}
|
90
|
+
@debug = false
|
91
|
+
@log = :fix_file
|
92
|
+
@proxy_host = nil
|
93
|
+
@proxy_port = nil
|
94
|
+
@last_request = nil
|
95
|
+
@last_response = nil
|
96
|
+
@request_id = ""
|
97
|
+
@use_mocks = false
|
98
|
+
@connections = []
|
99
|
+
@active = 0
|
100
|
+
@auto_redirect = true
|
101
|
+
@log_files = {}
|
102
|
+
@create_stats = false
|
103
|
+
@stats = {
|
104
|
+
all: {
|
105
|
+
num_requests: 0,
|
106
|
+
time_elapsed: {
|
107
|
+
total: 0,
|
108
|
+
maximum: 0,
|
109
|
+
minimum: 100000,
|
110
|
+
average: 0,
|
111
|
+
},
|
112
|
+
method: {},
|
113
|
+
},
|
114
|
+
path: {},
|
115
|
+
name: {},
|
116
|
+
}
|
117
|
+
end
|
118
|
+
reset!
|
119
|
+
|
120
|
+
######################################################
|
121
|
+
# If inheriting from NiceHttp class
|
122
|
+
######################################################
|
123
|
+
def self.inherited(subclass)
|
124
|
+
subclass.reset!
|
125
|
+
end
|
126
|
+
|
127
|
+
attr_reader :host, :port, :ssl, :debug, :log, :proxy_host, :proxy_port, :response, :num_redirects
|
128
|
+
attr_accessor :headers, :cookies, :use_mocks, :auto_redirect, :logger, :values_for
|
129
|
+
|
130
|
+
######################################################
|
131
|
+
# Change the default values for NiceHttp supplying a Hash
|
132
|
+
#
|
133
|
+
# @param par [Hash] keys: :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port, :use_mocks, :auto_redirect, :values_for, :create_stats
|
134
|
+
######################################################
|
135
|
+
def self.defaults=(par = {})
|
136
|
+
@host = par[:host] if par.key?(:host)
|
137
|
+
@port = par[:port] if par.key?(:port)
|
138
|
+
@ssl = par[:ssl] if par.key?(:ssl)
|
139
|
+
@headers = par[:headers].dup if par.key?(:headers)
|
140
|
+
@values_for = par[:values_for].dup if par.key?(:values_for)
|
141
|
+
@debug = par[:debug] if par.key?(:debug)
|
142
|
+
@log = par[:log] if par.key?(:log)
|
143
|
+
@proxy_host = par[:proxy_host] if par.key?(:proxy_host)
|
144
|
+
@proxy_port = par[:proxy_port] if par.key?(:proxy_port)
|
145
|
+
@use_mocks = par[:use_mocks] if par.key?(:use_mocks)
|
146
|
+
@auto_redirect = par[:auto_redirect] if par.key?(:auto_redirect)
|
147
|
+
@create_stats = par[:create_stats] if par.key?(:create_stats)
|
148
|
+
end
|
149
|
+
|
150
|
+
######################################################
|
151
|
+
# To add specific stats
|
152
|
+
# The stats will be added to NiceHttp.stats[:specific]
|
153
|
+
#
|
154
|
+
# @param name [Symbol] name to group your specific stats
|
155
|
+
# @param state [Symbol] state of the name supplied to group your specific stats
|
156
|
+
# @param started [Time] when the process you want the stats started
|
157
|
+
# @param finished [Time] when the process you want the stats finished
|
158
|
+
#
|
159
|
+
# @example
|
160
|
+
# started = Time.now
|
161
|
+
# @http.send_request Requests::Customer.add_customer
|
162
|
+
# 30.times do
|
163
|
+
# resp = @http.get(Requests::Customer.get_customer)
|
164
|
+
# break if resp.code == 200
|
165
|
+
# sleep 0.5
|
166
|
+
# end
|
167
|
+
# NiceHttp.add_stats(:customer, :create, started, Time.now)
|
168
|
+
######################################################
|
169
|
+
def self.add_stats(name, state, started, finished)
|
170
|
+
self.stats[:specific] ||= {}
|
171
|
+
self.stats[:specific][name] ||= {num: 0, time_elapsed: {total:0, maximum:0, minimum:1000, average: 0}}
|
172
|
+
self.stats[:specific][name][:num] += 1
|
173
|
+
time_elapsed = self.stats[:specific][name][:time_elapsed]
|
174
|
+
time_elapsed[:total] += finished - started
|
175
|
+
time_elapsed[:maximum] = (finished - started) if time_elapsed[:maximum]<(finished-started)
|
176
|
+
time_elapsed[:minimum] = (finished - started) if time_elapsed[:minimum]>(finished-started)
|
177
|
+
time_elapsed[:average] = time_elapsed[:total]/self.stats[:specific][name][:num]
|
178
|
+
|
179
|
+
self.stats[:specific][name][state] ||= {num: 0, time_elapsed: {total:0, maximum:0, minimum:1000, average: 0}}
|
180
|
+
self.stats[:specific][name][state][:num] += 1
|
181
|
+
time_elapsed = self.stats[:specific][name][state][:time_elapsed]
|
182
|
+
time_elapsed[:total] += finished - started
|
183
|
+
time_elapsed[:maximum] = (finished - started) if time_elapsed[:maximum]<(finished-started)
|
184
|
+
time_elapsed[:minimum] = (finished - started) if time_elapsed[:minimum]>(finished-started)
|
185
|
+
time_elapsed[:average] = time_elapsed[:total]/self.stats[:specific][name][state][:num]
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
######################################################
|
190
|
+
# Creates a new http connection.
|
191
|
+
#
|
192
|
+
# @param args [] If no parameter supplied, by default will access how is setup on defaults
|
193
|
+
# @example
|
194
|
+
# http = NiceHttp.new()
|
195
|
+
# @param args [String]. The url to create the connection.
|
196
|
+
# @example
|
197
|
+
# http = NiceHttp.new("https://www.example.com")
|
198
|
+
# @example
|
199
|
+
# http = NiceHttp.new("example.com:8999")
|
200
|
+
# @example
|
201
|
+
# http = NiceHttp.new("localhost:8322")
|
202
|
+
# @param args [Hash] containing these possible keys:
|
203
|
+
#
|
204
|
+
# host -- example.com. (default blank screen)
|
205
|
+
#
|
206
|
+
# port -- port for the connection. 80 (default)
|
207
|
+
#
|
208
|
+
# ssl -- true, false (default)
|
209
|
+
#
|
210
|
+
# headers -- hash with the headers
|
211
|
+
#
|
212
|
+
# values_for -- hash with the values_for
|
213
|
+
#
|
214
|
+
# debug -- true, false (default)
|
215
|
+
#
|
216
|
+
# log -- :no, :screen, :file, :fix_file (default).
|
217
|
+
#
|
218
|
+
# A string with a path can be supplied.
|
219
|
+
#
|
220
|
+
# If :fix_file: nice_http.log
|
221
|
+
#
|
222
|
+
# In case :file it will be generated a log file with name: nice_http_YY-mm-dd-HHMMSS.log
|
223
|
+
#
|
224
|
+
# proxy_host
|
225
|
+
#
|
226
|
+
# proxy_port
|
227
|
+
# @example
|
228
|
+
# http2 = NiceHttp.new( host: "reqres.in", port: 443, ssl: true )
|
229
|
+
# @example
|
230
|
+
# my_server = {host: "example.com",
|
231
|
+
# port: 80,
|
232
|
+
# headers: {"api-key": "zdDDdjkck"}
|
233
|
+
# }
|
234
|
+
# http3 = NiceHttp.new my_server
|
235
|
+
######################################################
|
236
|
+
def initialize(args = {})
|
237
|
+
require "net/http"
|
238
|
+
require "net/https"
|
239
|
+
@host = self.class.host
|
240
|
+
@port = self.class.port
|
241
|
+
@prepath = ""
|
242
|
+
@ssl = self.class.ssl
|
243
|
+
@headers = self.class.headers.dup
|
244
|
+
@values_for = self.class.values_for.dup
|
245
|
+
@debug = self.class.debug
|
246
|
+
@log = self.class.log
|
247
|
+
@proxy_host = self.class.proxy_host
|
248
|
+
@proxy_port = self.class.proxy_port
|
249
|
+
@use_mocks = self.class.use_mocks
|
250
|
+
@auto_redirect = false #set it up at the end of initialize
|
251
|
+
auto_redirect = self.class.auto_redirect
|
252
|
+
@num_redirects = 0
|
253
|
+
@create_stats = self.class.create_stats
|
254
|
+
|
255
|
+
#todo: set only the cookies for the current domain
|
256
|
+
#key: path, value: hash with key is the name of the cookie and value the value
|
257
|
+
# we set the default value for non existing keys to empty Hash {} so in case of merge there is no problem
|
258
|
+
@cookies = Hash.new { |h, k| h[k] = {} }
|
259
|
+
|
260
|
+
if args.is_a?(String)
|
261
|
+
uri = URI.parse(args)
|
262
|
+
@host = uri.host unless uri.host.nil?
|
263
|
+
@port = uri.port unless uri.port.nil?
|
264
|
+
@ssl = true if !uri.scheme.nil? && (uri.scheme == "https")
|
265
|
+
@prepath = uri.path unless uri.path == "/"
|
266
|
+
elsif args.is_a?(Hash) && !args.keys.empty?
|
267
|
+
@host = args[:host] if args.keys.include?(:host)
|
268
|
+
@port = args[:port] if args.keys.include?(:port)
|
269
|
+
@ssl = args[:ssl] if args.keys.include?(:ssl)
|
270
|
+
@headers = args[:headers].dup if args.keys.include?(:headers)
|
271
|
+
@values_for = args[:values_for].dup if args.keys.include?(:values_for)
|
272
|
+
@debug = args[:debug] if args.keys.include?(:debug)
|
273
|
+
@log = args[:log] if args.keys.include?(:log)
|
274
|
+
@proxy_host = args[:proxy_host] if args.keys.include?(:proxy_host)
|
275
|
+
@proxy_port = args[:proxy_port] if args.keys.include?(:proxy_port)
|
276
|
+
@use_mocks = args[:use_mocks] if args.keys.include?(:use_mocks)
|
277
|
+
auto_redirect = args[:auto_redirect] if args.keys.include?(:auto_redirect)
|
278
|
+
end
|
279
|
+
|
280
|
+
begin
|
281
|
+
log_filename = ""
|
282
|
+
if @log.kind_of?(String) or @log == :fix_file or @log == :file or @log == :file_run
|
283
|
+
if @log.kind_of?(String)
|
284
|
+
log_filename = @log.dup
|
285
|
+
elsif @log == :fix_file
|
286
|
+
log_filename = "nice_http.log"
|
287
|
+
elsif @log == :file
|
288
|
+
log_filename = "nice_http_#{Time.now.strftime("%Y-%m-%d-%H%M%S")}.log"
|
289
|
+
elsif @log == :file_run
|
290
|
+
log_filename = "#{caller.first[/[^:]+/]}.log"
|
291
|
+
end
|
292
|
+
if Thread.current.name.to_s!=''
|
293
|
+
log_filename.gsub!(/\.log$/, "_#{Thread.current.name}.log")
|
294
|
+
end
|
295
|
+
if self.class.log_files.key?(log_filename)
|
296
|
+
@logger = self.class.log_files[log_filename]
|
297
|
+
else
|
298
|
+
f = File.new(log_filename, "w")
|
299
|
+
f.sync = true
|
300
|
+
@logger = Logger.new f
|
301
|
+
self.class.log_files[log_filename] = @logger
|
302
|
+
end
|
303
|
+
elsif @log == :screen
|
304
|
+
@logger = Logger.new STDOUT
|
305
|
+
elsif @log == :no
|
306
|
+
@logger = Logger.new nil
|
307
|
+
else
|
308
|
+
raise InfoMissing, :log
|
309
|
+
end
|
310
|
+
@logger.level = Logger::INFO
|
311
|
+
rescue Exception => stack
|
312
|
+
@logger = Logger.new nil
|
313
|
+
raise InfoMissing, :log
|
314
|
+
end
|
315
|
+
|
316
|
+
if @host.to_s != "" and (@host.start_with?("http:") or @host.start_with?("https:"))
|
317
|
+
uri = URI.parse(@host)
|
318
|
+
@host = uri.host unless uri.host.nil?
|
319
|
+
@port = uri.port unless uri.port.nil?
|
320
|
+
@ssl = true if !uri.scheme.nil? && (uri.scheme == "https")
|
321
|
+
@prepath = uri.path unless uri.path == "/"
|
322
|
+
end
|
323
|
+
|
324
|
+
raise InfoMissing, :port if @port.to_s == ""
|
325
|
+
raise InfoMissing, :host if @host.to_s == ""
|
326
|
+
raise InfoMissing, :ssl unless @ssl.is_a?(TrueClass) or @ssl.is_a?(FalseClass)
|
327
|
+
raise InfoMissing, :debug unless @debug.is_a?(TrueClass) or @debug.is_a?(FalseClass)
|
328
|
+
raise InfoMissing, :auto_redirect unless auto_redirect.is_a?(TrueClass) or auto_redirect.is_a?(FalseClass)
|
329
|
+
raise InfoMissing, :use_mocks unless @use_mocks.is_a?(TrueClass) or @use_mocks.is_a?(FalseClass)
|
330
|
+
raise InfoMissing, :headers unless @headers.is_a?(Hash)
|
331
|
+
raise InfoMissing, :values_for unless @values_for.is_a?(Hash)
|
332
|
+
|
333
|
+
begin
|
334
|
+
if !@proxy_host.nil? && !@proxy_port.nil?
|
335
|
+
@http = Net::HTTP::Proxy(@proxy_host, @proxy_port).new(@host, @port)
|
336
|
+
@http.use_ssl = @ssl
|
337
|
+
@http.set_debug_output $stderr if @debug
|
338
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
339
|
+
@http.start
|
340
|
+
else
|
341
|
+
@http = Net::HTTP.new(@host, @port)
|
342
|
+
@http.use_ssl = @ssl
|
343
|
+
@http.set_debug_output $stderr if @debug
|
344
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
345
|
+
@http.start
|
346
|
+
end
|
347
|
+
|
348
|
+
@message_server = "(#{self.object_id}):"
|
349
|
+
|
350
|
+
log_message = "(#{self.object_id}): Http connection created. host:#{@host}, port:#{@port}, ssl:#{@ssl}, mode:#{@mode}, proxy_host: #{@proxy_host.to_s()}, proxy_port: #{@proxy_port.to_s()} "
|
351
|
+
|
352
|
+
@logger.info(log_message)
|
353
|
+
@message_server += " Http connection: "
|
354
|
+
if @ssl
|
355
|
+
@message_server += "https://"
|
356
|
+
else
|
357
|
+
@message_server += "http://"
|
358
|
+
end
|
359
|
+
@message_server += "#{@host}:#{@port}"
|
360
|
+
if @proxy_host.to_s != ""
|
361
|
+
@message_server += " proxy:#{@proxy_host}:#{@proxy_port}"
|
362
|
+
end
|
363
|
+
@auto_redirect = auto_redirect
|
364
|
+
# for the case we have headers following nice_hash implementation
|
365
|
+
@headers = @headers.generate
|
366
|
+
|
367
|
+
self.class.active += 1
|
368
|
+
self.class.connections.push(self)
|
369
|
+
rescue Exception => stack
|
370
|
+
puts stack
|
371
|
+
@logger.fatal stack
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
######################################################
|
376
|
+
# Close HTTP connection
|
377
|
+
######################################################
|
378
|
+
def close
|
379
|
+
begin
|
380
|
+
pos = 0
|
381
|
+
found = false
|
382
|
+
self.class.connections.each { |conn|
|
383
|
+
if conn.object_id == self.object_id
|
384
|
+
found = true
|
385
|
+
break
|
386
|
+
else
|
387
|
+
pos += 1
|
388
|
+
end
|
389
|
+
}
|
390
|
+
if found
|
391
|
+
self.class.connections.delete_at(pos)
|
392
|
+
end
|
393
|
+
|
394
|
+
unless @closed
|
395
|
+
if !@http.nil?
|
396
|
+
@http.finish()
|
397
|
+
@http = nil
|
398
|
+
@logger.info "the HTTP connection was closed: #{@message_server}"
|
399
|
+
else
|
400
|
+
@http = nil
|
401
|
+
@logger.fatal "It was not possible to close the HTTP connection: #{@message_server}"
|
402
|
+
end
|
403
|
+
@closed = true
|
404
|
+
else
|
405
|
+
@logger.warn "It was not possible to close the HTTP connection, already closed: #{@message_server}"
|
406
|
+
end
|
407
|
+
rescue Exception => stack
|
408
|
+
@logger.fatal stack
|
409
|
+
end
|
410
|
+
self.class.active -= 1
|
411
|
+
end
|
412
|
+
|
413
|
+
private :manage_request, :manage_response
|
414
|
+
end
|