nice_http 0.9.2 → 0.9.4

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