moesif_rack 1.4.19 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9648d28da08853893881cd32fef5fcf61d4f8d2c6a573d06ced10bb4e01bda3c
4
- data.tar.gz: cebdf8b64372dd77a80520e8cbec1da161f623a6435a8ced10a700aa86e57113
3
+ metadata.gz: fe86ff126bcaddeb96d24cc3216864727ba7be4f2e4ba7495b5fd6dda789369a
4
+ data.tar.gz: 2d1bc431a0a59e77a6f1eac898a78535870a424db164f381a52c61767da6d63d
5
5
  SHA512:
6
- metadata.gz: 35bb379b52dc6f4323d5dc98154c5ba741e438ec1cf98030f06775405c405e4a34871b9435a9a3f89d0b32e6545c2f6ec88083e59d2c4e97c271e765200e89bc
7
- data.tar.gz: 72422bb99d80d78e91af4034ff4dd31f7f94c8424a498819a6767ce066045209e4dc8c1e9784a88377cf100e79fad3cb0733989f0869b449dedf60e91b916f60
6
+ metadata.gz: 6ed3762486f9223b7562b36e38561f72a156a3be5ab836a0ad5b363d2034cfce912125b44e10b0eb9e330ce22b00cdc0bc8665ac59d90702742b5492dd061698
7
+ data.tar.gz: 376d83545ec2635c2980351f22fb277a99ac62e878385748d7c33e9767c40ca7731d2670f0c44f531f9350312066534eb593b6b729603dbeaec03ea3f70ac919
@@ -3,134 +3,97 @@ require 'json'
3
3
  require 'time'
4
4
  require 'zlib'
5
5
  require 'stringio'
6
- require_relative './moesif_helpers.rb'
7
- require_relative './regex_config_helper.rb'
6
+ require_relative './moesif_helpers'
7
+ require_relative './regex_config_helper'
8
8
 
9
9
  class AppConfig
10
+ attr_accessor :config, :recent_etag, :last_download_time
10
11
 
11
- def initialize debug
12
- @debug = debug
13
- @moesif_helpers = MoesifHelpers.new(debug)
14
- @regex_config_helper = RegexConfigHelper.new(debug)
15
- end
16
-
17
- def get_config(api_controller)
18
- # Get Application Config
19
- begin
20
- config_api_response = api_controller.get_app_config()
21
- @moesif_helpers.log_debug("new config downloaded")
22
- @moesif_helpers.log_debug(config_api_response.to_s)
23
- return config_api_response
24
- rescue MoesifApi::APIException => e
25
- if e.response_code.between?(401, 403)
26
- @moesif_helpers.log_debug 'Unauthorized access getting application configuration. Please check your Appplication Id.'
27
- end
28
- @moesif_helpers.log_debug 'Error getting application configuration, with status code:'
29
- @moesif_helpers.log_debug e.response_code
30
- rescue => e
31
- @moesif_helpers.log_debug e.to_s
32
- end
33
- rescue
34
- end
12
+ def initialize(debug)
13
+ @debug = debug
14
+ @moesif_helpers = MoesifHelpers.new(debug)
15
+ @regex_config_helper = RegexConfigHelper.new(debug)
16
+ end
35
17
 
36
- def parse_configuration(config_api_response)
37
- # Parse configuration object and return Etag, sample rate and last updated time
38
- begin
39
- # Rails return gzipped compressed response body, so decompressing it and getting JSON response body
40
- response_body = decompress_gzip_body(config_api_response)
41
- @moesif_helpers.log_debug(response_body.to_s)
18
+ def should_reload(etag_from_create_event)
19
+ if @last_download_time.nil?
20
+ return true
21
+ elsif Time.now.utc > (@last_download_time + 300)
22
+ return true
23
+ elsif !etag_from_create_event.nil? && !@recent_etag.nil?
24
+ @moesif_helpers.log_debug('comparing if etag from event and recent etag match ' + etag_from_create_event + ' ' + @recent_etag)
42
25
 
43
- # Check if response body is not nil
44
- if !response_body.nil? then
45
- # Return Etag, sample rate and last updated time
46
- return response_body, config_api_response.headers[:x_moesif_config_etag], Time.now.utc
47
- else
48
- @moesif_helpers.log_debug 'Response body is nil, assuming default behavior'
49
- # Response body is nil, so assuming default behavior
50
- return nil, nil, Time.now.utc
51
- end
52
- rescue => exception
53
- @moesif_helpers.log_debug 'Error while parsing the configuration object, assuming default behavior'
54
- @moesif_helpers.log_debug exception.to_s
55
- # Assuming default behavior
56
- return nil, nil, Time.now.utc
57
- end
26
+ return etag_from_create_event != @recent_etag
58
27
  end
28
+ @moesif_helpers.log_debug('should skip reload config')
29
+ return false;
30
+ end
59
31
 
60
- def get_sampling_percentage(event_model, config_api_response, user_id, company_id)
61
- # Get sampling percentage
62
- begin
63
- # Check if response body is not nil
64
- if !config_api_response.nil? then
65
- @moesif_helpers.log_debug("Getting sample rate for user #{user_id} company #{company_id}")
66
- @moesif_helpers.log_debug(config_api_response.to_s)
32
+ def get_config(api_controller)
33
+ # Get Application Config
34
+ @moesif_helpers.log_debug('try to loading etag')
35
+ config_json, _context = api_controller.get_app_config
36
+ @config = config_json
37
+ @recent_etag = _context.response.headers[:x_moesif_config_etag]
38
+ @last_download_time = Time.now.utc
39
+ @moesif_helpers.log_debug('new config downloaded')
40
+ @moesif_helpers.log_debug(config_json.to_s)
41
+ rescue MoesifApi::APIException => e
42
+ if e.response_code.between?(401, 403)
43
+ @moesif_helpers.log_debug 'Unauthorized access getting application configuration. Please check your Appplication Id.'
44
+ end
45
+ @moesif_helpers.log_debug 'Error getting application configuration, with status code:'
46
+ @moesif_helpers.log_debug e.response_code
47
+ rescue StandardError => e
48
+ @moesif_helpers.log_debug e.to_s
49
+ end
67
50
 
68
- # Get Regex Sampling rate
69
- regex_config = config_api_response.fetch('regex_config', nil)
51
+ def get_sampling_percentage(event_model, user_id, company_id)
52
+ # if we do not have config for some reason we return 100
53
+ if !@config.nil?
54
+ # Get sampling percentage
55
+ @moesif_helpers.log_debug("Getting sample rate for user #{user_id} company #{company_id}")
56
+ @moesif_helpers.log_debug(@config.to_s)
70
57
 
71
- if !regex_config.nil? and !event_model.nil?
72
- config_mapping = @regex_config_helper.prepare_config_mapping(event_model)
73
- regex_sample_rate = @regex_config_helper.fetch_sample_rate_on_regex_match(regex_config, config_mapping)
74
- if !regex_sample_rate.nil?
75
- return regex_sample_rate
76
- end
77
- end
58
+ # Get Regex Sampling rate
59
+ regex_config = @config.fetch('regex_config', nil)
78
60
 
79
- # Get user sample rate object
80
- user_sample_rate = config_api_response.fetch('user_sample_rate', nil)
61
+ if !regex_config.nil? and !event_model.nil?
62
+ config_mapping = @regex_config_helper.prepare_config_mapping(event_model)
63
+ regex_sample_rate = @regex_config_helper.fetch_sample_rate_on_regex_match(regex_config,
64
+ config_mapping)
65
+ return regex_sample_rate unless regex_sample_rate.nil?
66
+ end
81
67
 
82
- # Get company sample rate object
83
- company_sample_rate = config_api_response.fetch('company_sample_rate', nil)
68
+ # Get user sample rate object
69
+ user_sample_rate = @config.fetch('user_sample_rate', nil)
84
70
 
85
- # Get sample rate for the user if exist
86
- if !user_id.nil? && !user_sample_rate.nil? && user_sample_rate.key?(user_id)
87
- return user_sample_rate.fetch(user_id)
88
- end
71
+ # Get company sample rate object
72
+ company_sample_rate = @config.fetch('company_sample_rate', nil)
89
73
 
90
- # Get sample rate for the company if exist
91
- if !company_id.nil? && !company_sample_rate.nil? && company_sample_rate.key?(company_id)
92
- return company_sample_rate.fetch(company_id)
93
- end
74
+ # Get sample rate for the user if exist
75
+ if !user_id.nil? && !user_sample_rate.nil? && user_sample_rate.key?(user_id)
76
+ return user_sample_rate.fetch(user_id)
77
+ end
94
78
 
95
- # Return sample rate
96
- return config_api_response.fetch('sample_rate', 100)
97
- else
98
- @moesif_helpers.log_debug 'Assuming default behavior as response body is nil - '
99
- return 100
100
- end
101
- rescue => exception
102
- @moesif_helpers.log_debug 'Error while geting sampling percentage, assuming default behavior'
103
- @moesif_helpers.log_debug exception.to_s
104
- return 100
105
- end
106
- end
79
+ # Get sample rate for the company if exist
80
+ if !company_id.nil? && !company_sample_rate.nil? && company_sample_rate.key?(company_id)
81
+ return company_sample_rate.fetch(company_id)
82
+ end
107
83
 
108
- def decompress_gzip_body(config_api_response)
109
- # Decompress gzip response body
110
- begin
111
- # Check if the content-encoding header exist and is of type zip
112
- if config_api_response.headers.key?(:content_encoding) && config_api_response.headers[:content_encoding].eql?( 'gzip' ) then
113
-
114
- # Create a GZipReader object to read data
115
- gzip_reader = Zlib::GzipReader.new(StringIO.new(config_api_response.raw_body.to_s))
116
-
117
- # Read the body
118
- uncompressed_string = gzip_reader.read
119
-
120
- # Return the parsed body
121
- return JSON.parse( uncompressed_string )
122
- else
123
- @moesif_helpers.log_debug 'Content Encoding is of type other than gzip, returning nil'
124
- return nil
125
- end
126
- rescue => exception
127
- @moesif_helpers.log_debug 'Error while decompressing the response body'
128
- @moesif_helpers.log_debug exception.to_s
129
- return nil
130
- end
84
+ # Return overall sample rate
85
+ @config.fetch('sample_rate', 100)
86
+ else
87
+ @moesif_helpers.log_debug 'Assuming default behavior as response body is nil - '
88
+ 100
131
89
  end
90
+ rescue StandardError => e
91
+ @moesif_helpers.log_debug 'Error while geting sampling percentage, assuming default behavior'
92
+ @moesif_helpers.log_debug e.to_s
93
+ 100
94
+ end
132
95
 
133
- def calculate_weight(sample_rate)
134
- return sample_rate == 0 ? 1 : (100 / sample_rate).floor
135
- end
96
+ def calculate_weight(sample_rate)
97
+ sample_rate == 0 ? 1 : (100 / sample_rate).floor
98
+ end
136
99
  end
@@ -1,119 +1,78 @@
1
-
2
1
  def is_ip?(value)
3
- ipv4 = /^(?:(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/
4
- ipv6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
5
- # We use !! to convert the return value to a boolean
6
- !!(value =~ ipv4 or value=~ ipv6)
2
+ ipv4 = /^(?:(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])\.){3}(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])$/
3
+ ipv6 = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
4
+ # We use !! to convert the return value to a boolean
5
+ !!(value =~ ipv4 or value =~ ipv6)
7
6
  end
8
7
 
9
8
  def get_client_ip_from_x_forwarded_for(value)
10
- begin
11
- value = value.encode('utf-8')
12
-
13
- if value.to_s.empty?
14
- return nil
15
- end
16
-
17
- if !value.instance_of?(String)
18
- puts ("Expected a string, got - " + value.class.to_s)
19
- else
20
- # x-forwarded-for may return multiple IP addresses in the format:
21
- # "client IP, proxy 1 IP, proxy 2 IP"
22
- # Therefore, the right-most IP address is the IP address of the most recent proxy
23
- # and the left-most IP address is the IP address of the originating client.
24
- # source: http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html
25
- # Azure Web App's also adds a port for some reason, so we'll only use the first part (the IP)
26
- forwardedIps = []
27
-
28
- value.gsub(/\s+/, "").split(',').each do |e|
29
- if e.include?(':')
30
- splitted = e.split(':')
31
- if splitted.length == 2
32
- forwardedIps << splitted.first
33
- end
34
- end
35
- forwardedIps << e
36
- end
37
-
38
- # Sometimes IP addresses in this header can be 'unknown' (http://stackoverflow.com/a/11285650).
39
- # Therefore taking the left-most IP address that is not unknown
40
- # A Squid configuration directive can also set the value to "unknown" (http://www.squid-cache.org/Doc/config/forwarded_for/)
41
- return forwardedIps.find {|e| is_ip?(e) }
42
- end
43
- rescue
44
- return value.encode('utf-8')
9
+ value = value.encode('utf-8')
10
+
11
+ return nil if value.to_s.empty?
12
+
13
+ if !value.instance_of?(String)
14
+ puts('Expected a string, got - ' + value.class.to_s)
15
+ else
16
+ # x-forwarded-for may return multiple IP addresses in the format:
17
+ # "client IP, proxy 1 IP, proxy 2 IP"
18
+ # Therefore, the right-most IP address is the IP address of the most recent proxy
19
+ # and the left-most IP address is the IP address of the originating client.
20
+ # source: http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html
21
+ # Azure Web App's also adds a port for some reason, so we'll only use the first part (the IP)
22
+ forwardedIps = []
23
+
24
+ value.gsub(/\s+/, '').split(',').each do |e|
25
+ if e.include?(':')
26
+ splitted = e.split(':')
27
+ forwardedIps << splitted.first if splitted.length == 2
28
+ end
29
+ forwardedIps << e
45
30
  end
31
+
32
+ # Sometimes IP addresses in this header can be 'unknown' (http://stackoverflow.com/a/11285650).
33
+ # Therefore taking the left-most IP address that is not unknown
34
+ # A Squid configuration directive can also set the value to "unknown" (http://www.squid-cache.org/Doc/config/forwarded_for/)
35
+ forwardedIps.find { |e| is_ip?(e) }
36
+ end
37
+ rescue StandardError
38
+ value.encode('utf-8')
46
39
  end
47
40
 
48
41
  def get_client_address(env)
49
- begin
50
- # Standard headers used by Amazon EC2, Heroku, and others.
51
- if env.key?('HTTP_X_CLIENT_IP')
52
- if is_ip?(env['HTTP_X_CLIENT_IP'])
53
- return env['HTTP_X_CLIENT_IP']
54
- end
55
- end
42
+ # Standard headers used by Amazon EC2, Heroku, and others.
43
+ return env['HTTP_X_CLIENT_IP'] if env.key?('HTTP_X_CLIENT_IP') && is_ip?(env['HTTP_X_CLIENT_IP'])
56
44
 
57
- # Load-balancers (AWS ELB) or proxies.
58
- if env.key?('HTTP_X_FORWARDED_FOR')
59
- xForwardedFor = get_client_ip_from_x_forwarded_for(env['HTTP_X_FORWARDED_FOR'])
60
- if is_ip?(xForwardedFor)
61
- return xForwardedFor
62
- end
63
- end
45
+ # Load-balancers (AWS ELB) or proxies.
46
+ if env.key?('HTTP_X_FORWARDED_FOR')
47
+ xForwardedFor = get_client_ip_from_x_forwarded_for(env['HTTP_X_FORWARDED_FOR'])
48
+ return xForwardedFor if is_ip?(xForwardedFor)
49
+ end
64
50
 
65
- # Cloudflare.
66
- # @see https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-
67
- # CF-Connecting-IP - applied to every request to the origin.
68
- if env.key?('HTTP_CF_CONNECTING_IP')
69
- if is_ip?(env['HTTP_CF_CONNECTING_IP'])
70
- return env['HTTP_CF_CONNECTING_IP']
71
- end
72
- end
51
+ # Cloudflare.
52
+ # @see https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-
53
+ # CF-Connecting-IP - applied to every request to the origin.
54
+ return env['HTTP_CF_CONNECTING_IP'] if env.key?('HTTP_CF_CONNECTING_IP') && is_ip?(env['HTTP_CF_CONNECTING_IP'])
73
55
 
74
- # Akamai and Cloudflare: True-Client-IP.
75
- if env.key?('HTTP_TRUE_CLIENT_IP')
76
- if is_ip?(env['HTTP_TRUE_CLIENT_IP'])
77
- return env['HTTP_TRUE_CLIENT_IP']
78
- end
79
- end
56
+ # Akamai and Cloudflare: True-Client-IP.
57
+ return env['HTTP_TRUE_CLIENT_IP'] if env.key?('HTTP_TRUE_CLIENT_IP') && is_ip?(env['HTTP_TRUE_CLIENT_IP'])
80
58
 
81
- # Default nginx proxy/fcgi; alternative to x-forwarded-for, used by some proxies.
82
- if env.key?('HTTP_X_REAL_IP')
83
- if is_ip?(env['HTTP_X_REAL_IP'])
84
- return env['HTTP_X_REAL_IP']
85
- end
86
- end
59
+ # Default nginx proxy/fcgi; alternative to x-forwarded-for, used by some proxies.
60
+ return env['HTTP_X_REAL_IP'] if env.key?('HTTP_X_REAL_IP') && is_ip?(env['HTTP_X_REAL_IP'])
87
61
 
88
- # (Rackspace LB and Riverbed's Stingray)
89
- # http://www.rackspace.com/knowledge_center/article/controlling-access-to-linux-cloud-sites-based-on-the-client-ip-address
90
- # https://splash.riverbed.com/docs/DOC-1926
91
- if env.key?('HTTP_X_CLUSTER_CLIENT_IP')
92
- if is_ip?(env['HTTP_X_CLUSTER_CLIENT_IP'])
93
- return env['HTTP_X_CLUSTER_CLIENT_IP']
94
- end
95
- end
62
+ # (Rackspace LB and Riverbed's Stingray)
63
+ # http://www.rackspace.com/knowledge_center/article/controlling-access-to-linux-cloud-sites-based-on-the-client-ip-address
64
+ # https://splash.riverbed.com/docs/DOC-1926
65
+ if env.key?('HTTP_X_CLUSTER_CLIENT_IP') && is_ip?(env['HTTP_X_CLUSTER_CLIENT_IP'])
66
+ return env['HTTP_X_CLUSTER_CLIENT_IP']
67
+ end
96
68
 
97
- if env.key?('HTTP_X_FORWARDED')
98
- if is_ip?(env['HTTP_X_FORWARDED'])
99
- return env['HTTP_X_FORWARDED']
100
- end
101
- end
69
+ return env['HTTP_X_FORWARDED'] if env.key?('HTTP_X_FORWARDED') && is_ip?(env['HTTP_X_FORWARDED'])
102
70
 
103
- if env.key?('HTTP_FORWARDED_FOR')
104
- if is_ip?(env['HTTP_FORWARDED_FOR'])
105
- return env['HTTP_FORWARDED_FOR']
106
- end
107
- end
71
+ return env['HTTP_FORWARDED_FOR'] if env.key?('HTTP_FORWARDED_FOR') && is_ip?(env['HTTP_FORWARDED_FOR'])
108
72
 
109
- if env.key?('HTTP_FORWARDED')
110
- if is_ip?(env['HTTP_FORWARDED'])
111
- return env['HTTP_FORWARDED']
112
- end
113
- end
73
+ return env['HTTP_FORWARDED'] if env.key?('HTTP_FORWARDED') && is_ip?(env['HTTP_FORWARDED'])
114
74
 
115
- return env['REMOTE_ADDR']
116
- rescue
117
- return env['REMOTE_ADDR']
118
- end
119
- end
75
+ env['REMOTE_ADDR']
76
+ rescue StandardError
77
+ env['REMOTE_ADDR']
78
+ end