nice_http 1.1.1 → 1.2.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nice_http.rb +1195 -1176
  3. data/lib/nice_http/utils.rb +63 -66
  4. metadata +21 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 609d0cfed9e68d29af972ceb77095bfae7591899aa2715ce59987ea22298e98d
4
- data.tar.gz: 4bcaecdde1849f12198487e0a619759b5c56c907dda577fc6518d2efed21c8d0
3
+ metadata.gz: e13c6fcc544ad6f967b3d4a4d9f0efd945b798e7acf2caa5edefcc764902c1e0
4
+ data.tar.gz: b0b66d1cf1951a94b3d032774990f29d40dd6036ff54f313b8155c1d862d5299
5
5
  SHA512:
6
- metadata.gz: a29e0ae4d2d40f650a43abfc4be521bb7933c923b3f6852e373582de52629999d2bce1102978b831288fd586e7ad773d114b3f877e7c2adf8d7d590510afdbb0
7
- data.tar.gz: 279c1f0bd6bf5f760038f7bbf3bdfd242ccbdf133af3239eaf6f6466f824de8f0d9352ce0fbbe0075354c5ce8f0948cefca86136bff072da0baed617aeb5072c
6
+ metadata.gz: af513dc9bafc301fed7f282f4472c6c8f1449a01c0bd82de7d7fece8baa26df169767ee08697907a41d927a89b17f49fad4a3ab85ff99c02148fef676b780faa
7
+ data.tar.gz: 35a853fc116ba4c56d21ce006108db0b950789d6917f7bba1a70289821cbab1456658ede6eb7ca2f00843b5c7ef59b95b91f3817a8f81257f90a5cd9dfbaf444
@@ -1,1176 +1,1195 @@
1
- require 'logger'
2
- require 'nice_hash'
3
- require_relative 'nice_http/utils'
4
-
5
- ######################################################
6
- # Attributes you can access using NiceHttp.the_attribute:
7
- # :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port,
8
- # :last_request, :last_response, :request_id, :use_mocks, :connections,
9
- # :active, :auto_redirect
10
- #
11
- # @attr [String] host The host to be accessed
12
- # @attr [Integer] port The port number
13
- # @attr [Boolean] ssl If you use ssl or not
14
- # @attr [Hash] headers Contains the headers you will be using on your connection
15
- # @attr [Boolean] debug In case true shows all the details of the communication with the host
16
- # @attr [String, Symbol] log :fix_file, :no, :screen, :file, "path and file name".
17
- # :fix_file will log the communication on nice_http.log. (default).
18
- # :no will not generate any logs.
19
- # :screen will print the logs on the screen.
20
- # :file will be generated a log file with name: nice_http_YY-mm-dd-HHMMSS.log.
21
- # String the path and file name where the logs will be stored.
22
- # @attr [String] proxy_host the proxy host to be used
23
- # @attr [Integer] proxy_port the proxy port to be used
24
- # @attr [String] last_request The last request with all the content sent
25
- # @attr [String] last_response Only in case :debug is true, the last response with all the content
26
- # @attr [String] request_id If the response includes a requestId, will be stored here
27
- # @attr [Boolean] use_mocks If true, in case the request hash includes a :mock_response key, it will be used as the response instead
28
- # @attr [Array] connections It will include all the active connections (NiceHttp instances)
29
- # @attr [Integer] active Number of active connections
30
- # @attr [Boolean] auto_redirect If true, NiceHttp will take care of the auto redirections when required by the responses
31
- # @attr [Hash] response Contains the full response hash
32
- # @attr [Integer] num_redirects Number of consecutive redirections managed
33
- # @attr [Hash] headers The updated headers of the communication
34
- # @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:
35
- # { '/' => { "cfid" => "d95adfas2550255", "amddom.settings" => "doom" } }
36
- # @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:
37
- # my_http.logger.info "add this to the log file"
38
- # @see https://ruby-doc.org/stdlib-2.5.0/libdoc/logger/rdoc/Logger.html
39
- ######################################################
40
- class NiceHttp
41
-
42
- class << self
43
- attr_accessor :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port,
44
- :last_request, :last_response, :request_id, :use_mocks, :connections,
45
- :active, :auto_redirect
46
- end
47
- @host = nil
48
- @port = 80
49
- @ssl = false
50
- @headers = {}
51
- @debug = false
52
- @log = :fix_file
53
- @proxy_host = nil
54
- @proxy_port = nil
55
- @last_request=nil
56
- @last_response=nil
57
- @request_id=""
58
- @use_mocks = false
59
- @connections = []
60
- @active=0
61
- @auto_redirect = true
62
-
63
- attr_reader :host, :port, :ssl, :debug, :log, :proxy_host, :proxy_port, :response, :num_redirects
64
- attr_accessor :headers, :cookies, :use_mocks, :auto_redirect, :logger
65
-
66
- ######################################################
67
- # Change the default values for NiceHttp supplying a Hash
68
- #
69
- # @param par [Hash] keys: :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port, :use_mocks, :auto_redirect
70
- ######################################################
71
- def self.defaults=(par = {})
72
- @host = par[:host] if par.key?(:host)
73
- @port = par[:port] if par.key?(:port)
74
- @ssl = par[:ssl] if par.key?(:ssl)
75
- @headers = par[:headers] if par.key?(:headers)
76
- @debug = par[:debug] if par.key?(:debug)
77
- @log = par[:log] if par.key?(:log)
78
- @proxy_host = par[:proxy_host] if par.key?(:proxy_host)
79
- @proxy_port = par[:proxy_port] if par.key?(:proxy_port)
80
- @use_mocks = par[:use_mocks] if par.key?(:use_mocks)
81
- @auto_redirect = par[:auto_redirect] if par.key?(:auto_redirect)
82
- end
83
-
84
- ######################################################
85
- # Creates a new http connection.
86
- #
87
- # @param args [] If no parameter supplied, by default will access how is setup on defaults
88
- # @example
89
- # http = NiceHttp.new()
90
- # @param args [String]. The url to create the connection.
91
- # @example
92
- # http = NiceHttp.new("https://www.example.com")
93
- # @example
94
- # http = NiceHttp.new("example.com:8999")
95
- # @example
96
- # http = NiceHttp.new("localhost:8322")
97
- # @param args [Hash] containing these possible keys:
98
- #
99
- # host -- example.com. (default blank screen)
100
- #
101
- # port -- port for the connection. 80 (default)
102
- #
103
- # ssl -- true, false (default)
104
- #
105
- # headers -- hash with the headers
106
- #
107
- # debug -- true, false (default)
108
- #
109
- # log -- :no, :screen, :file, :fix_file (default).
110
- #
111
- # A string with a path can be supplied.
112
- #
113
- # If :fix_file: nice_http.log
114
- #
115
- # In case :file it will be generated a log file with name: nice_http_YY-mm-dd-HHMMSS.log
116
- #
117
- # proxy_host
118
- #
119
- # proxy_port
120
- # @example
121
- # http2 = NiceHttp.new( host: "reqres.in", port: 443, ssl: true )
122
- # @example
123
- # my_server = {host: "example.com",
124
- # port: 80,
125
- # headers: {"api-key": "zdDDdjkck"}
126
- # }
127
- # http3 = NiceHttp.new my_server
128
- ######################################################
129
- def initialize(args = {})
130
- require 'net/http'
131
- require 'net/https'
132
- @host = NiceHttp.host
133
- @port = NiceHttp.port
134
- @ssl = NiceHttp.ssl
135
- @headers = NiceHttp.headers
136
- @debug = NiceHttp.debug
137
- @log = NiceHttp.log
138
- @proxy_host = NiceHttp.proxy_host
139
- @proxy_port = NiceHttp.proxy_port
140
- @use_mocks = NiceHttp.use_mocks
141
- @auto_redirect=false #set it up at the end of initialize
142
- auto_redirect = NiceHttp.auto_redirect
143
- @num_redirects=0
144
-
145
- #todo: set only the cookies for the current domain
146
- #key: path, value: hash with key is the name of the cookie and value the value
147
- # we set the default value for non existing keys to empty Hash {} so in case of merge there is no problem
148
- @cookies=Hash.new {|h, k| h[k] = {}}
149
-
150
- begin
151
- if args.is_a?(String)
152
- uri = URI.parse(args)
153
- @host = uri.host unless uri.host.nil?
154
- @port = uri.port unless uri.port.nil?
155
- @ssl = true if !uri.scheme.nil? && (uri.scheme == 'https')
156
- elsif args.is_a?(Hash) && !args.keys.empty?
157
- @host = args[:host] if args.keys.include?(:host)
158
- @port = args[:port] if args.keys.include?(:port)
159
- @ssl = args[:ssl] if args.keys.include?(:ssl)
160
- @headers = args[:headers] if args.keys.include?(:headers)
161
- @debug = args[:debug] if args.keys.include?(:debug)
162
- @log = args[:log] if args.keys.include?(:log)
163
- @proxy_host = args[:proxy_host] if args.keys.include?(:proxy_host)
164
- @proxy_port = args[:proxy_port] if args.keys.include?(:proxy_port)
165
- @use_mocks = args[:use_mocks] if args.keys.include?(:use_mocks)
166
- @auto_redirect = args[:auto_redirect] if args.keys.include?(:auto_redirect)
167
- end
168
-
169
- if @host.to_s!="" and (@host.include?("http:") or @host.include?("https:"))
170
- uri = URI.parse(@host)
171
- @host = uri.host unless uri.host.nil?
172
- @port = uri.port unless uri.port.nil?
173
- @ssl = true if !uri.scheme.nil? && (uri.scheme == 'https')
174
- end
175
-
176
- if @host.nil? or @host.to_s=="" or @port.nil? or @port.to_s==""
177
- message = "It was not possible to create the http connection!!!\n"
178
- message += "Wrong host or port, remember to supply http:// or https:// in case you specify an url to create the http connection, for example:\n"
179
- message += "http = NiceHttp.new('http://example.com')"
180
- raise message
181
- end
182
-
183
- if !@proxy_host.nil? && !@proxy_port.nil?
184
- @http = Net::HTTP::Proxy(@proxy_host, @proxy_port).new(@host, @port)
185
- @http.use_ssl = @ssl
186
- @http.set_debug_output $stderr if @debug
187
- @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
188
- @http.start
189
- else
190
- @http = Net::HTTP.new(@host, @port)
191
- @http.use_ssl = @ssl
192
- @http.set_debug_output $stderr if @debug
193
- @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
194
- @http.start
195
- end
196
-
197
- if @log.kind_of?(String)
198
- @logger = Logger.new File.new(@log, "w")
199
- elsif @log==:fix_file
200
- @logger = Logger.new File.new("nice_http.log", "w")
201
- elsif @log==:file
202
- @logger = Logger.new File.new("nice_http_#{Time.now.strftime('%Y-%m-%d-%H%M%S')}.log", 'w')
203
- elsif @log==:screen
204
- @logger = Logger.new STDOUT
205
- elsif @log==:no
206
- @logger = Logger.new nil
207
- end
208
- @logger.level = Logger::INFO
209
-
210
- @message_server="(#{self.object_id}):"
211
-
212
- 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()} "
213
-
214
- @logger.info(log_message)
215
- @message_server+=" Http connection: "
216
- if @ssl then
217
- @message_server+="https://"
218
- else
219
- @message_server+="http://"
220
- end
221
- @message_server+="#{@host}:#{@port}"
222
- if @proxy_host.to_s!="" then
223
- @message_server+=" proxy:#{@proxy_host}:#{@proxy_port}"
224
- end
225
- @auto_redirect = auto_redirect
226
- rescue Exception => stack
227
- if @logger.nil?
228
- puts stack
229
- @logger = Logger.new nil
230
- else
231
- @logger.fatal stack
232
- end
233
- end
234
-
235
- NiceHttp.active+=1
236
- NiceHttp.connections.push(self)
237
-
238
- end
239
-
240
- ######################################################
241
- # Get data from path
242
- #
243
- # @param arg [Hash] containing at least key :path
244
- # @param arg [String] the path
245
- #
246
- # @return [Hash] response
247
- # Including at least the symbol keys:
248
- # :data = the response data body.
249
- # :message = plain text response.
250
- # :code = code response (200=ok,500=wrong...).
251
- # All keys in response are lowercase.
252
- # data, message and code can also be accessed as attributes like .message .code .data.
253
- # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
254
- #
255
- # @example
256
- # resp = @http.get(Requests::Customer.get_profile)
257
- # assert resp.code == 200
258
- # @example
259
- # resp = @http.get("/customers/1223")
260
- # assert resp.message == "OK"
261
- ######################################################
262
- def get(arg)
263
- begin
264
- path, data, headers_t=manage_request(arg)
265
- @start_time = Time.now if @start_time.nil?
266
- if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response) then
267
- data=""
268
- if arg[:mock_response].keys.include?(:data) then
269
- data=arg[:mock_response][:data]
270
- if data.kind_of?(Hash) #to json
271
- begin
272
- require 'json'
273
- data=data.to_json
274
- rescue
275
- @logger.fatal "There was a problem converting to json: #{data}"
276
- end
277
- end
278
- end
279
- @logger.warn "Pay attention!!! This is a mock response:"
280
- @start_time_net = Time.now if @start_time_net.nil?
281
- manage_response(arg[:mock_response], data.to_s)
282
- return @response
283
- end
284
- begin
285
- if path.start_with?("http:") or path.start_with?("https:") then #server included on path problably because of a redirection to a different server
286
- require 'uri'
287
- uri = URI.parse(path)
288
- ssl=false
289
- ssl=true if path.include?("https:")
290
-
291
-
292
- server="http://"
293
- server="https://" if path.include?("https:")
294
- if uri.port!=443 then
295
- server+="#{uri.host}:#{uri.port}"
296
- else
297
- server+="#{uri.host}"
298
- end
299
-
300
- http_redir=nil
301
- NiceHttp.connections.each {|conn|
302
- if conn.host == uri.host and conn.port==uri.port then
303
- http_redir=conn
304
- break
305
- end
306
- }
307
-
308
- if !http_redir.nil?
309
- path, data, headers_t=manage_request(arg)
310
- http_redir.cookies.merge!(@cookies)
311
- http_redir.headers.merge!(headers_t)
312
- resp=http_redir.get(path.gsub(server, "")) #todo: remove only the server at the begining in case in query is the server it will be replaced when it should not be
313
- @response=http_redir.response
314
- else
315
- @logger.warn "It seems like the http connection cannot redirect to #{server} because there is no active connection for that server. You need to create previously one."
316
- end
317
-
318
- else
319
- @start_time_net = Time.now if @start_time_net.nil?
320
- resp=@http.get(path, headers_t)
321
- data=resp.body
322
- manage_response(resp, data)
323
- end
324
- rescue Exception => stack
325
- @logger.warn stack
326
- @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
327
- @http.finish()
328
- @http.start()
329
- @start_time_net = Time.now if @start_time_net.nil?
330
- resp=@http.get(path)
331
- data=resp.body
332
- manage_response(resp, data)
333
- end
334
- if @auto_redirect and @response[:code].to_i>=300 and @response[:code].to_i<400 and @response.include?(:location) then
335
- if @num_redirects<=30 then
336
- @num_redirects+=1
337
- current_server="http"
338
- current_server+="s" if @ssl==true
339
- current_server+="://#{@host}"
340
- location=@response[:location].gsub(current_server, "")
341
- @logger.info "(#{@num_redirects}) Redirecting NiceHttp to #{location}"
342
- get(location)
343
- else
344
- @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"
345
- @num_redirects=0
346
- end
347
- else
348
- @num_redirects=0
349
- end
350
- return @response
351
- rescue Exception => stack
352
- @logger.fatal stack
353
- return {fatal_error: stack.to_s, code: nil, message: nil, data: ''}
354
- end
355
- end
356
-
357
- ######################################################
358
- # Post data to path
359
- # @param arguments [Hash] containing at least keys :data and :path.
360
- # In case :data not supplied and :data_examples array supplied, it will be taken the first example as :data.
361
- # @param arguments [Array<path, data, additional_headers>]
362
- # path (string).
363
- # data (json data for example).
364
- # additional_headers (Hash key=>value).
365
- # @return [Hash] response
366
- # Including at least the symbol keys:
367
- # :data = the response data body.
368
- # :message = plain text response.
369
- # :code = code response (200=ok,500=wrong...).
370
- # All keys in response are lowercase.
371
- # data, message and code can also be accessed as attributes like .message .code .data.
372
- # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
373
- # @example
374
- # resp = @http.post(Requests::Customer.update_customer)
375
- # assert resp.code == 201
376
- # @example
377
- # resp = http.post( {
378
- # path: "/api/users",
379
- # data: {name: "morpheus", job: "leader"}
380
- # } )
381
- # pp resp.data.json
382
- ######################################################
383
- def post(*arguments)
384
- begin
385
- path, data, headers_t=manage_request(*arguments)
386
- @start_time = Time.now if @start_time.nil?
387
- if arguments.size>0 and arguments[0].kind_of?(Hash) then
388
- arg=arguments[0]
389
- if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response) then
390
- data=""
391
- if arg[:mock_response].keys.include?(:data) then
392
- data=arg[:mock_response][:data]
393
- if data.kind_of?(Hash) #to json
394
- begin
395
- require 'json'
396
- data=data.to_json
397
- rescue
398
- @logger.fatal "There was a problem converting to json: #{data}"
399
- end
400
- end
401
- end
402
- @logger.warn "Pay attention!!! This is a mock response:"
403
- @start_time_net = Time.now if @start_time_net.nil?
404
- manage_response(arg[:mock_response], data.to_s)
405
- return @response
406
- end
407
- end
408
-
409
- begin
410
- @start_time_net = Time.now if @start_time_net.nil?
411
- if headers_t["Content-Type"] == "multipart/form-data" then
412
- require 'net/http/post/multipart'
413
- headers_t.each {|key, value|
414
- arguments[0][:data].add_field(key, value) #add to Headers
415
- }
416
- resp=@http.request(arguments[0][:data])
417
- else
418
- resp=@http.post(path, data, headers_t)
419
- data=resp.body
420
- end
421
- rescue Exception => stack
422
- @logger.warn stack
423
- @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
424
- @http.finish()
425
- @http.start()
426
- @start_time_net = Time.now if @start_time_net.nil?
427
- resp, data=@http.post(path, data, headers_t)
428
- end
429
- manage_response(resp, data)
430
- if @auto_redirect and @response[:code].to_i>=300 and @response[:code].to_i<400 and @response.include?(:location) then
431
- if @num_redirects<=30 then
432
- @num_redirects+=1
433
- current_server="http"
434
- current_server+="s" if @ssl==true
435
- current_server+="://#{@host}"
436
- location=@response[:location].gsub(current_server, "")
437
- @logger.info "(#{@num_redirects}) Redirecting NiceHttp to #{location}"
438
- get(location)
439
- else
440
- @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"
441
- @num_redirects=0
442
- end
443
- else
444
- @num_redirects=0
445
- end
446
- return @response
447
- rescue Exception => stack
448
- @logger.fatal stack
449
- return {fatal_error: stack.to_s, code: nil, message: nil, data: ''}
450
- end
451
-
452
- end
453
-
454
- ######################################################
455
- # Put data to path
456
- # @param arguments [Hash] containing at least keys :data and :path.
457
- # In case :data not supplied and :data_examples array supplied, it will be taken the first example as :data.
458
- # @param arguments [Array<path, data, additional_headers>]
459
- # path (string).
460
- # data (json data for example).
461
- # additional_headers (Hash key=>value).
462
- # @return [Hash] response
463
- # Including at least the symbol keys:
464
- # :data = the response data body.
465
- # :message = plain text response.
466
- # :code = code response (200=ok,500=wrong...).
467
- # All keys in response are lowercase.
468
- # data, message and code can also be accessed as attributes like .message .code .data.
469
- # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
470
- # @example
471
- # resp = @http.put(Requests::Customer.remove_phone)
472
- ######################################################
473
- def put(*arguments)
474
- begin
475
- path, data, headers_t=manage_request(*arguments)
476
- @start_time = Time.now if @start_time.nil?
477
- if arguments.size>0 and arguments[0].kind_of?(Hash) then
478
- arg=arguments[0]
479
- if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response) then
480
- data=""
481
- if arg[:mock_response].keys.include?(:data) then
482
- data=arg[:mock_response][:data]
483
- if data.kind_of?(Hash) #to json
484
- begin
485
- require 'json'
486
- data=data.to_json
487
- rescue
488
- @logger.fatal "There was a problem converting to json: #{data}"
489
- end
490
- end
491
- end
492
- @logger.warn "Pay attention!!! This is a mock response:"
493
- @start_time_net = Time.now if @start_time_net.nil?
494
- manage_response(arg[:mock_response], data.to_s)
495
- return @response
496
- end
497
- end
498
-
499
- begin
500
- @start_time_net = Time.now if @start_time_net.nil?
501
- resp=@http.send_request("PUT", path, data, headers_t)
502
- data=resp.body
503
- rescue Exception => stack
504
- @logger.warn stack
505
- @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
506
- @http.finish()
507
- @http.start()
508
- @start_time_net = Time.now if @start_time_net.nil?
509
- resp, data=@http.send_request("PUT", path, data, headers_t)
510
- end
511
- manage_response(resp, data)
512
-
513
- return @response
514
- rescue Exception => stack
515
- @logger.fatal stack
516
- return {fatal_error: stack.to_s, code: nil, message: nil, data: ''}
517
- end
518
-
519
- end
520
-
521
-
522
- ######################################################
523
- # Patch data to path
524
- # @param arguments [Hash] containing at least keys :data and :path.
525
- # In case :data not supplied and :data_examples array supplied, it will be taken the first example as :data.
526
- # @param arguments [Array<path, data, additional_headers>]
527
- # path (string).
528
- # data (json data for example).
529
- # additional_headers (Hash key=>value).
530
- # @return [Hash] response
531
- # Including at least the symbol keys:
532
- # :data = the response data body.
533
- # :message = plain text response.
534
- # :code = code response (200=ok,500=wrong...).
535
- # All keys in response are lowercase.
536
- # data, message and code can also be accessed as attributes like .message .code .data.
537
- # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
538
- # @example
539
- # resp = @http.patch(Requests::Customer.unrelease_account)
540
- ######################################################
541
- def patch(*arguments)
542
- begin
543
- path, data, headers_t=manage_request(*arguments)
544
- @start_time = Time.now if @start_time.nil?
545
- if arguments.size>0 and arguments[0].kind_of?(Hash) then
546
- arg=arguments[0]
547
- if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response) then
548
- data=""
549
- if arg[:mock_response].keys.include?(:data) then
550
- data=arg[:mock_response][:data]
551
- if data.kind_of?(Hash) #to json
552
- begin
553
- require 'json'
554
- data=data.to_json
555
- rescue
556
- @logger.fatal "There was a problem converting to json: #{data}"
557
- end
558
- end
559
- end
560
- @logger.warn "Pay attention!!! This is a mock response:"
561
- @start_time_net = Time.now if @start_time_net.nil?
562
- manage_response(arg[:mock_response], data.to_s)
563
- return @response
564
- end
565
- end
566
-
567
- begin
568
- @start_time_net = Time.now if @start_time_net.nil?
569
- resp=@http.patch(path, data, headers_t)
570
- data=resp.body
571
- rescue Exception => stack
572
- @logger.warn stack
573
- @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
574
- @http.finish()
575
- @http.start()
576
- @start_time_net = Time.now if @start_time_net.nil?
577
- resp, data=@http.patch(path, data, headers_t)
578
- end
579
- manage_response(resp, data)
580
- if @auto_redirect and @response[:code].to_i>=300 and @response[:code].to_i<400 and @response.include?(:location) then
581
- if @num_redirects<=30 then
582
- @num_redirects+=1
583
- current_server="http"
584
- current_server+="s" if @ssl==true
585
- current_server+="://#{@host}"
586
- location=@response[:location].gsub(current_server, "")
587
- @logger.info "(#{@num_redirects}) Redirecting NiceHttp to #{location}"
588
- get(location)
589
- else
590
- @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"
591
- @num_redirects=0
592
- end
593
- else
594
- @num_redirects=0
595
- end
596
- return @response
597
- rescue Exception => stack
598
- @logger.fatal stack
599
- return {fatal_error: stack.to_s, code: nil, message: nil, data: ''}
600
- end
601
-
602
- end
603
-
604
- ######################################################
605
- # Delete an existing resource
606
- # @param arg [Hash] containing at least key :path
607
- # @param arg [String] the path
608
- #
609
- # @return [Hash] response
610
- # Including at least the symbol keys:
611
- # :data = the response data body.
612
- # :message = plain text response.
613
- # :code = code response (200=ok,500=wrong...).
614
- # All keys in response are lowercase.
615
- # data, message and code can also be accessed as attributes like .message .code .data.
616
- # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
617
- # @example
618
- # resp = @http.delete(Requests::Customer.remove_session)
619
- # assert resp.code == 204
620
- ######################################################
621
- def delete(argument)
622
- begin
623
- if argument.kind_of?(String) then
624
- argument={:path => argument}
625
- end
626
- path, data, headers_t=manage_request(argument)
627
- @start_time = Time.now if @start_time.nil?
628
- if argument.kind_of?(Hash) then
629
- arg=argument
630
- if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response) then
631
- data=""
632
- if arg[:mock_response].keys.include?(:data) then
633
- data=arg[:mock_response][:data]
634
- if data.kind_of?(Hash) #to json
635
- begin
636
- require 'json'
637
- data=data.to_json
638
- rescue
639
- @logger.fatal "There was a problem converting to json: #{data}"
640
- end
641
- end
642
- end
643
- @logger.warn "Pay attention!!! This is a mock response:"
644
- @start_time_net = Time.now if @start_time_net.nil?
645
- manage_response(arg[:mock_response], data.to_s)
646
- return @response
647
- end
648
- end
649
-
650
- begin
651
- @start_time_net = Time.now if @start_time_net.nil?
652
- resp=@http.delete(path, headers_t)
653
- data=resp.body
654
- rescue Exception => stack
655
- @logger.warn stack
656
- @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
657
- @http.finish()
658
- @http.start()
659
- @start_time_net = Time.now if @start_time_net.nil?
660
- resp, data=@http.delete(path)
661
- end
662
- manage_response(resp, data)
663
-
664
- return @response
665
- rescue Exception => stack
666
- @logger.fatal stack
667
- return {fatal_error: stack.to_s, code: nil, message: nil, data: ''}
668
- end
669
-
670
- end
671
-
672
- ######################################################
673
- # Implementation of the http HEAD method.
674
- # Asks for the response identical to the one that would correspond to a GET request, but without the response body.
675
- # This is useful for retrieving meta-information written in response headers, without having to transport the entire content.
676
- # @param arg [Hash] containing at least key :path
677
- # @param arg [String] the path
678
- #
679
- # @return [Hash] response
680
- # Including at least the symbol keys:
681
- # :message = plain text response.
682
- # :code = code response (200=ok,500=wrong...).
683
- # All keys in response are lowercase.
684
- # message and code can also be accessed as attributes like .message .code.
685
- # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil }
686
- ######################################################
687
- def head(argument)
688
- begin
689
- if argument.kind_of?(String) then
690
- argument={:path => argument}
691
- end
692
- path, data, headers_t=manage_request(argument)
693
- @start_time = Time.now if @start_time.nil?
694
- if argument.kind_of?(Hash) then
695
- arg=argument
696
- if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response) then
697
- data=""
698
- if arg[:mock_response].keys.include?(:data) then
699
- data=arg[:mock_response][:data]
700
- if data.kind_of?(Hash) #to json
701
- begin
702
- require 'json'
703
- data=data.to_json
704
- rescue
705
- @logger.fatal "There was a problem converting to json: #{data}"
706
- end
707
- end
708
- end
709
- @logger.warn "Pay attention!!! This is a mock response:"
710
- @start_time_net = Time.now if @start_time_net.nil?
711
- manage_response(arg[:mock_response], data.to_s)
712
- return @response
713
- end
714
- end
715
-
716
- begin
717
- @start_time_net = Time.now if @start_time_net.nil?
718
- resp=@http.head(path, headers_t)
719
- data=resp.body
720
- rescue Exception => stack
721
- @logger.warn stack
722
- @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
723
- @http.finish()
724
- @http.start()
725
- @start_time_net = Time.now if @start_time_net.nil?
726
- resp, data=@http.head(path)
727
- end
728
- manage_response(resp, data)
729
- return @response
730
- rescue Exception => stack
731
- @logger.fatal stack
732
- return {fatal_error: stack.to_s, code: nil, message: nil}
733
- end
734
- end
735
-
736
-
737
- ######################################################
738
- # Close HTTP connection
739
- ######################################################
740
- def close
741
- begin
742
- pos=0
743
- found=false
744
- NiceHttp.connections.each {|conn|
745
- if conn.object_id == self.object_id then
746
- found=true
747
- break
748
- end
749
- pos+=1
750
- }
751
- if found
752
- NiceHttp.connections.delete_at(pos)
753
- end
754
-
755
- unless @closed
756
- if !@http.nil? then
757
- @http.finish()
758
- @http=nil
759
- @logger.info "the HTTP connection was closed: #{@message_server}"
760
- else
761
- @http=nil
762
- @logger.fatal "It was not possible to close the HTTP connection: #{@message_server}"
763
- end
764
- @closed=true
765
- else
766
- @logger.warn "It was not possible to close the HTTP connection, already closed: #{@message_server}"
767
- end
768
- rescue Exception => stack
769
- @logger.fatal stack
770
- end
771
- NiceHttp.active-=1
772
- end
773
-
774
-
775
- ######################################################
776
- # private method to manage Request
777
- # input:
778
- # 3 args: path, data, headers
779
- # 1 arg: Hash containg at least keys :path and :data
780
- # In case :data not supplied and :data_examples array supplied, it will be taken the first example as :data.
781
- # output:
782
- # path, data, headers
783
- ######################################################
784
- def manage_request(*arguments)
785
- require 'json'
786
- begin
787
- content_type_included=false
788
- path=""
789
- data=""
790
-
791
- @response=Hash.new()
792
- headers_t=@headers.dup()
793
- cookies_to_set_str=""
794
- if arguments.size==3 then
795
- path=arguments[0]
796
- elsif arguments.size==1 and arguments[0].kind_of?(Hash) then
797
- path=arguments[0][:path]
798
- elsif arguments.size==1 and arguments[0].kind_of?(String) then
799
- path=arguments[0].to_s()
800
- end
801
- @cookies.each {|cookie_path, cookies_hash|
802
- cookie_path="" if cookie_path=="/"
803
- path_to_check=path
804
- if path=="/" or path[-1]!="/" then
805
- path_to_check+="/"
806
- end
807
- if path_to_check.scan(/^#{cookie_path}\//).size>0 then
808
- cookies_hash.each {|key, value|
809
- cookies_to_set_str+="#{key}=#{value}; "
810
- }
811
- end
812
- }
813
- headers_t["Cookie"]=cookies_to_set_str
814
-
815
- method_s=caller[0].to_s().scan(/:in `(.*)'/).join
816
-
817
- if arguments.size==3 then
818
- data=arguments[1]
819
- if arguments[2].kind_of?(Hash) then
820
- headers_t.merge!(arguments[2])
821
- end
822
- elsif arguments.size==1 and arguments[0].kind_of?(Hash) then
823
- if arguments[0][:data].nil? then
824
- if arguments[0].keys.include?(:data) then
825
- data=""
826
- elsif arguments[0].keys.include?(:data_examples) and
827
- arguments[0][:data_examples].kind_of?(Array) then
828
- data=arguments[0][:data_examples][0] #the first example by default
829
- else
830
- data=""
831
- end
832
-
833
- else
834
- data=arguments[0][:data]
835
- end
836
- if arguments[0].include?(:headers) then
837
- headers_t.merge!(arguments[0][:headers])
838
- end
839
-
840
- if headers_t["Content-Type"].to_s()=="" and headers_t["content-type"].to_s()=="" and
841
- headers_t[:"content-type"].to_s()=="" and headers_t[:"Content-Type"].to_s()=="" then
842
- content_type_included=false
843
- elsif headers_t["content-type"].to_s()!="" then
844
- content_type_included=true
845
- headers_t["Content-Type"]=headers_t["content-type"]
846
- elsif headers_t[:"content-type"].to_s()!="" then
847
- content_type_included=true
848
- headers_t["Content-Type"]=headers_t[:"content-type"]
849
- headers_t.delete(:"content-type")
850
- elsif headers_t[:"Content-Type"].to_s()!="" then
851
- content_type_included=true
852
- headers_t["Content-Type"]=headers_t[:"Content-Type"]
853
- headers_t.delete(:"Content-Type")
854
- elsif headers_t["Content-Type"].to_s()!="" then
855
- content_type_included=true
856
- end
857
-
858
- if !content_type_included and data.kind_of?(Hash)
859
- headers_t['Content-Type'] = 'application/json'
860
- content_type_included=true
861
- end
862
- # to be backwards compatible since before was :values
863
- if arguments[0].include?(:values) and !arguments[0].include?(:values_for)
864
- arguments[0][:values_for] = arguments[0][:values]
865
- end
866
- if content_type_included and (!headers_t["Content-Type"][/text\/xml/].nil? or
867
- !headers_t["Content-Type"]["application/soap+xml"].nil? or
868
- !headers_t["Content-Type"][/application\/jxml/].nil?) then
869
- if arguments[0].include?(:values_for) then
870
- arguments[0][:values_for].each {|key, value|
871
- data=NiceHttpUtils.set_value_xml_tag(key.to_s(), data, value.to_s(), true)
872
- }
873
- end
874
- elsif content_type_included and !headers_t["Content-Type"][/application\/json/].nil? and data.to_s()!="" then
875
- require 'json'
876
- if data.kind_of?(String) then
877
- if arguments[0].include?(:values_for) then
878
- arguments[0][:values_for].each {|key, value|
879
- data.gsub!(/(( *|^)"?#{key.to_s()}"? *: *")(.*)(" *, *$)/, '\1' + value+ '\4') # "key":"value", or key:"value",
880
- data.gsub!(/(( *|^)"?#{key.to_s()}"? *: *")(.*)(" *$)/, '\1' + value+ '\4') # "key":"value" or key:"value"
881
- data.gsub!(/(( *|^)"?#{key.to_s()}"? *: *[^"])([^"].*)([^"] *, *$)/, '\1' + value+ '\4') # "key":456, or key:456,
882
- data.gsub!(/(( *|^)"?#{key.to_s()}"? *: *[^"])([^"].*)([^"] * *$)/, '\1' + value+ '\4') # "key":456 or key:456
883
- }
884
- end
885
- elsif data.kind_of?(Hash) then
886
- data_n=Hash.new()
887
- data.each {|key, value|
888
- data_n[key.to_s()]=value
889
- }
890
- if arguments[0].include?(:values_for) then
891
- #req[:values_for][:loginName] or req[:values_for]["loginName"]
892
- new_values_hash=Hash.new()
893
- arguments[0][:values_for].each {|kv, vv|
894
- if data_n.keys.include?(kv.to_s()) then
895
- new_values_hash[kv.to_s()]=vv
896
- end
897
- }
898
- data_n.merge!(new_values_hash)
899
- end
900
- data=data_n.to_json()
901
- elsif data.kind_of?(Array) then
902
- data_arr=Array.new()
903
- data.each_with_index {|row, indx|
904
- unless row.kind_of?(Hash) then
905
- @logger.fatal("Wrong format on request application/json, be sure is a Hash, Array of Hashes or JSON string")
906
- return :error, :error, :error
907
- end
908
- data_n=Hash.new()
909
- row.each {|key, value|
910
- data_n[key.to_s()]=value
911
- }
912
- if arguments[0].include?(:values_for) then
913
- #req[:values_for][:loginName] or req[:values_for]["loginName"]
914
- new_values_hash=Hash.new()
915
- if arguments[0][:values_for].kind_of?(Hash) then #values[:mykey][3]
916
- arguments[0][:values_for].each {|kv, vv|
917
- if data_n.keys.include?(kv.to_s()) and !vv[indx].nil? then
918
- new_values_hash[kv.to_s()]=vv[indx]
919
- end
920
- }
921
- elsif arguments[0][:values_for].kind_of?(Array) then #values[5][:mykey]
922
- if !arguments[0][:values_for][indx].nil? then
923
- arguments[0][:values_for][indx].each {|kv, vv|
924
- if data_n.keys.include?(kv.to_s()) then
925
- new_values_hash[kv.to_s()]=vv
926
- end
927
- }
928
- end
929
- else
930
- @logger.fatal("Wrong format on request application/json when supplying values, the data is an array of Hashes but the values supplied are not")
931
- return :error, :error, :error
932
- end
933
- data_n.merge!(new_values_hash)
934
- end
935
- data_arr.push(data_n)
936
- }
937
- data=data_arr.to_json()
938
- else
939
- @logger.fatal("Wrong format on request application/json, be sure is a Hash, Array of Hashes or JSON string")
940
- return :error, :error, :error
941
- end
942
- elsif content_type_included and arguments[0].include?(:values_for) then
943
- if arguments[0][:values_for].kind_of?(Hash) and arguments[0][:values_for].keys.size>0 then
944
- if !headers_t.nil? and headers_t.kind_of?(Hash) and headers_t["Content-Type"]!="application/x-www-form-urlencoded" and headers_t["content-type"]!="application/x-www-form-urlencoded" then
945
- @logger.warn(":values_for key given without a valid content-type or data for request. No values modified on the request")
946
- end
947
- end
948
- end
949
- elsif arguments.size==1 and arguments[0].kind_of?(String) then
950
- #path=arguments[0].to_s()
951
- data=""
952
- else
953
- @logger.fatal("Invalid number of arguments or wrong arguments in #{method_s}")
954
- return :error, :error, :error
955
- end
956
- if headers_t.keys.include?("Content-Type") and !headers_t["Content-Type"]["multipart/form-data"].nil? and headers_t["Content-Type"]!=["multipart/form-data"] then #only for the case raw multipart request
957
- encoding="UTF-8"
958
- data_s=""
959
- else
960
- encoding=data.to_s().scan(/encoding='(.*)'/i).join
961
- if encoding.to_s()=="" then
962
- encoding=data.to_s().scan(/charset='(.*)'/i).join
963
- end
964
- if encoding.to_s()=="" and headers_t.include?("Content-Type") then
965
- encoding=headers_t["Content-Type"].scan(/charset='?(.*)'?/i).join
966
- if encoding.to_s()=="" then
967
- encoding=headers_t["Content-Type"].scan(/encoding='?(.*)'?/i).join
968
- end
969
- end
970
-
971
- begin
972
- data_s=JSON.pretty_generate(JSON.parse(data))
973
- rescue
974
- data_s=data
975
- end
976
- data_s=data_s.to_s().gsub("<", "&lt;")
977
- end
978
- if headers_t.keys.include?("Accept-Encoding")
979
- headers_t["Accept-Encoding"].gsub!("gzip","")#removed so the response is in plain text
980
- end
981
-
982
- headers_ts=""
983
- headers_t.each {|key, val| headers_ts+=key.to_s + ":" + val.to_s() + ", "}
984
- message="#{method_s} REQUEST: \npath= " + path.to_s() + "\n"
985
- message+="headers= " + headers_ts.to_s() + "\n"
986
- message+="data= " + data_s.to_s() + "\n"
987
- message=@message_server+"\n"+message
988
- if path.to_s().scan(/^https?:\/\//).size>0 and path.to_s().scan(/^https?:\/\/#{@host}/).size==0 then
989
- # the path is for another server than the current
990
- else
991
- NiceHttp.last_request=message
992
- @logger.info(message)
993
- end
994
-
995
- if data.to_s()!="" and encoding.to_s().upcase!="UTF-8" and encoding!="" then
996
- data=data.to_s().encode(encoding, "UTF-8")
997
- end
998
- return path, data, headers_t
999
- rescue Exception => stack
1000
- @logger.fatal(stack)
1001
- @logger.fatal("manage_request Error on method #{method_s} . path:#{path.to_s()}. data:#{data.to_s()}. headers:#{headers_t.to_s()}")
1002
- return :error
1003
- end
1004
- end
1005
-
1006
- ######################################################
1007
- # private method to manage Response
1008
- # input:
1009
- # resp
1010
- # data
1011
- # output:
1012
- # @response updated
1013
- ######################################################
1014
- def manage_response(resp, data)
1015
- require 'json'
1016
- begin
1017
- if @start_time.kind_of?(Time)
1018
- @response[:time_elapsed_total]=Time.now-@start_time
1019
- @start_time = nil
1020
- else
1021
- @response[:time_elapsed_total]=nil
1022
- end
1023
- if @start_time_net.kind_of?(Time)
1024
- @response[:time_elapsed]=Time.now-@start_time_net
1025
- @start_time_net = nil
1026
- else
1027
- @response[:time_elapsed]=nil
1028
- end
1029
- begin
1030
- # this is to be able to access all keys as symbols
1031
- new_resp=Hash.new()
1032
- resp.each {|key, value|
1033
- if key.kind_of?(String) then
1034
- new_resp[key.to_sym]=value
1035
- end
1036
- }
1037
- new_resp.each {|key, value|
1038
- resp[key]=value
1039
- }
1040
- rescue
1041
- end
1042
- #for mock_responses to be able to add outside of the header like content-type for example
1043
- if resp.kind_of?(Hash) and !resp.has_key?(:header) then
1044
- resp[:header]={}
1045
- end
1046
- if resp.kind_of?(Hash)
1047
- resp.each {|k, v|
1048
- if k!=:code and k!=:message and k!=:data and k!=:'set-cookie' and k!=:header
1049
- resp[:header][k]=v
1050
- end
1051
- }
1052
- resp[:header].each {|k, v|
1053
- resp.delete(k) if resp.has_key?(k)
1054
- }
1055
- end
1056
-
1057
- method_s=caller[0].to_s().scan(/:in `(.*)'/).join
1058
- if resp.header.kind_of?(Hash) and (resp.header["content-type"].to_s()=="application/x-deflate" or resp.header[:"content-type"].to_s()=="application/x-deflate") then
1059
- data=Zlib::Inflate.inflate(data)
1060
- end
1061
- encoding_response=""
1062
- if resp.header.kind_of?(Hash) and (resp.header["content-type"].to_s()!="" or resp.header[:"content-type"].to_s()!="") then
1063
- encoding_response=resp.header["content-type"].scan(/;charset=(.*)/i).join if resp.header.has_key?("content-type")
1064
- encoding_response=resp.header[:"content-type"].scan(/;charset=(.*)/i).join if resp.header.has_key?(:"content-type")
1065
- end
1066
- if encoding_response.to_s()=="" then
1067
- encoding_response="UTF-8"
1068
- end
1069
-
1070
- if encoding_response.to_s()!="" and encoding_response.to_s().upcase!="UTF-8" then
1071
- data.encode!("UTF-8", encoding_response.to_s())
1072
- end
1073
- if encoding_response!="" and encoding_response.to_s().upcase!="UTF-8" then
1074
- @response[:message]=resp.message.to_s().encode("UTF-8", encoding_response.to_s())
1075
- #todo: response data in here for example is convert into string, verify if that is correct or needs to maintain the original data type (hash, array...)
1076
- resp.each {|key, val| @response[key]=val.to_s().encode("UTF-8", encoding_response.to_s())}
1077
- else
1078
- @response[:message]=resp.message
1079
- resp.each {|key, val| @response[key]=val}
1080
- end
1081
- if !defined?(Net::HTTP::Post::Multipart) or (defined?(Net::HTTP::Post::Multipart) and !data.kind_of?(Net::HTTP::Post::Multipart))
1082
- @response[:data]=data
1083
- else
1084
- @response[:data]=""
1085
- end
1086
-
1087
- @response[:code]=resp.code
1088
-
1089
- unless @response.nil? then
1090
- message="\nRESPONSE: \n" + @response[:code].to_s()+ ":" + @response[:message].to_s()
1091
- if @debug then
1092
- NiceHttp.last_response=message
1093
- @response.each {|key, value|
1094
- if value.to_s()!="" then
1095
- value_orig=value
1096
- if key.kind_of?(Symbol) then
1097
- if key==:code or key==:data or key==:header or key==:message then
1098
- if key==:data then
1099
- begin
1100
- JSON.parse(value_orig)
1101
- data_s=JSON.pretty_generate(JSON.parse(value_orig))
1102
- rescue
1103
- data_s=value_orig
1104
- end
1105
- NiceHttp.last_response+="\nresponse." + key.to_s() + " = '" + data_s.gsub("<", "&lt;") + "'\n"
1106
- if value_orig != value then
1107
- message+="\nresponse." + key.to_s() + " = '" + value.gsub("<", "&lt;") + "'\n"
1108
- else
1109
- message+="\nresponse." + key.to_s() + " = '" + data_s.gsub("<", "&lt;") + "'\n"
1110
- end
1111
- else
1112
- NiceHttp.last_response+="\nresponse." + key.to_s() + " = '" + value.to_s().gsub("<", "&lt;") + "'"
1113
- message+="\nresponse." + key.to_s() + " = '" + value.to_s().gsub("<", "&lt;") + "'"
1114
- end
1115
- else
1116
- NiceHttp.last_response+="\nresponse[:" + key.to_s() + "] = '" + value.to_s().gsub("<", "&lt;") + "'"
1117
- message+="\nresponse[:" + key.to_s() + "] = '" + value.to_s().gsub("<", "&lt;") + "'"
1118
- end
1119
- elsif !@response.include?(key.to_sym)
1120
- NiceHttp.last_response+="\nresponse['" + key.to_s() + "'] = '" + value.to_s().gsub("<", "&lt;") + "'"
1121
- message+="\nresponse['" + key.to_s() + "'] = '" + value.to_s().gsub("<", "&lt;") + "'"
1122
- end
1123
- end
1124
- }
1125
-
1126
- end
1127
- @logger.info message
1128
- if @response.kind_of?(Hash) then
1129
- if @response.keys.include?(:requestid) then
1130
- @headers["requestId"]=@response[:requestid]
1131
- NiceHttp.request_id=@response[:requestid]
1132
- @logger.info "requestId was found on the response header and it has been added to the headers for the next request"
1133
- end
1134
- end
1135
- end
1136
-
1137
- if resp[:'set-cookie'].to_s()!="" then
1138
- if resp.kind_of?(Hash) then #mock_response
1139
- cookies_to_set=resp[:'set-cookie'].to_s().split(", ")
1140
- else #Net::Http
1141
- cookies_to_set=resp.get_fields('set-cookie')
1142
- end
1143
- cookies_to_set.each {|cookie|
1144
- cookie_pair=cookie.split('; ')[0].split("=")
1145
- cookie_path=cookie.scan(/; path=([^;]+)/i).join
1146
- @cookies[cookie_path]=Hash.new() unless @cookies.keys.include?(cookie_path)
1147
- @cookies[cookie_path][cookie_pair[0]]=cookie_pair[1]
1148
- }
1149
-
1150
- @logger.info "set-cookie added to Cookie header as required"
1151
-
1152
- if @headers.has_key?("X-CSRFToken") then
1153
- csrftoken=resp[:"set-cookie"].to_s().scan(/csrftoken=([\da-z]+);/).join
1154
- if csrftoken.to_s()!="" then
1155
- @headers["X-CSRFToken"]=csrftoken
1156
- @logger.info "X-CSRFToken exists on headers and has been overwritten"
1157
- end
1158
- else
1159
- csrftoken=resp[:"set-cookie"].to_s().scan(/csrftoken=([\da-z]+);/).join
1160
- if csrftoken.to_s()!="" then
1161
- @headers["X-CSRFToken"]=csrftoken
1162
- @logger.info "X-CSRFToken added to header as required"
1163
- end
1164
-
1165
- end
1166
- end
1167
-
1168
- rescue Exception => stack
1169
- @logger.fatal stack
1170
- @logger.fatal "manage_response Error on method #{method_s} "
1171
- end
1172
- end
1173
-
1174
- private :manage_request, :manage_response
1175
- end
1176
-
1
+ require "logger"
2
+ require "nice_hash"
3
+ require_relative "nice_http/utils"
4
+
5
+ ######################################################
6
+ # Attributes you can access using NiceHttp.the_attribute:
7
+ # :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port,
8
+ # :last_request, :last_response, :request_id, :use_mocks, :connections,
9
+ # :active, :auto_redirect
10
+ #
11
+ # @attr [String] host The host to be accessed
12
+ # @attr [Integer] port The port number
13
+ # @attr [Boolean] ssl If you use ssl or not
14
+ # @attr [Hash] headers Contains the headers you will be using on your connection
15
+ # @attr [Boolean] debug In case true shows all the details of the communication with the host
16
+ # @attr [String, Symbol] log :fix_file, :no, :screen, :file, "path and file name".
17
+ # :fix_file will log the communication on nice_http.log. (default).
18
+ # :no will not generate any logs.
19
+ # :screen will print the logs on the screen.
20
+ # :file will be generated a log file with name: nice_http_YY-mm-dd-HHMMSS.log.
21
+ # String the path and file name where the logs will be stored.
22
+ # @attr [String] proxy_host the proxy host to be used
23
+ # @attr [Integer] proxy_port the proxy port to be used
24
+ # @attr [String] last_request The last request with all the content sent
25
+ # @attr [String] last_response Only in case :debug is true, the last response with all the content
26
+ # @attr [String] request_id If the response includes a requestId, will be stored here
27
+ # @attr [Boolean] use_mocks If true, in case the request hash includes a :mock_response key, it will be used as the response instead
28
+ # @attr [Array] connections It will include all the active connections (NiceHttp instances)
29
+ # @attr [Integer] active Number of active connections
30
+ # @attr [Boolean] auto_redirect If true, NiceHttp will take care of the auto redirections when required by the responses
31
+ # @attr [Hash] response Contains the full response hash
32
+ # @attr [Integer] num_redirects Number of consecutive redirections managed
33
+ # @attr [Hash] headers The updated headers of the communication
34
+ # @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:
35
+ # { '/' => { "cfid" => "d95adfas2550255", "amddom.settings" => "doom" } }
36
+ # @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:
37
+ # my_http.logger.info "add this to the log file"
38
+ # @see https://ruby-doc.org/stdlib-2.5.0/libdoc/logger/rdoc/Logger.html
39
+ ######################################################
40
+ class NiceHttp
41
+ Error = Class.new StandardError
42
+
43
+ InfoMissing = Class.new Error do
44
+ attr_reader :attribute
45
+
46
+ def initialize(attribute)
47
+ @attribute = attribute
48
+ message = "It was not possible to create the http connection!!!\n"
49
+ message += "Wrong #{attribute}, remember to supply http:// or https:// in case you specify an url to create the http connection, for example:\n"
50
+ message += "http = NiceHttp.new('http://example.com')"
51
+ super message
52
+ end
53
+ end
54
+
55
+ class << self
56
+ attr_accessor :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port,
57
+ :last_request, :last_response, :request_id, :use_mocks, :connections,
58
+ :active, :auto_redirect
59
+ end
60
+
61
+ ######################################################
62
+ # to reset to the original defaults
63
+ ######################################################
64
+ def self.reset!
65
+ @host = nil
66
+ @port = 80
67
+ @ssl = false
68
+ @headers = {}
69
+ @debug = false
70
+ @log = :fix_file
71
+ @proxy_host = nil
72
+ @proxy_port = nil
73
+ @last_request = nil
74
+ @last_response = nil
75
+ @request_id = ""
76
+ @use_mocks = false
77
+ @connections = []
78
+ @active = 0
79
+ @auto_redirect = true
80
+ end
81
+ reset!
82
+
83
+ ######################################################
84
+ # If inheriting from NiceHttp class
85
+ ######################################################
86
+ def self.inherited(subclass)
87
+ subclass.reset!
88
+ end
89
+
90
+ attr_reader :host, :port, :ssl, :debug, :log, :proxy_host, :proxy_port, :response, :num_redirects
91
+ attr_accessor :headers, :cookies, :use_mocks, :auto_redirect, :logger
92
+
93
+ ######################################################
94
+ # Change the default values for NiceHttp supplying a Hash
95
+ #
96
+ # @param par [Hash] keys: :host, :port, :ssl, :headers, :debug, :log, :proxy_host, :proxy_port, :use_mocks, :auto_redirect
97
+ ######################################################
98
+ def self.defaults=(par = {})
99
+ @host = par[:host] if par.key?(:host)
100
+ @port = par[:port] if par.key?(:port)
101
+ @ssl = par[:ssl] if par.key?(:ssl)
102
+ @headers = par[:headers].dup if par.key?(:headers)
103
+ @debug = par[:debug] if par.key?(:debug)
104
+ @log = par[:log] if par.key?(:log)
105
+ @proxy_host = par[:proxy_host] if par.key?(:proxy_host)
106
+ @proxy_port = par[:proxy_port] if par.key?(:proxy_port)
107
+ @use_mocks = par[:use_mocks] if par.key?(:use_mocks)
108
+ @auto_redirect = par[:auto_redirect] if par.key?(:auto_redirect)
109
+ end
110
+
111
+ ######################################################
112
+ # Creates a new http connection.
113
+ #
114
+ # @param args [] If no parameter supplied, by default will access how is setup on defaults
115
+ # @example
116
+ # http = NiceHttp.new()
117
+ # @param args [String]. The url to create the connection.
118
+ # @example
119
+ # http = NiceHttp.new("https://www.example.com")
120
+ # @example
121
+ # http = NiceHttp.new("example.com:8999")
122
+ # @example
123
+ # http = NiceHttp.new("localhost:8322")
124
+ # @param args [Hash] containing these possible keys:
125
+ #
126
+ # host -- example.com. (default blank screen)
127
+ #
128
+ # port -- port for the connection. 80 (default)
129
+ #
130
+ # ssl -- true, false (default)
131
+ #
132
+ # headers -- hash with the headers
133
+ #
134
+ # debug -- true, false (default)
135
+ #
136
+ # log -- :no, :screen, :file, :fix_file (default).
137
+ #
138
+ # A string with a path can be supplied.
139
+ #
140
+ # If :fix_file: nice_http.log
141
+ #
142
+ # In case :file it will be generated a log file with name: nice_http_YY-mm-dd-HHMMSS.log
143
+ #
144
+ # proxy_host
145
+ #
146
+ # proxy_port
147
+ # @example
148
+ # http2 = NiceHttp.new( host: "reqres.in", port: 443, ssl: true )
149
+ # @example
150
+ # my_server = {host: "example.com",
151
+ # port: 80,
152
+ # headers: {"api-key": "zdDDdjkck"}
153
+ # }
154
+ # http3 = NiceHttp.new my_server
155
+ ######################################################
156
+ def initialize(args = {})
157
+ require "net/http"
158
+ require "net/https"
159
+ @host = self.class.host
160
+ @port = self.class.port
161
+ @ssl = self.class.ssl
162
+ @headers = self.class.headers.dup
163
+ @debug = self.class.debug
164
+ @log = self.class.log
165
+ @proxy_host = self.class.proxy_host
166
+ @proxy_port = self.class.proxy_port
167
+ @use_mocks = self.class.use_mocks
168
+ @auto_redirect = false #set it up at the end of initialize
169
+ auto_redirect = self.class.auto_redirect
170
+ @num_redirects = 0
171
+
172
+ #todo: set only the cookies for the current domain
173
+ #key: path, value: hash with key is the name of the cookie and value the value
174
+ # we set the default value for non existing keys to empty Hash {} so in case of merge there is no problem
175
+ @cookies = Hash.new { |h, k| h[k] = {} }
176
+
177
+ if args.is_a?(String)
178
+ uri = URI.parse(args)
179
+ @host = uri.host unless uri.host.nil?
180
+ @port = uri.port unless uri.port.nil?
181
+ @ssl = true if !uri.scheme.nil? && (uri.scheme == "https")
182
+ elsif args.is_a?(Hash) && !args.keys.empty?
183
+ @host = args[:host] if args.keys.include?(:host)
184
+ @port = args[:port] if args.keys.include?(:port)
185
+ @ssl = args[:ssl] if args.keys.include?(:ssl)
186
+ @headers = args[:headers].dup if args.keys.include?(:headers)
187
+ @debug = args[:debug] if args.keys.include?(:debug)
188
+ @log = args[:log] if args.keys.include?(:log)
189
+ @proxy_host = args[:proxy_host] if args.keys.include?(:proxy_host)
190
+ @proxy_port = args[:proxy_port] if args.keys.include?(:proxy_port)
191
+ @use_mocks = args[:use_mocks] if args.keys.include?(:use_mocks)
192
+ auto_redirect = args[:auto_redirect] if args.keys.include?(:auto_redirect)
193
+ end
194
+
195
+ begin
196
+ if @log.kind_of?(String)
197
+ @logger = Logger.new File.new(@log, "w")
198
+ elsif @log == :fix_file
199
+ @logger = Logger.new File.new("nice_http.log", "w")
200
+ elsif @log == :file
201
+ @logger = Logger.new File.new("nice_http_#{Time.now.strftime("%Y-%m-%d-%H%M%S")}.log", "w")
202
+ elsif @log == :screen
203
+ @logger = Logger.new STDOUT
204
+ elsif @log == :no
205
+ @logger = Logger.new nil
206
+ else
207
+ raise InfoMissing, :log
208
+ end
209
+ @logger.level = Logger::INFO
210
+ rescue Exception => stack
211
+ raise InfoMissing, :log
212
+ @logger = Logger.new nil
213
+ end
214
+
215
+
216
+ if @host.to_s != "" and (@host.include?("http:") or @host.include?("https:"))
217
+ uri = URI.parse(@host)
218
+ @host = uri.host unless uri.host.nil?
219
+ @port = uri.port unless uri.port.nil?
220
+ @ssl = true if !uri.scheme.nil? && (uri.scheme == "https")
221
+ end
222
+
223
+ raise InfoMissing, :port if @port.to_s == ""
224
+ raise InfoMissing, :host if @host.to_s == ""
225
+ raise InfoMissing, :ssl unless @ssl.is_a?(TrueClass) or @ssl.is_a?(FalseClass)
226
+ raise InfoMissing, :debug unless @debug.is_a?(TrueClass) or @debug.is_a?(FalseClass)
227
+ raise InfoMissing, :auto_redirect unless auto_redirect.is_a?(TrueClass) or auto_redirect.is_a?(FalseClass)
228
+ raise InfoMissing, :use_mocks unless @use_mocks.is_a?(TrueClass) or @use_mocks.is_a?(FalseClass)
229
+ raise InfoMissing, :headers unless @headers.is_a?(Hash)
230
+
231
+ begin
232
+ if !@proxy_host.nil? && !@proxy_port.nil?
233
+ @http = Net::HTTP::Proxy(@proxy_host, @proxy_port).new(@host, @port)
234
+ @http.use_ssl = @ssl
235
+ @http.set_debug_output $stderr if @debug
236
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
237
+ @http.start
238
+ else
239
+ @http = Net::HTTP.new(@host, @port)
240
+ @http.use_ssl = @ssl
241
+ @http.set_debug_output $stderr if @debug
242
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
243
+ @http.start
244
+ end
245
+
246
+ @message_server = "(#{self.object_id}):"
247
+
248
+ 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()} "
249
+
250
+ @logger.info(log_message)
251
+ @message_server += " Http connection: "
252
+ if @ssl
253
+ @message_server += "https://"
254
+ else
255
+ @message_server += "http://"
256
+ end
257
+ @message_server += "#{@host}:#{@port}"
258
+ if @proxy_host.to_s != ""
259
+ @message_server += " proxy:#{@proxy_host}:#{@proxy_port}"
260
+ end
261
+ @auto_redirect = auto_redirect
262
+
263
+ self.class.active += 1
264
+ self.class.connections.push(self)
265
+ rescue Exception => stack
266
+ puts stack
267
+ @logger.fatal stack
268
+ end
269
+ end
270
+
271
+ ######################################################
272
+ # Get data from path
273
+ #
274
+ # @param arg [Hash] containing at least key :path
275
+ # @param arg [String] the path
276
+ #
277
+ # @return [Hash] response
278
+ # Including at least the symbol keys:
279
+ # :data = the response data body.
280
+ # :message = plain text response.
281
+ # :code = code response (200=ok,500=wrong...).
282
+ # All keys in response are lowercase.
283
+ # data, message and code can also be accessed as attributes like .message .code .data.
284
+ # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
285
+ #
286
+ # @example
287
+ # resp = @http.get(Requests::Customer.get_profile)
288
+ # assert resp.code == 200
289
+ # @example
290
+ # resp = @http.get("/customers/1223")
291
+ # assert resp.message == "OK"
292
+ ######################################################
293
+ def get(arg)
294
+ begin
295
+ path, data, headers_t = manage_request(arg)
296
+
297
+ @start_time = Time.now if @start_time.nil?
298
+ if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response)
299
+ data = ""
300
+ if arg[:mock_response].keys.include?(:data)
301
+ data = arg[:mock_response][:data]
302
+ if data.kind_of?(Hash) #to json
303
+ begin
304
+ require "json"
305
+ data = data.to_json
306
+ rescue
307
+ @logger.fatal "There was a problem converting to json: #{data}"
308
+ end
309
+ end
310
+ end
311
+ @logger.warn "Pay attention!!! This is a mock response:"
312
+ @start_time_net = Time.now if @start_time_net.nil?
313
+ manage_response(arg[:mock_response], data.to_s)
314
+ return @response
315
+ end
316
+ begin
317
+ if path.start_with?("http:") or path.start_with?("https:") #server included on path problably because of a redirection to a different server
318
+ require "uri"
319
+ uri = URI.parse(path)
320
+ ssl = false
321
+ ssl = true if path.include?("https:")
322
+
323
+ server = "http://"
324
+ server = "https://" if path.include?("https:")
325
+ if uri.port != 443
326
+ server += "#{uri.host}:#{uri.port}"
327
+ else
328
+ server += "#{uri.host}"
329
+ end
330
+
331
+ http_redir = nil
332
+ self.class.connections.each { |conn|
333
+ if conn.host == uri.host and conn.port == uri.port
334
+ http_redir = conn
335
+ break
336
+ end
337
+ }
338
+
339
+ if !http_redir.nil?
340
+ path, data, headers_t = manage_request(arg)
341
+ http_redir.cookies.merge!(@cookies)
342
+ http_redir.headers.merge!(headers_t)
343
+ resp = http_redir.get(path.gsub(server, "")) #todo: remove only the server at the begining in case in query is the server it will be replaced when it should not be
344
+ @response = http_redir.response
345
+ else
346
+ @logger.warn "It seems like the http connection cannot redirect to #{server} because there is no active connection for that server. You need to create previously one."
347
+ end
348
+ else
349
+ @start_time_net = Time.now if @start_time_net.nil?
350
+ resp = @http.get(path, headers_t)
351
+ data = resp.body
352
+ manage_response(resp, data)
353
+ end
354
+ rescue Exception => stack
355
+ @logger.warn stack
356
+ @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
357
+ @http.finish()
358
+ @http.start()
359
+ @start_time_net = Time.now if @start_time_net.nil?
360
+ resp = @http.get(path)
361
+ data = resp.body
362
+ manage_response(resp, data)
363
+ end
364
+
365
+ if @auto_redirect and @response[:code].to_i >= 300 and @response[:code].to_i < 400 and @response.include?(:location)
366
+ if @num_redirects <= 30
367
+ @num_redirects += 1
368
+ current_server = "http"
369
+ current_server += "s" if @ssl == true
370
+ current_server += "://#{@host}"
371
+ location = @response[:location].gsub(current_server, "")
372
+ @logger.info "(#{@num_redirects}) Redirecting NiceHttp to #{location}"
373
+ get(location)
374
+ else
375
+ @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"
376
+ @num_redirects = 0
377
+ end
378
+ else
379
+ @num_redirects = 0
380
+ end
381
+ return @response
382
+ rescue Exception => stack
383
+ @logger.fatal stack
384
+ return {fatal_error: stack.to_s, code: nil, message: nil, data: ""}
385
+ end
386
+ end
387
+
388
+ ######################################################
389
+ # Post data to path
390
+ # @param arguments [Hash] containing at least keys :data and :path.
391
+ # In case :data not supplied and :data_examples array supplied, it will be taken the first example as :data.
392
+ # @param arguments [Array<path, data, additional_headers>]
393
+ # path (string).
394
+ # data (json data for example).
395
+ # additional_headers (Hash key=>value).
396
+ # @return [Hash] response
397
+ # Including at least the symbol keys:
398
+ # :data = the response data body.
399
+ # :message = plain text response.
400
+ # :code = code response (200=ok,500=wrong...).
401
+ # All keys in response are lowercase.
402
+ # data, message and code can also be accessed as attributes like .message .code .data.
403
+ # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
404
+ # @example
405
+ # resp = @http.post(Requests::Customer.update_customer)
406
+ # assert resp.code == 201
407
+ # @example
408
+ # resp = http.post( {
409
+ # path: "/api/users",
410
+ # data: {name: "morpheus", job: "leader"}
411
+ # } )
412
+ # pp resp.data.json
413
+ ######################################################
414
+ def post(*arguments)
415
+ begin
416
+ path, data, headers_t = manage_request(*arguments)
417
+ @start_time = Time.now if @start_time.nil?
418
+ if arguments.size > 0 and arguments[0].kind_of?(Hash)
419
+ arg = arguments[0]
420
+ if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response)
421
+ data = ""
422
+ if arg[:mock_response].keys.include?(:data)
423
+ data = arg[:mock_response][:data]
424
+ if data.kind_of?(Hash) #to json
425
+ begin
426
+ require "json"
427
+ data = data.to_json
428
+ rescue
429
+ @logger.fatal "There was a problem converting to json: #{data}"
430
+ end
431
+ end
432
+ end
433
+ @logger.warn "Pay attention!!! This is a mock response:"
434
+ @start_time_net = Time.now if @start_time_net.nil?
435
+ manage_response(arg[:mock_response], data.to_s)
436
+ return @response
437
+ end
438
+ end
439
+
440
+ begin
441
+ @start_time_net = Time.now if @start_time_net.nil?
442
+ if headers_t["Content-Type"] == "multipart/form-data"
443
+ require "net/http/post/multipart"
444
+ headers_t.each { |key, value|
445
+ arguments[0][:data].add_field(key, value) #add to Headers
446
+ }
447
+ resp = @http.request(arguments[0][:data])
448
+ else
449
+ resp = @http.post(path, data, headers_t)
450
+ data = resp.body
451
+ end
452
+ rescue Exception => stack
453
+ @logger.warn stack
454
+ @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
455
+ @http.finish()
456
+ @http.start()
457
+ @start_time_net = Time.now if @start_time_net.nil?
458
+ resp, data = @http.post(path, data, headers_t)
459
+ end
460
+ manage_response(resp, data)
461
+ if @auto_redirect and @response[:code].to_i >= 300 and @response[:code].to_i < 400 and @response.include?(:location)
462
+ if @num_redirects <= 30
463
+ @num_redirects += 1
464
+ current_server = "http"
465
+ current_server += "s" if @ssl == true
466
+ current_server += "://#{@host}"
467
+ location = @response[:location].gsub(current_server, "")
468
+ @logger.info "(#{@num_redirects}) Redirecting NiceHttp to #{location}"
469
+ get(location)
470
+ else
471
+ @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"
472
+ @num_redirects = 0
473
+ end
474
+ else
475
+ @num_redirects = 0
476
+ end
477
+ return @response
478
+ rescue Exception => stack
479
+ @logger.fatal stack
480
+ return {fatal_error: stack.to_s, code: nil, message: nil, data: ""}
481
+ end
482
+ end
483
+
484
+ ######################################################
485
+ # Put data to path
486
+ # @param arguments [Hash] containing at least keys :data and :path.
487
+ # In case :data not supplied and :data_examples array supplied, it will be taken the first example as :data.
488
+ # @param arguments [Array<path, data, additional_headers>]
489
+ # path (string).
490
+ # data (json data for example).
491
+ # additional_headers (Hash key=>value).
492
+ # @return [Hash] response
493
+ # Including at least the symbol keys:
494
+ # :data = the response data body.
495
+ # :message = plain text response.
496
+ # :code = code response (200=ok,500=wrong...).
497
+ # All keys in response are lowercase.
498
+ # data, message and code can also be accessed as attributes like .message .code .data.
499
+ # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
500
+ # @example
501
+ # resp = @http.put(Requests::Customer.remove_phone)
502
+ ######################################################
503
+ def put(*arguments)
504
+ begin
505
+ path, data, headers_t = manage_request(*arguments)
506
+ @start_time = Time.now if @start_time.nil?
507
+ if arguments.size > 0 and arguments[0].kind_of?(Hash)
508
+ arg = arguments[0]
509
+ if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response)
510
+ data = ""
511
+ if arg[:mock_response].keys.include?(:data)
512
+ data = arg[:mock_response][:data]
513
+ if data.kind_of?(Hash) #to json
514
+ begin
515
+ require "json"
516
+ data = data.to_json
517
+ rescue
518
+ @logger.fatal "There was a problem converting to json: #{data}"
519
+ end
520
+ end
521
+ end
522
+ @logger.warn "Pay attention!!! This is a mock response:"
523
+ @start_time_net = Time.now if @start_time_net.nil?
524
+ manage_response(arg[:mock_response], data.to_s)
525
+ return @response
526
+ end
527
+ end
528
+
529
+ begin
530
+ @start_time_net = Time.now if @start_time_net.nil?
531
+ resp = @http.send_request("PUT", path, data, headers_t)
532
+ data = resp.body
533
+ rescue Exception => stack
534
+ @logger.warn stack
535
+ @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
536
+ @http.finish()
537
+ @http.start()
538
+ @start_time_net = Time.now if @start_time_net.nil?
539
+ resp, data = @http.send_request("PUT", path, data, headers_t)
540
+ end
541
+ manage_response(resp, data)
542
+
543
+ return @response
544
+ rescue Exception => stack
545
+ @logger.fatal stack
546
+ return {fatal_error: stack.to_s, code: nil, message: nil, data: ""}
547
+ end
548
+ end
549
+
550
+ ######################################################
551
+ # Patch data to path
552
+ # @param arguments [Hash] containing at least keys :data and :path.
553
+ # In case :data not supplied and :data_examples array supplied, it will be taken the first example as :data.
554
+ # @param arguments [Array<path, data, additional_headers>]
555
+ # path (string).
556
+ # data (json data for example).
557
+ # additional_headers (Hash key=>value).
558
+ # @return [Hash] response
559
+ # Including at least the symbol keys:
560
+ # :data = the response data body.
561
+ # :message = plain text response.
562
+ # :code = code response (200=ok,500=wrong...).
563
+ # All keys in response are lowercase.
564
+ # data, message and code can also be accessed as attributes like .message .code .data.
565
+ # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
566
+ # @example
567
+ # resp = @http.patch(Requests::Customer.unrelease_account)
568
+ ######################################################
569
+ def patch(*arguments)
570
+ begin
571
+ path, data, headers_t = manage_request(*arguments)
572
+ @start_time = Time.now if @start_time.nil?
573
+ if arguments.size > 0 and arguments[0].kind_of?(Hash)
574
+ arg = arguments[0]
575
+ if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response)
576
+ data = ""
577
+ if arg[:mock_response].keys.include?(:data)
578
+ data = arg[:mock_response][:data]
579
+ if data.kind_of?(Hash) #to json
580
+ begin
581
+ require "json"
582
+ data = data.to_json
583
+ rescue
584
+ @logger.fatal "There was a problem converting to json: #{data}"
585
+ end
586
+ end
587
+ end
588
+ @logger.warn "Pay attention!!! This is a mock response:"
589
+ @start_time_net = Time.now if @start_time_net.nil?
590
+ manage_response(arg[:mock_response], data.to_s)
591
+ return @response
592
+ end
593
+ end
594
+
595
+ begin
596
+ @start_time_net = Time.now if @start_time_net.nil?
597
+ resp = @http.patch(path, data, headers_t)
598
+ data = resp.body
599
+ rescue Exception => stack
600
+ @logger.warn stack
601
+ @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
602
+ @http.finish()
603
+ @http.start()
604
+ @start_time_net = Time.now if @start_time_net.nil?
605
+ resp, data = @http.patch(path, data, headers_t)
606
+ end
607
+ manage_response(resp, data)
608
+ if @auto_redirect and @response[:code].to_i >= 300 and @response[:code].to_i < 400 and @response.include?(:location)
609
+ if @num_redirects <= 30
610
+ @num_redirects += 1
611
+ current_server = "http"
612
+ current_server += "s" if @ssl == true
613
+ current_server += "://#{@host}"
614
+ location = @response[:location].gsub(current_server, "")
615
+ @logger.info "(#{@num_redirects}) Redirecting NiceHttp to #{location}"
616
+ get(location)
617
+ else
618
+ @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"
619
+ @num_redirects = 0
620
+ end
621
+ else
622
+ @num_redirects = 0
623
+ end
624
+ return @response
625
+ rescue Exception => stack
626
+ @logger.fatal stack
627
+ return {fatal_error: stack.to_s, code: nil, message: nil, data: ""}
628
+ end
629
+ end
630
+
631
+ ######################################################
632
+ # Delete an existing resource
633
+ # @param arg [Hash] containing at least key :path
634
+ # @param arg [String] the path
635
+ #
636
+ # @return [Hash] response
637
+ # Including at least the symbol keys:
638
+ # :data = the response data body.
639
+ # :message = plain text response.
640
+ # :code = code response (200=ok,500=wrong...).
641
+ # All keys in response are lowercase.
642
+ # data, message and code can also be accessed as attributes like .message .code .data.
643
+ # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil, data: '' }
644
+ # @example
645
+ # resp = @http.delete(Requests::Customer.remove_session)
646
+ # assert resp.code == 204
647
+ ######################################################
648
+ def delete(argument)
649
+ begin
650
+ if argument.kind_of?(String)
651
+ argument = {:path => argument}
652
+ end
653
+ path, data, headers_t = manage_request(argument)
654
+ @start_time = Time.now if @start_time.nil?
655
+ if argument.kind_of?(Hash)
656
+ arg = argument
657
+ if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response)
658
+ data = ""
659
+ if arg[:mock_response].keys.include?(:data)
660
+ data = arg[:mock_response][:data]
661
+ if data.kind_of?(Hash) #to json
662
+ begin
663
+ require "json"
664
+ data = data.to_json
665
+ rescue
666
+ @logger.fatal "There was a problem converting to json: #{data}"
667
+ end
668
+ end
669
+ end
670
+ @logger.warn "Pay attention!!! This is a mock response:"
671
+ @start_time_net = Time.now if @start_time_net.nil?
672
+ manage_response(arg[:mock_response], data.to_s)
673
+ return @response
674
+ end
675
+ end
676
+
677
+ begin
678
+ @start_time_net = Time.now if @start_time_net.nil?
679
+ resp = @http.delete(path, headers_t)
680
+ data = resp.body
681
+ rescue Exception => stack
682
+ @logger.warn stack
683
+ @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
684
+ @http.finish()
685
+ @http.start()
686
+ @start_time_net = Time.now if @start_time_net.nil?
687
+ resp, data = @http.delete(path)
688
+ end
689
+ manage_response(resp, data)
690
+
691
+ return @response
692
+ rescue Exception => stack
693
+ @logger.fatal stack
694
+ return {fatal_error: stack.to_s, code: nil, message: nil, data: ""}
695
+ end
696
+ end
697
+
698
+ ######################################################
699
+ # Implementation of the http HEAD method.
700
+ # Asks for the response identical to the one that would correspond to a GET request, but without the response body.
701
+ # This is useful for retrieving meta-information written in response headers, without having to transport the entire content.
702
+ # @param arg [Hash] containing at least key :path
703
+ # @param arg [String] the path
704
+ #
705
+ # @return [Hash] response
706
+ # Including at least the symbol keys:
707
+ # :message = plain text response.
708
+ # :code = code response (200=ok,500=wrong...).
709
+ # All keys in response are lowercase.
710
+ # message and code can also be accessed as attributes like .message .code.
711
+ # In case of fatal error returns { fatal_error: "the error description", code: nil, message: nil }
712
+ ######################################################
713
+ def head(argument)
714
+ begin
715
+ if argument.kind_of?(String)
716
+ argument = {:path => argument}
717
+ end
718
+ path, data, headers_t = manage_request(argument)
719
+ @start_time = Time.now if @start_time.nil?
720
+ if argument.kind_of?(Hash)
721
+ arg = argument
722
+ if @use_mocks and arg.kind_of?(Hash) and arg.keys.include?(:mock_response)
723
+ data = ""
724
+ if arg[:mock_response].keys.include?(:data)
725
+ data = arg[:mock_response][:data]
726
+ if data.kind_of?(Hash) #to json
727
+ begin
728
+ require "json"
729
+ data = data.to_json
730
+ rescue
731
+ @logger.fatal "There was a problem converting to json: #{data}"
732
+ end
733
+ end
734
+ end
735
+ @logger.warn "Pay attention!!! This is a mock response:"
736
+ @start_time_net = Time.now if @start_time_net.nil?
737
+ manage_response(arg[:mock_response], data.to_s)
738
+ return @response
739
+ end
740
+ end
741
+
742
+ begin
743
+ @start_time_net = Time.now if @start_time_net.nil?
744
+ resp = @http.head(path, headers_t)
745
+ data = resp.body
746
+ rescue Exception => stack
747
+ @logger.warn stack
748
+ @logger.warn "The connection seems to be closed in the host machine. Trying to reconnect"
749
+ @http.finish()
750
+ @http.start()
751
+ @start_time_net = Time.now if @start_time_net.nil?
752
+ resp, data = @http.head(path)
753
+ end
754
+ manage_response(resp, data)
755
+ return @response
756
+ rescue Exception => stack
757
+ @logger.fatal stack
758
+ return {fatal_error: stack.to_s, code: nil, message: nil}
759
+ end
760
+ end
761
+
762
+ ######################################################
763
+ # Close HTTP connection
764
+ ######################################################
765
+ def close
766
+ begin
767
+ pos = 0
768
+ found = false
769
+ self.class.connections.each { |conn|
770
+ if conn.object_id == self.object_id
771
+ found = true
772
+ break
773
+ end
774
+ pos += 1
775
+ }
776
+ if found
777
+ self.class.connections.delete_at(pos)
778
+ end
779
+
780
+ unless @closed
781
+ if !@http.nil?
782
+ @http.finish()
783
+ @http = nil
784
+ @logger.info "the HTTP connection was closed: #{@message_server}"
785
+ else
786
+ @http = nil
787
+ @logger.fatal "It was not possible to close the HTTP connection: #{@message_server}"
788
+ end
789
+ @closed = true
790
+ else
791
+ @logger.warn "It was not possible to close the HTTP connection, already closed: #{@message_server}"
792
+ end
793
+ rescue Exception => stack
794
+ @logger.fatal stack
795
+ end
796
+ self.class.active -= 1
797
+ end
798
+
799
+ ######################################################
800
+ # private method to manage Request
801
+ # input:
802
+ # 3 args: path, data, headers
803
+ # 1 arg: Hash containg at least keys :path and :data
804
+ # In case :data not supplied and :data_examples array supplied, it will be taken the first example as :data.
805
+ # output:
806
+ # path, data, headers
807
+ ######################################################
808
+ def manage_request(*arguments)
809
+ require "json"
810
+ begin
811
+ content_type_included = false
812
+ path = ""
813
+ data = ""
814
+
815
+ @response = Hash.new()
816
+ headers_t = @headers.dup()
817
+ cookies_to_set_str = ""
818
+ if arguments.size == 3
819
+ path = arguments[0]
820
+ elsif arguments.size == 1 and arguments[0].kind_of?(Hash)
821
+ path = arguments[0][:path]
822
+ elsif arguments.size == 1 and arguments[0].kind_of?(String)
823
+ path = arguments[0].to_s()
824
+ end
825
+ @cookies.each { |cookie_path, cookies_hash|
826
+ cookie_path = "" if cookie_path == "/"
827
+ path_to_check = path
828
+ if path == "/" or path[-1] != "/"
829
+ path_to_check += "/"
830
+ end
831
+ if path_to_check.scan(/^#{cookie_path}\//).size > 0
832
+ cookies_hash.each { |key, value|
833
+ cookies_to_set_str += "#{key}=#{value}; "
834
+ }
835
+ end
836
+ }
837
+ headers_t["Cookie"] = cookies_to_set_str
838
+
839
+ method_s = caller[0].to_s().scan(/:in `(.*)'/).join
840
+
841
+ if arguments.size == 3
842
+ data = arguments[1]
843
+ if arguments[2].kind_of?(Hash)
844
+ headers_t.merge!(arguments[2])
845
+ end
846
+ elsif arguments.size == 1 and arguments[0].kind_of?(Hash)
847
+ if arguments[0][:data].nil?
848
+ if arguments[0].keys.include?(:data)
849
+ data = ""
850
+ elsif arguments[0].keys.include?(:data_examples) and
851
+ arguments[0][:data_examples].kind_of?(Array)
852
+ data = arguments[0][:data_examples][0] #the first example by default
853
+ else
854
+ data = ""
855
+ end
856
+ else
857
+ data = arguments[0][:data]
858
+ end
859
+ if arguments[0].include?(:headers)
860
+ headers_t.merge!(arguments[0][:headers])
861
+ end
862
+
863
+ if headers_t["Content-Type"].to_s() == "" and headers_t["content-type"].to_s() == "" and
864
+ headers_t[:"content-type"].to_s() == "" and headers_t[:"Content-Type"].to_s() == ""
865
+ content_type_included = false
866
+ elsif headers_t["content-type"].to_s() != ""
867
+ content_type_included = true
868
+ headers_t["Content-Type"] = headers_t["content-type"]
869
+ elsif headers_t[:"content-type"].to_s() != ""
870
+ content_type_included = true
871
+ headers_t["Content-Type"] = headers_t[:"content-type"]
872
+ headers_t.delete(:"content-type")
873
+ elsif headers_t[:"Content-Type"].to_s() != ""
874
+ content_type_included = true
875
+ headers_t["Content-Type"] = headers_t[:"Content-Type"]
876
+ headers_t.delete(:"Content-Type")
877
+ elsif headers_t["Content-Type"].to_s() != ""
878
+ content_type_included = true
879
+ end
880
+
881
+ if !content_type_included and data.kind_of?(Hash)
882
+ headers_t["Content-Type"] = "application/json"
883
+ content_type_included = true
884
+ end
885
+ # to be backwards compatible since before was :values
886
+ if arguments[0].include?(:values) and !arguments[0].include?(:values_for)
887
+ arguments[0][:values_for] = arguments[0][:values]
888
+ end
889
+ if content_type_included and (!headers_t["Content-Type"][/text\/xml/].nil? or
890
+ !headers_t["Content-Type"]["application/soap+xml"].nil? or
891
+ !headers_t["Content-Type"][/application\/jxml/].nil?)
892
+ if arguments[0].include?(:values_for)
893
+ arguments[0][:values_for].each { |key, value|
894
+ data = NiceHttpUtils.set_value_xml_tag(key.to_s(), data, value.to_s(), true)
895
+ }
896
+ end
897
+ elsif content_type_included and !headers_t["Content-Type"][/application\/json/].nil? and data.to_s() != ""
898
+ require "json"
899
+ if data.kind_of?(String)
900
+ if arguments[0].include?(:values_for)
901
+ arguments[0][:values_for].each { |key, value|
902
+ data.gsub!(/(( *|^)"?#{key.to_s()}"? *: *")(.*)(" *, *$)/, '\1' + value + '\4') # "key":"value", or key:"value",
903
+ data.gsub!(/(( *|^)"?#{key.to_s()}"? *: *")(.*)(" *$)/, '\1' + value + '\4') # "key":"value" or key:"value"
904
+ data.gsub!(/(( *|^)"?#{key.to_s()}"? *: *[^"])([^"].*)([^"] *, *$)/, '\1' + value + '\4') # "key":456, or key:456,
905
+ data.gsub!(/(( *|^)"?#{key.to_s()}"? *: *[^"])([^"].*)([^"] * *$)/, '\1' + value + '\4') # "key":456 or key:456
906
+ }
907
+ end
908
+ elsif data.kind_of?(Hash)
909
+ data_n = Hash.new()
910
+ data.each { |key, value|
911
+ data_n[key.to_s()] = value
912
+ }
913
+ if arguments[0].include?(:values_for)
914
+ #req[:values_for][:loginName] or req[:values_for]["loginName"]
915
+ new_values_hash = Hash.new()
916
+ arguments[0][:values_for].each { |kv, vv|
917
+ if data_n.keys.include?(kv.to_s())
918
+ new_values_hash[kv.to_s()] = vv
919
+ end
920
+ }
921
+ data_n.merge!(new_values_hash)
922
+ end
923
+ data = data_n.to_json()
924
+ elsif data.kind_of?(Array)
925
+ data_arr = Array.new()
926
+ data.each_with_index { |row, indx|
927
+ unless row.kind_of?(Hash)
928
+ @logger.fatal("Wrong format on request application/json, be sure is a Hash, Array of Hashes or JSON string")
929
+ return :error, :error, :error
930
+ end
931
+ data_n = Hash.new()
932
+ row.each { |key, value|
933
+ data_n[key.to_s()] = value
934
+ }
935
+ if arguments[0].include?(:values_for)
936
+ #req[:values_for][:loginName] or req[:values_for]["loginName"]
937
+ new_values_hash = Hash.new()
938
+ if arguments[0][:values_for].kind_of?(Hash) #values[:mykey][3]
939
+ arguments[0][:values_for].each { |kv, vv|
940
+ if data_n.keys.include?(kv.to_s()) and !vv[indx].nil?
941
+ new_values_hash[kv.to_s()] = vv[indx]
942
+ end
943
+ }
944
+ elsif arguments[0][:values_for].kind_of?(Array) #values[5][:mykey]
945
+ if !arguments[0][:values_for][indx].nil?
946
+ arguments[0][:values_for][indx].each { |kv, vv|
947
+ if data_n.keys.include?(kv.to_s())
948
+ new_values_hash[kv.to_s()] = vv
949
+ end
950
+ }
951
+ end
952
+ else
953
+ @logger.fatal("Wrong format on request application/json when supplying values, the data is an array of Hashes but the values supplied are not")
954
+ return :error, :error, :error
955
+ end
956
+ data_n.merge!(new_values_hash)
957
+ end
958
+ data_arr.push(data_n)
959
+ }
960
+ data = data_arr.to_json()
961
+ else
962
+ @logger.fatal("Wrong format on request application/json, be sure is a Hash, Array of Hashes or JSON string")
963
+ return :error, :error, :error
964
+ end
965
+ elsif content_type_included and arguments[0].include?(:values_for)
966
+ if arguments[0][:values_for].kind_of?(Hash) and arguments[0][:values_for].keys.size > 0
967
+ if !headers_t.nil? and headers_t.kind_of?(Hash) and headers_t["Content-Type"] != "application/x-www-form-urlencoded" and headers_t["content-type"] != "application/x-www-form-urlencoded"
968
+ @logger.warn(":values_for key given without a valid content-type or data for request. No values modified on the request")
969
+ end
970
+ end
971
+ end
972
+ elsif arguments.size == 1 and arguments[0].kind_of?(String)
973
+ #path=arguments[0].to_s()
974
+ data = ""
975
+ else
976
+ @logger.fatal("Invalid number of arguments or wrong arguments in #{method_s}")
977
+ return :error, :error, :error
978
+ end
979
+ if headers_t.keys.include?("Content-Type") and !headers_t["Content-Type"]["multipart/form-data"].nil? and headers_t["Content-Type"] != ["multipart/form-data"] #only for the case raw multipart request
980
+ encoding = "UTF-8"
981
+ data_s = ""
982
+ else
983
+ encoding = data.to_s().scan(/encoding='(.*)'/i).join
984
+ if encoding.to_s() == ""
985
+ encoding = data.to_s().scan(/charset='(.*)'/i).join
986
+ end
987
+ if encoding.to_s() == "" and headers_t.include?("Content-Type")
988
+ encoding = headers_t["Content-Type"].scan(/charset='?(.*)'?/i).join
989
+ if encoding.to_s() == ""
990
+ encoding = headers_t["Content-Type"].scan(/encoding='?(.*)'?/i).join
991
+ end
992
+ end
993
+
994
+ begin
995
+ data_s = JSON.pretty_generate(JSON.parse(data))
996
+ rescue
997
+ data_s = data
998
+ end
999
+ data_s = data_s.to_s().gsub("<", "&lt;")
1000
+ end
1001
+ if headers_t.keys.include?("Accept-Encoding")
1002
+ headers_t["Accept-Encoding"].gsub!("gzip", "") #removed so the response is in plain text
1003
+ end
1004
+
1005
+ headers_ts = ""
1006
+ headers_t.each { |key, val| headers_ts += key.to_s + ":" + val.to_s() + ", " }
1007
+ message = "#{method_s} REQUEST: \npath= " + path.to_s() + "\n"
1008
+ message += "headers= " + headers_ts.to_s() + "\n"
1009
+ message += "data= " + data_s.to_s() + "\n"
1010
+ message = @message_server + "\n" + message
1011
+ if path.to_s().scan(/^https?:\/\//).size > 0 and path.to_s().scan(/^https?:\/\/#{@host}/).size == 0
1012
+ # the path is for another server than the current
1013
+ else
1014
+ self.class.last_request = message
1015
+ @logger.info(message)
1016
+ end
1017
+
1018
+ if data.to_s() != "" and encoding.to_s().upcase != "UTF-8" and encoding != ""
1019
+ data = data.to_s().encode(encoding, "UTF-8")
1020
+ end
1021
+ return path, data, headers_t
1022
+ rescue Exception => stack
1023
+ @logger.fatal(stack)
1024
+ @logger.fatal("manage_request Error on method #{method_s} . path:#{path.to_s()}. data:#{data.to_s()}. headers:#{headers_t.to_s()}")
1025
+ return :error
1026
+ end
1027
+ end
1028
+
1029
+ ######################################################
1030
+ # private method to manage Response
1031
+ # input:
1032
+ # resp
1033
+ # data
1034
+ # output:
1035
+ # @response updated
1036
+ ######################################################
1037
+ def manage_response(resp, data)
1038
+ require "json"
1039
+ begin
1040
+ if @start_time.kind_of?(Time)
1041
+ @response[:time_elapsed_total] = Time.now - @start_time
1042
+ @start_time = nil
1043
+ else
1044
+ @response[:time_elapsed_total] = nil
1045
+ end
1046
+ if @start_time_net.kind_of?(Time)
1047
+ @response[:time_elapsed] = Time.now - @start_time_net
1048
+ @start_time_net = nil
1049
+ else
1050
+ @response[:time_elapsed] = nil
1051
+ end
1052
+ begin
1053
+ # this is to be able to access all keys as symbols
1054
+ new_resp = Hash.new()
1055
+ resp.each { |key, value|
1056
+ if key.kind_of?(String)
1057
+ new_resp[key.to_sym] = value
1058
+ end
1059
+ }
1060
+ new_resp.each { |key, value|
1061
+ resp[key] = value
1062
+ }
1063
+ rescue
1064
+ end
1065
+ #for mock_responses to be able to add outside of the header like content-type for example
1066
+ if resp.kind_of?(Hash) and !resp.has_key?(:header)
1067
+ resp[:header] = {}
1068
+ end
1069
+ if resp.kind_of?(Hash)
1070
+ resp.each { |k, v|
1071
+ if k != :code and k != :message and k != :data and k != :'set-cookie' and k != :header
1072
+ resp[:header][k] = v
1073
+ end
1074
+ }
1075
+ resp[:header].each { |k, v|
1076
+ resp.delete(k) if resp.has_key?(k)
1077
+ }
1078
+ end
1079
+
1080
+ method_s = caller[0].to_s().scan(/:in `(.*)'/).join
1081
+ if resp.header.kind_of?(Hash) and (resp.header["content-type"].to_s() == "application/x-deflate" or resp.header[:"content-type"].to_s() == "application/x-deflate")
1082
+ data = Zlib::Inflate.inflate(data)
1083
+ end
1084
+ encoding_response = ""
1085
+ if resp.header.kind_of?(Hash) and (resp.header["content-type"].to_s() != "" or resp.header[:"content-type"].to_s() != "")
1086
+ encoding_response = resp.header["content-type"].scan(/;charset=(.*)/i).join if resp.header.has_key?("content-type")
1087
+ encoding_response = resp.header[:"content-type"].scan(/;charset=(.*)/i).join if resp.header.has_key?(:"content-type")
1088
+ end
1089
+ if encoding_response.to_s() == ""
1090
+ encoding_response = "UTF-8"
1091
+ end
1092
+
1093
+ if encoding_response.to_s() != "" and encoding_response.to_s().upcase != "UTF-8"
1094
+ data.encode!("UTF-8", encoding_response.to_s())
1095
+ end
1096
+ if encoding_response != "" and encoding_response.to_s().upcase != "UTF-8"
1097
+ @response[:message] = resp.message.to_s().encode("UTF-8", encoding_response.to_s())
1098
+ #todo: response data in here for example is convert into string, verify if that is correct or needs to maintain the original data type (hash, array...)
1099
+ resp.each { |key, val| @response[key] = val.to_s().encode("UTF-8", encoding_response.to_s()) }
1100
+ else
1101
+ @response[:message] = resp.message
1102
+ resp.each { |key, val| @response[key] = val }
1103
+ end
1104
+ if !defined?(Net::HTTP::Post::Multipart) or (defined?(Net::HTTP::Post::Multipart) and !data.kind_of?(Net::HTTP::Post::Multipart))
1105
+ @response[:data] = data
1106
+ else
1107
+ @response[:data] = ""
1108
+ end
1109
+
1110
+ @response[:code] = resp.code
1111
+
1112
+ unless @response.nil?
1113
+ message = "\nRESPONSE: \n" + @response[:code].to_s() + ":" + @response[:message].to_s()
1114
+ if @debug
1115
+ self.class.last_response = message
1116
+ @response.each { |key, value|
1117
+ if value.to_s() != ""
1118
+ value_orig = value
1119
+ if key.kind_of?(Symbol)
1120
+ if key == :code or key == :data or key == :header or key == :message
1121
+ if key == :data
1122
+ begin
1123
+ JSON.parse(value_orig)
1124
+ data_s = JSON.pretty_generate(JSON.parse(value_orig))
1125
+ rescue
1126
+ data_s = value_orig
1127
+ end
1128
+ self.class.last_response += "\nresponse." + key.to_s() + " = '" + data_s.gsub("<", "&lt;") + "'\n"
1129
+ if value_orig != value
1130
+ message += "\nresponse." + key.to_s() + " = '" + value.gsub("<", "&lt;") + "'\n"
1131
+ else
1132
+ message += "\nresponse." + key.to_s() + " = '" + data_s.gsub("<", "&lt;") + "'\n"
1133
+ end
1134
+ else
1135
+ self.class.last_response += "\nresponse." + key.to_s() + " = '" + value.to_s().gsub("<", "&lt;") + "'"
1136
+ message += "\nresponse." + key.to_s() + " = '" + value.to_s().gsub("<", "&lt;") + "'"
1137
+ end
1138
+ else
1139
+ self.class.last_response += "\nresponse[:" + key.to_s() + "] = '" + value.to_s().gsub("<", "&lt;") + "'"
1140
+ message += "\nresponse[:" + key.to_s() + "] = '" + value.to_s().gsub("<", "&lt;") + "'"
1141
+ end
1142
+ elsif !@response.include?(key.to_sym)
1143
+ self.class.last_response += "\nresponse['" + key.to_s() + "'] = '" + value.to_s().gsub("<", "&lt;") + "'"
1144
+ message += "\nresponse['" + key.to_s() + "'] = '" + value.to_s().gsub("<", "&lt;") + "'"
1145
+ end
1146
+ end
1147
+ }
1148
+ end
1149
+ @logger.info message
1150
+ if @response.kind_of?(Hash)
1151
+ if @response.keys.include?(:requestid)
1152
+ @headers["requestId"] = @response[:requestid]
1153
+ self.class.request_id = @response[:requestid]
1154
+ @logger.info "requestId was found on the response header and it has been added to the headers for the next request"
1155
+ end
1156
+ end
1157
+ end
1158
+
1159
+ if resp[:'set-cookie'].to_s() != ""
1160
+ if resp.kind_of?(Hash) #mock_response
1161
+ cookies_to_set = resp[:'set-cookie'].to_s().split(", ")
1162
+ else #Net::Http
1163
+ cookies_to_set = resp.get_fields("set-cookie")
1164
+ end
1165
+ cookies_to_set.each { |cookie|
1166
+ cookie_pair = cookie.split("; ")[0].split("=")
1167
+ cookie_path = cookie.scan(/; path=([^;]+)/i).join
1168
+ @cookies[cookie_path] = Hash.new() unless @cookies.keys.include?(cookie_path)
1169
+ @cookies[cookie_path][cookie_pair[0]] = cookie_pair[1]
1170
+ }
1171
+
1172
+ @logger.info "set-cookie added to Cookie header as required"
1173
+
1174
+ if @headers.has_key?("X-CSRFToken")
1175
+ csrftoken = resp[:"set-cookie"].to_s().scan(/csrftoken=([\da-z]+);/).join
1176
+ if csrftoken.to_s() != ""
1177
+ @headers["X-CSRFToken"] = csrftoken
1178
+ @logger.info "X-CSRFToken exists on headers and has been overwritten"
1179
+ end
1180
+ else
1181
+ csrftoken = resp[:"set-cookie"].to_s().scan(/csrftoken=([\da-z]+);/).join
1182
+ if csrftoken.to_s() != ""
1183
+ @headers["X-CSRFToken"] = csrftoken
1184
+ @logger.info "X-CSRFToken added to header as required"
1185
+ end
1186
+ end
1187
+ end
1188
+ rescue Exception => stack
1189
+ @logger.fatal stack
1190
+ @logger.fatal "manage_response Error on method #{method_s} "
1191
+ end
1192
+ end
1193
+
1194
+ private :manage_request, :manage_response
1195
+ end