nice_http 0.9.1 → 0.9.2

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 +1090 -1083
  4. metadata +3 -2
data/lib/nice_http.rb CHANGED
@@ -1,1083 +1,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
-
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
+