nice_http 0.9.2 → 0.9.4

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