moesif_rack 1.4.19 → 2.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.
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