nice_http 1.8.10 → 1.9.0
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 +4 -4
- data/README.md +53 -3
- data/lib/nice_http/add_stats.rb +85 -0
- data/lib/nice_http/close.rb +39 -0
- data/lib/nice_http/defaults.rb +30 -0
- data/lib/nice_http/inherited.rb +8 -0
- data/lib/nice_http/initialize.rb +253 -0
- data/lib/nice_http/manage/create_stats.rb +64 -0
- data/lib/nice_http/{manage_request.rb → manage/request.rb} +16 -9
- data/lib/nice_http/{manage_response.rb → manage/response.rb} +7 -111
- data/lib/nice_http/manage/set_stats.rb +43 -0
- data/lib/nice_http/manage/wait_async_operation.rb +43 -0
- data/lib/nice_http/methods/delete.rb +108 -0
- data/lib/nice_http/methods/get.rb +159 -0
- data/lib/nice_http/methods/head.rb +72 -0
- data/lib/nice_http/methods/patch.rb +103 -0
- data/lib/nice_http/methods/post.rb +122 -0
- data/lib/nice_http/methods/put.rb +87 -0
- data/lib/nice_http/methods/send_request.rb +47 -0
- data/lib/nice_http/reset.rb +54 -0
- data/lib/nice_http/save_stats.rb +37 -0
- data/lib/nice_http/utils/basic_authentication.rb +18 -0
- data/lib/nice_http/{utils.rb → utils/get_value_xml_tag.rb} +0 -45
- data/lib/nice_http/utils/set_value_xml_tag.rb +30 -0
- data/lib/nice_http.rb +33 -475
- metadata +24 -6
- data/lib/nice_http/http_methods.rb +0 -686
@@ -0,0 +1,122 @@
|
|
1
|
+
module NiceHttpHttpMethods
|
2
|
+
|
3
|
+
######################################################
|
4
|
+
# Post data to path
|
5
|
+
# @param arguments [Hash] containing at least keys :data and :path.
|
6
|
+
# In case :data not supplied and :data_examples array supplied, it will be taken the first example as :data.
|
7
|
+
# @param arguments [Array<path, data, additional_headers>]
|
8
|
+
# path (string).
|
9
|
+
# data (json data for example).
|
10
|
+
# additional_headers (Hash key=>value).
|
11
|
+
# @return [Hash] response
|
12
|
+
# Including at least the symbol keys:
|
13
|
+
# :data = the response data body.
|
14
|
+
# :message = plain text response.
|
15
|
+
# :code = code response (200=ok,500=wrong...).
|
16
|
+
# All keys in response are lowercase.
|
17
|
+
# data, message and code can also be accessed as attributes like .message .code .data.
|
18
|
+
# In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
|
19
|
+
# @example
|
20
|
+
# resp = @http.post(Requests::Customer.update_customer)
|
21
|
+
# assert resp.code == 201
|
22
|
+
# @example
|
23
|
+
# resp = http.post( {
|
24
|
+
# path: "/api/users",
|
25
|
+
# data: {name: "morpheus", job: "leader"}
|
26
|
+
# } )
|
27
|
+
# pp resp.data.json
|
28
|
+
######################################################
|
29
|
+
def post(*arguments)
|
30
|
+
begin
|
31
|
+
path, data, headers_t = manage_request(*arguments)
|
32
|
+
@start_time = Time.now if @start_time.nil?
|
33
|
+
if arguments.size > 0 and arguments[0].kind_of?(Hash)
|
34
|
+
arg = arguments[0]
|
35
|
+
if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response)
|
36
|
+
data = ""
|
37
|
+
if arg[:mock_response].keys.include?(:data)
|
38
|
+
data = arg[:mock_response][:data]
|
39
|
+
if data.kind_of?(Hash) #to json
|
40
|
+
begin
|
41
|
+
require "json"
|
42
|
+
data = data.to_json
|
43
|
+
rescue
|
44
|
+
@logger.fatal "There was a problem converting to json: #{data}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
@logger.warn "Pay attention!!! This is a mock response:"
|
49
|
+
@start_time_net = Time.now if @start_time_net.nil?
|
50
|
+
manage_response(arg[:mock_response], data.to_s)
|
51
|
+
return @response
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
begin
|
56
|
+
@start_time_net = Time.now if @start_time_net.nil?
|
57
|
+
if headers_t["Content-Type"] == "multipart/form-data"
|
58
|
+
require "net/http/post/multipart"
|
59
|
+
headers_t.each { |key, value|
|
60
|
+
arguments[0][:data].add_field(key, value) #add to Headers
|
61
|
+
}
|
62
|
+
resp = @http.request(arguments[0][:data])
|
63
|
+
elsif headers_t["Content-Type"].to_s.include?("application/x-www-form-urlencoded")
|
64
|
+
encoded_form = URI.encode_www_form(arguments[0][:data])
|
65
|
+
resp = @http.request_post(path, encoded_form, headers_t)
|
66
|
+
data = resp.body
|
67
|
+
else
|
68
|
+
resp = @http.post(path, data, headers_t)
|
69
|
+
#todo: do it also for forms and multipart
|
70
|
+
if (resp.code == 401 or resp.code == 408) and @headers_orig.values.map(&:class).include?(Proc)
|
71
|
+
try = false
|
72
|
+
@headers_orig.each do |k, v|
|
73
|
+
if v.is_a?(Proc) and headers_t.key?(k)
|
74
|
+
try = true
|
75
|
+
headers_t[k] = v.call
|
76
|
+
end
|
77
|
+
end
|
78
|
+
if try
|
79
|
+
@logger.warn "Not authorized. Trying to generate a new token."
|
80
|
+
resp = @http.post(path, data, headers_t)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
data = resp.body
|
84
|
+
end
|
85
|
+
rescue Exception => stack
|
86
|
+
@logger.warn stack
|
87
|
+
if !@timeout.nil? and (Time.now - @start_time_net) > @timeout
|
88
|
+
@logger.warn "The connection seems to be closed in the host machine. Timeout."
|
89
|
+
return { fatal_error: "Net::ReadTimeout", code: nil, message: nil, data: "" }
|
90
|
+
else
|
91
|
+
@logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
|
92
|
+
@http.finish()
|
93
|
+
@http.start()
|
94
|
+
@start_time_net = Time.now if @start_time_net.nil?
|
95
|
+
@headers_orig.each { |k, v| headers_t[k] = v.call if v.is_a?(Proc) and headers_t.key?(k) }
|
96
|
+
resp, data = @http.post(path, data, headers_t)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
manage_response(resp, data)
|
100
|
+
if @auto_redirect and @response[:code].to_i >= 300 and @response[:code].to_i < 400 and @response.include?(:location)
|
101
|
+
if @num_redirects <= 30
|
102
|
+
@num_redirects += 1
|
103
|
+
current_server = "http"
|
104
|
+
current_server += "s" if @ssl == true
|
105
|
+
current_server += "://#{@host}"
|
106
|
+
location = @response[:location].gsub(current_server, "")
|
107
|
+
@logger.info "(#{@num_redirects}) Redirecting NiceHttp to #{location}"
|
108
|
+
get(location)
|
109
|
+
else
|
110
|
+
@logger.fatal "(#{@num_redirects}) Maximum number of redirections for a single request reached. Be sure everything is correct, it seems there is a non ending loop"
|
111
|
+
@num_redirects = 0
|
112
|
+
end
|
113
|
+
else
|
114
|
+
@num_redirects = 0
|
115
|
+
end
|
116
|
+
return @response
|
117
|
+
rescue Exception => stack
|
118
|
+
@logger.fatal stack
|
119
|
+
return { fatal_error: stack.to_s, code: nil, message: nil, data: "" }
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module NiceHttpHttpMethods
|
2
|
+
|
3
|
+
######################################################
|
4
|
+
# Put data to path
|
5
|
+
# @param arguments [Hash] containing at least keys :data and :path.
|
6
|
+
# In case :data not supplied and :data_examples array supplied, it will be taken the first example as :data.
|
7
|
+
# @param arguments [Array<path, data, additional_headers>]
|
8
|
+
# path (string).
|
9
|
+
# data (json data for example).
|
10
|
+
# additional_headers (Hash key=>value).
|
11
|
+
# @return [Hash] response
|
12
|
+
# Including at least the symbol keys:
|
13
|
+
# :data = the response data body.
|
14
|
+
# :message = plain text response.
|
15
|
+
# :code = code response (200=ok,500=wrong...).
|
16
|
+
# All keys in response are lowercase.
|
17
|
+
# data, message and code can also be accessed as attributes like .message .code .data.
|
18
|
+
# In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
|
19
|
+
# @example
|
20
|
+
# resp = @http.put(Requests::Customer.remove_phone)
|
21
|
+
######################################################
|
22
|
+
def put(*arguments)
|
23
|
+
begin
|
24
|
+
path, data, headers_t = manage_request(*arguments)
|
25
|
+
@start_time = Time.now if @start_time.nil?
|
26
|
+
if arguments.size > 0 and arguments[0].kind_of?(Hash)
|
27
|
+
arg = arguments[0]
|
28
|
+
if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response)
|
29
|
+
data = ""
|
30
|
+
if arg[:mock_response].keys.include?(:data)
|
31
|
+
data = arg[:mock_response][:data]
|
32
|
+
if data.kind_of?(Hash) #to json
|
33
|
+
begin
|
34
|
+
require "json"
|
35
|
+
data = data.to_json
|
36
|
+
rescue
|
37
|
+
@logger.fatal "There was a problem converting to json: #{data}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
@logger.warn "Pay attention!!! This is a mock response:"
|
42
|
+
@start_time_net = Time.now if @start_time_net.nil?
|
43
|
+
manage_response(arg[:mock_response], data.to_s)
|
44
|
+
return @response
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
begin
|
49
|
+
@start_time_net = Time.now if @start_time_net.nil?
|
50
|
+
resp = @http.send_request("PUT", path, data, headers_t)
|
51
|
+
if (resp.code == 401 or resp.code == 408) and @headers_orig.values.map(&:class).include?(Proc)
|
52
|
+
try = false
|
53
|
+
@headers_orig.each do |k, v|
|
54
|
+
if v.is_a?(Proc) and headers_t.key?(k)
|
55
|
+
try = true
|
56
|
+
headers_t[k] = v.call
|
57
|
+
end
|
58
|
+
end
|
59
|
+
if try
|
60
|
+
@logger.warn "Not authorized. Trying to generate a new token."
|
61
|
+
resp = @http.send_request("PUT", path, data, headers_t)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
data = resp.body
|
65
|
+
rescue Exception => stack
|
66
|
+
@logger.warn stack
|
67
|
+
if !@timeout.nil? and (Time.now - @start_time_net) > @timeout
|
68
|
+
@logger.warn "The connection seems to be closed in the host machine. Timeout."
|
69
|
+
return { fatal_error: "Net::ReadTimeout", code: nil, message: nil, data: "" }
|
70
|
+
else
|
71
|
+
@logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
|
72
|
+
@http.finish()
|
73
|
+
@http.start()
|
74
|
+
@headers_orig.each { |k, v| headers_t[k] = v.call if v.is_a?(Proc) and headers_t.key?(k) }
|
75
|
+
@start_time_net = Time.now if @start_time_net.nil?
|
76
|
+
resp, data = @http.send_request("PUT", path, data, headers_t)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
manage_response(resp, data)
|
80
|
+
|
81
|
+
return @response
|
82
|
+
rescue Exception => stack
|
83
|
+
@logger.fatal stack
|
84
|
+
return { fatal_error: stack.to_s, code: nil, message: nil, data: "" }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module NiceHttpHttpMethods
|
2
|
+
|
3
|
+
######################################################
|
4
|
+
# It will send the request depending on the :method declared on the request hash
|
5
|
+
# Take a look at https://github.com/MarioRuiz/Request-Hash
|
6
|
+
#
|
7
|
+
# @param request_hash [Hash] containing at least key :path and :method. The methods that are accepted are: :get, :head, :post, :put, :delete, :patch
|
8
|
+
#
|
9
|
+
# @return [Hash] response
|
10
|
+
# Including at least the symbol keys:
|
11
|
+
# :data = the response data body.
|
12
|
+
# :message = plain text response.
|
13
|
+
# :code = code response (200=ok,500=wrong...).
|
14
|
+
# All keys in response are lowercase.
|
15
|
+
# data, message and code can also be accessed as attributes like .message .code .data.
|
16
|
+
# In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
|
17
|
+
# @example
|
18
|
+
# resp = @http.send_request Requests::Customer.remove_session
|
19
|
+
# assert resp.code == 204
|
20
|
+
######################################################
|
21
|
+
def send_request(request_hash)
|
22
|
+
unless request_hash.is_a?(Hash) and request_hash.key?(:method) and request_hash.key?(:path) and
|
23
|
+
request_hash[:method].is_a?(Symbol) and
|
24
|
+
[:get, :head, :post, :put, :delete, :patch].include?(request_hash[:method])
|
25
|
+
message = "send_request: it needs to be supplied a Request Hash that includes a :method and :path. "
|
26
|
+
message += "Supported methods: :get, :head, :post, :put, :delete, :patch"
|
27
|
+
@logger.fatal message
|
28
|
+
return { fatal_error: message, code: nil, message: nil }
|
29
|
+
else
|
30
|
+
case request_hash[:method]
|
31
|
+
when :get
|
32
|
+
resp = get request_hash
|
33
|
+
when :post
|
34
|
+
resp = post request_hash
|
35
|
+
when :head
|
36
|
+
resp = head request_hash
|
37
|
+
when :put
|
38
|
+
resp = put request_hash
|
39
|
+
when :delete
|
40
|
+
resp = delete request_hash
|
41
|
+
when :patch
|
42
|
+
resp = patch request_hash
|
43
|
+
end
|
44
|
+
return resp
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
class NiceHttp
|
2
|
+
######################################################
|
3
|
+
# to reset to the original defaults
|
4
|
+
######################################################
|
5
|
+
def self.reset!
|
6
|
+
@host = nil
|
7
|
+
@port = 80
|
8
|
+
@ssl = false
|
9
|
+
@timeout = nil
|
10
|
+
@headers = {}
|
11
|
+
@values_for = {}
|
12
|
+
@debug = false
|
13
|
+
@log = :fix_file
|
14
|
+
@log_path = ""
|
15
|
+
@log_headers = :all
|
16
|
+
@proxy_host = nil
|
17
|
+
@proxy_port = nil
|
18
|
+
@last_request = nil
|
19
|
+
@request = nil
|
20
|
+
@requests = nil
|
21
|
+
@last_response = nil
|
22
|
+
@request_id = ""
|
23
|
+
@use_mocks = false
|
24
|
+
@connections = []
|
25
|
+
@active = 0
|
26
|
+
@auto_redirect = true
|
27
|
+
@log_files = {}
|
28
|
+
@create_stats = false
|
29
|
+
@stats = {
|
30
|
+
all: {
|
31
|
+
num_requests: 0,
|
32
|
+
started: nil,
|
33
|
+
finished: nil,
|
34
|
+
real_time_elapsed: 0,
|
35
|
+
time_elapsed: {
|
36
|
+
total: 0,
|
37
|
+
maximum: 0,
|
38
|
+
minimum: 1000000,
|
39
|
+
average: 0,
|
40
|
+
},
|
41
|
+
method: {},
|
42
|
+
},
|
43
|
+
path: {},
|
44
|
+
name: {},
|
45
|
+
}
|
46
|
+
@capture = false
|
47
|
+
@captured = []
|
48
|
+
@async_wait_seconds = 0
|
49
|
+
@async_header = "location"
|
50
|
+
@async_completed = ""
|
51
|
+
@async_resource = ""
|
52
|
+
@async_status = ""
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class NiceHttp
|
2
|
+
######################################################
|
3
|
+
# It will save the NiceHttp.stats on different files, each key of the hash in a different file.
|
4
|
+
#
|
5
|
+
# @param file_name [String] path and file name to be used to store the stats.
|
6
|
+
# In case no one supplied it will be used the value in NiceHttp.log and it will be saved on YAML format.
|
7
|
+
# In case extension is .yaml will be saved on YAML format.
|
8
|
+
# In case extension is .json will be saved on JSON format.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# NiceHttp.save_stats
|
12
|
+
# NiceHttp.save_stats('./stats/my_stats.yaml')
|
13
|
+
# NiceHttp.save_stats('./stats/my_stats.json')
|
14
|
+
######################################################
|
15
|
+
def self.save_stats(file_name = "")
|
16
|
+
if file_name == ""
|
17
|
+
if self.log.is_a?(String)
|
18
|
+
file_name = self.log
|
19
|
+
else
|
20
|
+
file_name = "./#{self.log_path}nice_http.log"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
require "fileutils"
|
24
|
+
FileUtils.mkdir_p File.dirname(file_name)
|
25
|
+
if file_name.match?(/\.json$/)
|
26
|
+
require "json"
|
27
|
+
self.stats.keys.each do |key|
|
28
|
+
File.open("#{file_name.gsub(/.json$/, "_stats_")}#{key}.json", "w") { |file| file.write(self.stats[key].to_json) }
|
29
|
+
end
|
30
|
+
else
|
31
|
+
require "yaml"
|
32
|
+
self.stats.keys.each do |key|
|
33
|
+
File.open("#{file_name.gsub(/.\w+$/, "_stats_")}#{key}.yaml", "w") { |file| file.write(self.stats[key].to_yaml) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module NiceHttpUtils
|
2
|
+
##################################################
|
3
|
+
# returns the seed for Basic authentication
|
4
|
+
# @param user [String]
|
5
|
+
# @param password [String]
|
6
|
+
# @param strict [Boolean] (default: false) use strict_encode64 if true, if not encode64
|
7
|
+
# @return [String] seed string to be used on Authorization key header on a get request
|
8
|
+
####################################################
|
9
|
+
def self.basic_authentication(user:, password:, strict: false)
|
10
|
+
require "base64"
|
11
|
+
if strict
|
12
|
+
seed = "Basic " + Base64.strict_encode64(user + ":" + password)
|
13
|
+
else
|
14
|
+
seed = "Basic " + Base64.encode64(user + ":" + password)
|
15
|
+
end
|
16
|
+
return seed
|
17
|
+
end
|
18
|
+
end
|
@@ -60,49 +60,4 @@ module NiceHttpUtils
|
|
60
60
|
return ret
|
61
61
|
end
|
62
62
|
end
|
63
|
-
|
64
|
-
##################################################
|
65
|
-
# set a value on xml tag
|
66
|
-
# @param tag_name [String]
|
67
|
-
# @param xml_string [String]
|
68
|
-
# @param value [String]
|
69
|
-
# @param take_off_prefix [Boolean] (optional). true, false(default)
|
70
|
-
# @return [String] with the new value
|
71
|
-
####################################################
|
72
|
-
def self.set_value_xml_tag(tag_name, xml_string, value, take_off_prefix = false)
|
73
|
-
tag_name = tag_name.to_s
|
74
|
-
if take_off_prefix
|
75
|
-
i = tag_name.index(":")
|
76
|
-
tag_name = tag_name[i + 1..tag_name.length] unless i.nil?
|
77
|
-
end
|
78
|
-
if xml_string.to_s != ""
|
79
|
-
if take_off_prefix
|
80
|
-
old_value = NiceHttpUtils.get_value_xml_tag(tag_name, xml_string.dup, true)
|
81
|
-
xml_string.gsub!(/:#{tag_name}>#{Regexp.escape(old_value)}<\//i, ":" + tag_name + ">" + value + "</")
|
82
|
-
xml_string.gsub!(/<#{tag_name}>#{Regexp.escape(old_value)}<\//i, "<" + tag_name + ">" + value + "</")
|
83
|
-
else
|
84
|
-
xml_string.gsub!(/<#{tag_name}>.*<\/#{tag_name}>/i, "<" + tag_name + ">" + value + "</" + tag_name + ">")
|
85
|
-
end
|
86
|
-
return xml_string
|
87
|
-
else
|
88
|
-
return ""
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
##################################################
|
93
|
-
# returns the seed for Basic authentication
|
94
|
-
# @param user [String]
|
95
|
-
# @param password [String]
|
96
|
-
# @param strict [Boolean] (default: false) use strict_encode64 if true, if not encode64
|
97
|
-
# @return [String] seed string to be used on Authorization key header on a get request
|
98
|
-
####################################################
|
99
|
-
def self.basic_authentication(user:, password:, strict: false)
|
100
|
-
require "base64"
|
101
|
-
if strict
|
102
|
-
seed = "Basic " + Base64.strict_encode64(user + ":" + password)
|
103
|
-
else
|
104
|
-
seed = "Basic " + Base64.encode64(user + ":" + password)
|
105
|
-
end
|
106
|
-
return seed
|
107
|
-
end
|
108
63
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module NiceHttpUtils
|
2
|
+
|
3
|
+
##################################################
|
4
|
+
# set a value on xml tag
|
5
|
+
# @param tag_name [String]
|
6
|
+
# @param xml_string [String]
|
7
|
+
# @param value [String]
|
8
|
+
# @param take_off_prefix [Boolean] (optional). true, false(default)
|
9
|
+
# @return [String] with the new value
|
10
|
+
####################################################
|
11
|
+
def self.set_value_xml_tag(tag_name, xml_string, value, take_off_prefix = false)
|
12
|
+
tag_name = tag_name.to_s
|
13
|
+
if take_off_prefix
|
14
|
+
i = tag_name.index(":")
|
15
|
+
tag_name = tag_name[i + 1..tag_name.length] unless i.nil?
|
16
|
+
end
|
17
|
+
if xml_string.to_s != ""
|
18
|
+
if take_off_prefix
|
19
|
+
old_value = NiceHttpUtils.get_value_xml_tag(tag_name, xml_string.dup, true)
|
20
|
+
xml_string.gsub!(/:#{tag_name}>#{Regexp.escape(old_value)}<\//i, ":" + tag_name + ">" + value + "</")
|
21
|
+
xml_string.gsub!(/<#{tag_name}>#{Regexp.escape(old_value)}<\//i, "<" + tag_name + ">" + value + "</")
|
22
|
+
else
|
23
|
+
xml_string.gsub!(/<#{tag_name}>.*<\/#{tag_name}>/i, "<" + tag_name + ">" + value + "</" + tag_name + ">")
|
24
|
+
end
|
25
|
+
return xml_string
|
26
|
+
else
|
27
|
+
return ""
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|