nice_http 1.0.0 → 1.0.1

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