geo_redirect 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cc53d6e770a29fb9a25ad601803bc220e9de5595
4
+ data.tar.gz: ce7e9473fb1a032807256e361c72811ef06856c8
5
+ SHA512:
6
+ metadata.gz: 4b82b53e72d1ac2f59562433e6f4f30033115692484049253991507aa3871c4030751f382020976fda8b945425c9df93d7957a58534fa1f065b5e7f13b9b998e
7
+ data.tar.gz: 467773cacba033e14b1f0ee811fc420095e9f650d7239db8caf10a6bc0ebf4948fb967a5fde8e6096b8d8223624d08d4c732047e2194efa5198ab85dbf8c5326
data/.rubocop.yml ADDED
@@ -0,0 +1,16 @@
1
+ require: rubocop-rspec
2
+
3
+ Style/Documentation:
4
+ Enabled: false
5
+
6
+ Metrics/MethodLength:
7
+ Max: 15
8
+
9
+ Metrics/ClassLength:
10
+ Max: 154
11
+
12
+ Style/RescueModifier:
13
+ Enabled: false
14
+
15
+ Style/RegexpLiteral:
16
+ Enabled: false
data/README.md CHANGED
@@ -12,9 +12,15 @@ to redirect users to:
12
12
  * [biz.waze.com](http://biz.waze.com) for US and Canada incoming traffic.
13
13
  * [biz-world.waze.com](http://biz-world.waze.com/) for any other sources.
14
14
 
15
- The server stores a session variable with the server it decided on, for future traffic from the same client.
15
+ The server stores a session variable with the server it decided on, for future
16
+ traffic from the same client.
16
17
 
17
- In addition, you can override these redirects by adding `?redirect=1` to any URL, and by that forcing the server to host from the current domain (and saving that domain to the user's session variable).
18
+ In addition, you can override these redirects by adding `?redirect=1` to any
19
+ URL, and by that forcing the server to host from the current domain (and saving
20
+ that domain to the user's session variable).
21
+
22
+ To skip geo-redirection completely, pass a `?skip_geo=true` argument (this would
23
+ avoid saving any session value and/or HTTP redirects).
18
24
 
19
25
  ## Installation
20
26
 
@@ -45,36 +51,44 @@ This should be a YML file representing your redirection rules.
45
51
 
46
52
  Here's a template that we use for the setup described above:
47
53
 
48
- ```
49
- :us:
50
- :host: 'biz.waze.com'
51
- :countries: ['US', 'CA']
54
+ :us:
55
+ :host: 'biz.waze.com'
56
+ :countries: ['US', 'CA']
52
57
 
53
- :il:
54
- :host: 'biz.waze.co.il'
55
- :countries: ['IL']
58
+ :il:
59
+ :host: 'biz.waze.co.il'
60
+ :countries: ['IL']
56
61
 
57
- :world: &default
58
- :host: 'biz-world.waze.com'
62
+ :world: &default
63
+ :host: 'biz-world.waze.com'
59
64
 
60
- :default: *default
61
- ```
65
+ :default: *default
62
66
 
63
67
  Note that:
64
68
 
65
69
  1. Every main item is a location, and must have a `host` configured.
66
- 2. A location can have a `countries` array. This will cause a redirect to this location for users from that country code. For available country codes, see [ISO 3166 Country Codes list](http://www.maxmind.com/en/iso3166) from MaxMind (the Geo IP provider `GeoRedirect` uses).
67
- 3. There must be a `default` location that would be used in case the client can't be geo-located.
70
+ 2. A location can have a `countries` array. This will cause a redirect to this
71
+ location for users from that country code. For available country codes, see
72
+ [ISO 3166 Country Codes list](http://www.maxmind.com/en/iso3166) from MaxMind
73
+ (the Geo IP provider `GeoRedirect` uses).
74
+ 3. There must be a `default` location that would be used in case the client
75
+ can't be geo-located.
68
76
 
69
77
  ### 2. GeoIP Countries database
70
78
 
71
- `GeoRedirect` uses the [`geoip`](http://geoip.rubyforge.org/) gem for its geo-location functionality. In particular, it requires the `GeoLite country` free database from [MaxMind](http://www.maxmind.com/).
79
+ `GeoRedirect` uses the [`geoip`](http://geoip.rubyforge.org/) gem for its
80
+ geo-location functionality. In particular, it requires the `GeoLite country`
81
+ free database from [MaxMind](http://www.maxmind.com/).
72
82
 
73
- You can download the database file [directly from MaxMind](http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz) and unzip it into `db/` in your project, **or** you could use the following `rake` task designed just for that:
83
+ You can download the database file [directly from
84
+ MaxMind](http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz)
85
+ and unzip it into `db/` in your project, **or** you could use the following
86
+ `rake` task designed just for that:
74
87
 
75
88
  $ rake geo_redirect:fetch_db
76
89
 
77
- It'd be a good idea to use this task on your (Capistrano or whatever) deployment scripts.
90
+ It'd be a good idea to use this task on your (Capistrano or whatever) deployment
91
+ scripts.
78
92
 
79
93
  ### Custom paths
80
94
 
@@ -83,33 +97,41 @@ The default paths for these files are:
83
97
  1. `config/georedirect.yml`
84
98
  2. `db/GeoIP.dat`
85
99
 
86
- If that doesn't suit you, you can customize these when adding `GeoRedirect` to your project:
100
+ If that doesn't suit you, you can customize these when adding `GeoRedirect` to
101
+ your project:
87
102
 
88
103
  Rails.application.middleware.use GeoRedirect::Middleware, {
89
- :db => 'db/geo_database.dat',
90
- :config => 'geo_cfg.yml'
104
+ db: 'db/geo_database.dat',
105
+ config: 'geo_cfg.yml'
91
106
  }
92
107
 
93
108
  ### Debugging
94
109
 
95
- You can add a `logfile` path string when adding the middleware if you want it to log some of its decision process into the file.
110
+ You can add a `logfile` path string when adding the middleware if you want it to
111
+ log some of its decision process into the file.
96
112
  This is useful when working on your configuration YAML.
97
113
 
98
- Rails.application.middleware.use GeoRedirect::Middleware, :logfile => 'log/geo_redirect.log'
114
+ Rails.application.middleware.use GeoRedirect::Middleware, logfile: 'log/geo_redirect.log'
99
115
 
100
116
  `GeoRedirect`'s log messages will always be prefixed with `[GeoRedirect]`.
101
117
 
102
118
  ### Accessing discovered country
103
119
 
104
- The country code discovered for the current user is available for your convenience, under `session['geo_redirect.country']`.
120
+ The country code discovered for the current user is available for your
121
+ convenience, under `session['geo_redirect.country']`.
105
122
  You can use it to make content decisions, or whatever.
106
123
 
107
124
  ## Known Issues
108
125
 
109
126
  A couple issues I know about but haven't had the time to fix:
110
127
 
111
- 1. Cross-domain session var is required. In particular, if your stubborn user goes to more than 1 server with `?redirect=1`, all of these servers will never redirect them again (until the session is expired).
112
- 2. When a client accesses your site from an unknown hostname (one that was not configured in the `yml` file) with `?redirect=1`, they will stay in that hostname for the current session, but in the future would be redirected to the configured default hostname (because it was saved on their session var).
128
+ 1. Cross-domain session var is required. In particular, if your stubborn user
129
+ goes to more than 1 server with `?redirect=1`, all of these servers will
130
+ never redirect them again (until the session is expired).
131
+ 2. When a client accesses your site from an unknown hostname (one that was not
132
+ configured in the `yml` file) with `?redirect=1`, they will stay in that
133
+ hostname for the current session, but in the future would be redirected to
134
+ the configured default hostname (because it was saved on their session var).
113
135
 
114
136
 
115
137
  ## Contributing
data/Rakefile CHANGED
@@ -1,6 +1,6 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => [:spec]
6
+ task default: [:spec]
data/geo_redirect.gemspec CHANGED
@@ -4,25 +4,24 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'geo_redirect/version'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
- gem.name = "geo_redirect"
7
+ gem.name = 'geo_redirect'
8
8
  gem.version = GeoRedirect::VERSION
9
- gem.authors = ["Sagie Maoz"]
10
- gem.email = ["sagie@waze.com"]
11
- gem.description = %q{Geo-location based redirector}
12
- gem.summary = %q{Rack middleware to redirect clients to hostnames based on geo-location}
13
- gem.homepage = ""
9
+ gem.authors = ['Sagie Maoz']
10
+ gem.email = ['sagie@waze.com']
11
+ gem.description = 'Geo-location based redirector'
12
+ gem.summary = 'Rack middleware to redirect clients to hostnames based on geo-location'
13
+ gem.homepage = ''
14
14
 
15
- gem.add_dependency "rake"
16
- gem.add_dependency "geoip"
15
+ gem.add_dependency 'rake'
16
+ gem.add_dependency 'geoip'
17
17
 
18
- gem.add_development_dependency "rspec", "~> 2.13.0"
19
- gem.add_development_dependency "rack", "~> 1.5.2"
20
- gem.add_development_dependency "rack-test", "~> 0.6.2"
21
- gem.add_development_dependency "debugger", "~> 1.5.0"
22
- gem.add_development_dependency "simplecov", "~> 0.7.1"
18
+ gem.add_development_dependency 'rspec', '~> 3.1.0'
19
+ gem.add_development_dependency 'rack', '~> 1.6.0'
20
+ gem.add_development_dependency 'rack-test', '~> 0.6.3'
21
+ gem.add_development_dependency 'simplecov', '~> 0.9.1'
23
22
 
24
- gem.files = `git ls-files`.split($/)
25
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
23
+ gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
24
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
26
25
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
27
- gem.require_paths = ["lib"]
26
+ gem.require_paths = ['lib']
28
27
  end
data/lib/geo_redirect.rb CHANGED
@@ -6,8 +6,5 @@ module GeoRedirect
6
6
  DEFAULT_CONFIG_PATH = 'config/geo_redirect.yml'
7
7
 
8
8
  # Load rake tasks
9
- if defined? Rails
10
- require 'geo_redirect/railtie'
11
- end
12
-
9
+ require 'geo_redirect/railtie' if defined? Rails
13
10
  end
@@ -16,13 +16,16 @@ module GeoRedirect
16
16
  @db = init_db(options[:db])
17
17
  @config = init_config(options[:config])
18
18
 
19
- self.log "Initialized middleware"
19
+ log 'Initialized middleware'
20
20
  end
21
21
 
22
22
  def call(env)
23
23
  @request = Rack::Request.new(env)
24
24
 
25
- if force_redirect?
25
+ if skip_redirect?
26
+ @app.call(env)
27
+
28
+ elsif force_redirect?
26
29
  handle_force
27
30
 
28
31
  elsif session_exists?
@@ -36,7 +39,7 @@ module GeoRedirect
36
39
  def session_exists?
37
40
  host = @request.session['geo_redirect']
38
41
  if host && @config[host].nil? # Invalid var, remove it
39
- self.log "Invalid session var, forgetting"
42
+ log 'Invalid session var, forgetting'
40
43
  forget_host(host)
41
44
  host = nil
42
45
  end
@@ -46,7 +49,7 @@ module GeoRedirect
46
49
 
47
50
  def handle_session
48
51
  host = @request.session['geo_redirect']
49
- self.log "Handling session var: #{host}"
52
+ log "Handling session var: #{host}"
50
53
  redirect_request(host)
51
54
  end
52
55
 
@@ -55,10 +58,15 @@ module GeoRedirect
55
58
  Rack::Utils.parse_query(url.query).key? 'redirect'
56
59
  end
57
60
 
61
+ def skip_redirect?
62
+ url = URI.parse(@request.url)
63
+ Rack::Utils.parse_query(url.query).key? 'skip_geo'
64
+ end
65
+
58
66
  def handle_force
59
67
  url = URI.parse(@request.url)
60
68
  host = host_by_hostname(url.host)
61
- self.log "Handling force flag: #{host}"
69
+ log "Handling force flag: #{host}"
62
70
  remember_host(host)
63
71
  redirect_request(url.host, true)
64
72
  end
@@ -66,28 +74,28 @@ module GeoRedirect
66
74
  def handle_geoip
67
75
  country = country_from_request rescue nil
68
76
  @request.session['geo_redirect.country'] = country
69
- self.log "GeoIP match: country code #{country}"
77
+ log "GeoIP match: country code #{country}"
70
78
 
71
- unless country.nil?
79
+ if country.nil?
80
+ @app.call(@request.env)
81
+ else
72
82
  host = host_by_country(country) # desired host
73
- self.log "GeoIP host match: #{host}"
83
+ log "GeoIP host match: #{host}"
74
84
  remember_host(host)
75
85
 
76
86
  redirect_request(host)
77
- else
78
- @app.call(@request.env)
79
87
  end
80
88
  end
81
89
 
82
- def redirect_request(host=nil, same_host=false)
90
+ def redirect_request(host = nil, same_host = false)
83
91
  hostname = hostname_by_host(host)
84
92
 
85
93
  if should_redirect?(hostname, same_host)
86
94
  url = redirect_url(hostname)
87
95
 
88
- self.log "Redirecting to #{url}"
96
+ log "Redirecting to #{url}"
89
97
  [301,
90
- {'Location' => url.to_s, 'Content-Type' => 'text/plain'},
98
+ { 'Location' => url.to_s, 'Content-Type' => 'text/plain' },
91
99
  ['Moved Permanently\n']]
92
100
  else
93
101
  @app.call(@request.env)
@@ -95,12 +103,12 @@ module GeoRedirect
95
103
  end
96
104
 
97
105
  def host_by_country(country)
98
- hosts = @config.select { |k, v| Array(v[:countries]).include?(country) }
106
+ hosts = @config.select { |_k, v| Array(v[:countries]).include?(country) }
99
107
  hosts.keys.first || :default
100
108
  end
101
109
 
102
110
  def host_by_hostname(hostname)
103
- hosts = @config.select { |k, v| v[:host] == hostname }
111
+ hosts = @config.select { |_k, v| v[:host] == hostname }
104
112
  hosts.keys.first || :default
105
113
  end
106
114
 
@@ -109,17 +117,18 @@ module GeoRedirect
109
117
  end
110
118
 
111
119
  def remember_host(host)
112
- self.log "Remembering: #{host}"
120
+ log "Remembering: #{host}"
113
121
  @request.session['geo_redirect'] = host
114
122
  end
115
123
 
116
124
  def forget_host(host)
117
- self.log "Forgetting: #{host}"
125
+ log "Forgetting: #{host}"
118
126
  remember_host(nil)
119
127
  end
120
128
 
121
129
  protected
122
- def log(message, level=:debug)
130
+
131
+ def log(message, level = :debug)
123
132
  @logger.send(level, "[GeoRedirect] #{message}") unless @logger.nil?
124
133
  end
125
134
 
@@ -134,35 +143,38 @@ module GeoRedirect
134
143
  rescue Errno::EINVAL, Errno::ENOENT
135
144
  message = <<-ERROR
136
145
  Could not load GeoIP database file.
137
- Please make sure you have a valid one and add its name to the GeoRedirect middleware.
138
- Alternatively, use `rake georedirect:fetch_db` to fetch it to the default location (under db/).
146
+ Please make sure you have a valid one and add its name to
147
+ the GeoRedirect middleware.
148
+ Alternatively, use `rake georedirect:fetch_db` to fetch it
149
+ to the default location (under db/).
139
150
  ERROR
140
- self.log(message, :error)
151
+ log(message, :error)
141
152
  end
142
153
 
143
154
  def init_config(path)
144
- YAML.load_file(path) || raise(Errno::EINVAL)
155
+ YAML.load_file(path) || fail(Errno::EINVAL)
145
156
  rescue Errno::EINVAL, Errno::ENOENT, Psych::SyntaxError, SyntaxError
146
157
  message = <<-ERROR
147
158
  Could not load GeoRedirect config YML file.
148
- Please make sure you have a valid YML file and pass its name when adding the GeoRedirect middlware.
159
+ Please make sure you have a valid YML file and pass its name
160
+ when adding the GeoRedirect middlware.
149
161
  ERROR
150
- self.log(message, :error)
162
+ log(message, :error)
151
163
  end
152
164
 
153
165
  def request_ip
154
- ip_address = @request.env['HTTP_X_FORWARDED_FOR'] || @request.env['REMOTE_ADDR']
166
+ ip_address =
167
+ @request.env['HTTP_X_FORWARDED_FOR'] || @request.env['REMOTE_ADDR']
155
168
  # take only the first given ip
156
169
  ip_address.split(',').first.strip
157
170
  end
158
171
 
159
-
160
172
  def country_from_request
161
173
  ip = request_ip
162
- self.log "Handling GeoIP lookup: IP #{ip}"
174
+ log "Handling GeoIP lookup: IP #{ip}"
163
175
 
164
- res = @db.country(ip)
165
- code = res[:country_code]
176
+ res = @db.country(ip)
177
+ code = res[:country_code]
166
178
 
167
179
  res[:country_code2] unless code.nil? || code.zero?
168
180
  end
@@ -173,9 +185,9 @@ module GeoRedirect
173
185
  url.host = hostname if hostname
174
186
 
175
187
  # Remove force flag from GET arguments
176
- query_hash = Rack::Utils.parse_query(url.query).tap{ |u|
188
+ query_hash = Rack::Utils.parse_query(url.query).tap do |u|
177
189
  u.delete('redirect')
178
- }
190
+ end
179
191
 
180
192
  # Copy query
181
193
  url.query = URI.encode_www_form(query_hash)
@@ -185,13 +197,10 @@ module GeoRedirect
185
197
  end
186
198
 
187
199
  def should_redirect?(hostname, same_host)
188
- unless hostname.nil? || same_host
189
- hostname_ends_with = %r{#{hostname.gsub(".", "\.")}$}
190
- (@request.host =~ hostname_ends_with).nil?
191
- else
192
- true
193
- end
194
- end
200
+ return true if hostname.nil? || same_host
195
201
 
202
+ hostname_ends_with = %r{#{hostname.gsub(".", "\.")}$}
203
+ (@request.host =~ hostname_ends_with).nil?
204
+ end
196
205
  end
197
206
  end
@@ -1,3 +1,3 @@
1
1
  module GeoRedirect
2
- VERSION = "0.3"
2
+ VERSION = '0.4'
3
3
  end
@@ -5,9 +5,9 @@ require 'zlib'
5
5
  namespace :geo_redirect do
6
6
  DB_URI = 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz'
7
7
 
8
- desc "Fetches an updated copy of the GeoIP countries DB from MaxMind"
9
- task :fetch_db, :db_path do |t, args|
10
- args.with_defaults(:db_path => GeoRedirect::DEFAULT_DB_PATH)
8
+ desc 'Fetches an updated copy of the GeoIP countries DB from MaxMind'
9
+ task :fetch_db, :db_path do |_t, args|
10
+ args.with_defaults(db_path: GeoRedirect::DEFAULT_DB_PATH)
11
11
 
12
12
  # Fetches DB copy and gunzips it
13
13
  # Thx http://stackoverflow.com/a/2014317/107085
@@ -1,141 +1,130 @@
1
- require "spec_helper"
2
- require "tempfile"
3
- require "logger"
1
+ require 'spec_helper'
2
+ require 'tempfile'
3
+ require 'logger'
4
4
 
5
- describe "geo_redirect" do
5
+ describe 'geo_redirect' do
6
6
  include GeoRedirect::Support
7
7
  include Rack::Test::Methods
8
8
 
9
9
  def session
10
- last_request.env['rack.session']
10
+ last_request.env['rack.session'] || {}
11
11
  end
12
12
 
13
13
  def url_scheme
14
14
  last_request.env['rack.url_scheme']
15
15
  end
16
16
 
17
- before :each do
18
- @config = YAML.load_file(fixture_path("config.yml"))
19
- end
17
+ let(:config) { YAML.load_file(fixture_path('config.yml')) }
20
18
 
21
- describe "#load_config" do
22
- it "reads a config file" do
19
+ describe '#load_config' do
20
+ it 'reads a config file' do
23
21
  mock_app
24
-
25
- @app.config.should_not be_nil
26
- @app.config.should eq(@config)
22
+ expect(@app.config).to eq(config)
27
23
  end
28
24
 
29
- it "errors on not-found config file" do
30
- mock_app :config => nonexisting_file_path
31
- log_should_include("ERROR")
32
- log_should_include("Could not load GeoRedirect config YML file")
25
+ it 'errors on not-found config file' do
26
+ mock_app config: nonexisting_file_path
27
+ log_should_include('ERROR')
28
+ log_should_include('Could not load GeoRedirect config YML file')
33
29
  end
34
30
 
35
- it "errors on a mal-formatted config file" do
36
- mock_app :config => fixture_path("config.bad.yml")
37
- log_should_include("ERROR")
38
- log_should_include("Could not load GeoRedirect config YML file")
31
+ it 'errors on a mal-formatted config file' do
32
+ mock_app config: fixture_path('config.bad.yml')
33
+ log_should_include('ERROR')
34
+ log_should_include('Could not load GeoRedirect config YML file')
39
35
  end
40
36
  end
41
37
 
42
- describe "#load_db" do
43
- it "reads a db file" do
38
+ describe '#load_db' do
39
+ it 'reads a db file' do
44
40
  mock_app
45
-
46
- @app.db.should_not be_nil
47
- @app.db.should be_a_kind_of GeoIP
41
+ expect(@app.db).to be_a(GeoIP)
48
42
  end
49
43
 
50
- it "errors on not-found db file" do
51
- mock_app :db => nonexisting_file_path
52
- log_should_include("ERROR")
53
- log_should_include("Could not load GeoIP database file.")
44
+ it 'errors on not-found db file' do
45
+ mock_app db: nonexisting_file_path
46
+ log_should_include('ERROR')
47
+ log_should_include('Could not load GeoIP database file.')
54
48
  end
55
49
 
56
50
  # this example is disabled, as it seems that
57
51
  # GeoIP does not let me know if a db file is proper.
58
- =begin
59
- it "errors on mal-formatted db file" do
60
- pending "GeoIP does not raise on bad files"
61
- mock_app :db => fixture_path("config.yml")
62
- log_should_include("ERROR")
63
- log_should_include("Could not load GeoIP database file.")
64
- end
65
- =end
52
+ # it "errors on mal-formatted db file" do
53
+ # pending "GeoIP does not raise on bad files"
54
+ # mock_app :db => fixture_path("config.yml")
55
+ # log_should_include("ERROR")
56
+ # log_should_include("Could not load GeoIP database file.")
57
+ # end
66
58
  end
67
59
 
68
- describe "#log" do
69
- describe "with valid logfile path" do
70
- before :each do
71
- mock_app
72
- end
60
+ describe '#log' do
61
+ describe 'with valid logfile path' do
62
+ before { mock_app }
73
63
 
74
- it "initiates a log file" do
64
+ it 'initiates a log file' do
75
65
  @app.instance_variable_get(:"@logger").should be_kind_of Logger
76
66
  end
77
67
 
78
- it "prints to log file" do
79
- message = "Testing GeoRedirect logger"
68
+ it 'prints to log file' do
69
+ message = 'Testing GeoRedirect logger'
80
70
  @app.send(:log, [message])
81
71
  log_should_include(message)
82
72
  end
83
73
  end
84
74
 
85
- it "ignores invalid logfile path" do
86
- mock_app :logfile => '/no_such_file'
87
- @app.instance_variable_get(:"@logger").should be_nil
75
+ it 'ignores invalid logfile path' do
76
+ mock_app logfile: '/no_such_file'
77
+ expect(@app.instance_variable_get(:"@logger")).to be_nil
88
78
  end
89
79
  end
90
80
 
91
- describe "#host_by_country" do
92
- before :each do
93
- mock_app
94
- end
81
+ describe '#host_by_country' do
82
+ before { mock_app }
83
+ subject { @app.host_by_country(country) }
95
84
 
96
- it "fetches host by country" do
97
- @app.host_by_country("US").should eq(:us)
98
- @app.host_by_country("IL").should eq(:il)
85
+ context 'when country is valid' do
86
+ let(:country) { 'US' }
87
+ it { is_expected.to eq(:us) }
99
88
  end
100
89
 
101
- it "falls back to default" do
102
- @app.host_by_country(:foo).should eq(:default)
90
+ context 'when country is invalid' do
91
+ let(:country) { 'WHATEVER' }
92
+ it { is_expected.to eq(:default) }
103
93
  end
104
94
  end
105
95
 
106
- describe "host_by_hostname" do
107
- before :each do
108
- mock_app
109
- end
96
+ describe 'host_by_hostname' do
97
+ before { mock_app }
98
+ subject { @app.host_by_hostname(hostname) }
110
99
 
111
- it "fetches host by hostname" do
112
- @app.host_by_hostname("biz.waze.com").should eq(:us)
113
- @app.host_by_hostname("biz.waze.co.il").should eq(:il)
114
- @app.host_by_hostname("biz.world.waze.com").should eq(:world)
100
+ context 'when hostname is valid' do
101
+ let(:hostname) { 'biz.waze.co.il' }
102
+ it { is_expected.to eq(:il) }
115
103
  end
116
104
 
117
- it "falls back to default" do
118
- @app.host_by_hostname("foo").should eq(:default)
105
+ context 'when hostname is invalid' do
106
+ let(:hostname) { 'something.else.org' }
107
+ it { is_expected.to eq(:default) }
119
108
  end
120
109
  end
121
110
 
122
- describe "redirect logic" do
111
+ describe 'redirect logic' do
123
112
  before :each do
124
113
  mock_app
125
114
  end
126
115
 
127
- def mock_request_from(code, options={})
128
- ip = "5.5.5.5"
116
+ def mock_request_from(code, options = {})
117
+ ip = '5.5.5.5'
129
118
 
130
119
  if code.nil?
131
120
  country = nil
132
121
  else
133
- country = GeoIP::Country.stub({ :country_code2 => code,
134
- :country_code => 5 })
122
+ country = GeoIP::Country.stub(country_code2: code,
123
+ country_code: 5)
135
124
  end
136
125
  @app.db.stub(:country).with(ip).and_return(country)
137
126
 
138
- env = { "REMOTE_ADDR" => ip, "HTTP_HOST" => "biz.waze.co.il" }
127
+ env = { 'REMOTE_ADDR' => ip, 'HTTP_HOST' => 'biz.waze.co.il' }
139
128
 
140
129
  if options[:session]
141
130
  env['rack.session'] ||= {}
@@ -144,23 +133,22 @@ describe "geo_redirect" do
144
133
  end
145
134
 
146
135
  args = {}
147
- if options[:force]
148
- args[:redirect] = 1
149
- end
136
+ args[:redirect] = 1 if options[:force]
137
+ args[:skip_geo] = true if options[:skip]
150
138
 
151
- get "/", args, env
139
+ get '/', args, env
152
140
  end
153
141
 
154
142
  def should_redirect_to(host)
155
- last_response.body.should include("Moved Permanently")
143
+ last_response.body.should include('Moved Permanently')
156
144
  last_response.status.should eq(301)
157
- last_response.headers.should have_key("Location")
158
- url = "#{url_scheme}://#{@config[host][:host]}"
159
- last_response.headers["Location"].should start_with(url)
145
+ last_response.headers.should have_key('Location')
146
+ url = "#{url_scheme}://#{config[host][:host]}"
147
+ last_response.headers['Location'].should start_with(url)
160
148
  end
161
149
 
162
150
  def should_not_redirect
163
- last_response.body.should include("Hello world!")
151
+ last_response.body.should include('Hello world!')
164
152
  last_response.should be_ok
165
153
  end
166
154
 
@@ -172,149 +160,82 @@ describe "geo_redirect" do
172
160
  session['geo_redirect.country'].should eq(country)
173
161
  end
174
162
 
175
- describe "without session memory" do
176
- describe "for a foreign source" do
177
- before :each do
178
- mock_request_from "US"
179
- end
180
-
181
- it "redirects to destination" do
182
- should_redirect_to :us
183
- end
184
-
185
- it "stores decision in session" do
186
- should_remember :us
187
- end
188
-
189
- it "stores discovered country in session" do
190
- should_remember_country "US"
191
- end
163
+ describe 'without session memory' do
164
+ describe 'for a foreign source' do
165
+ before { mock_request_from 'US' }
166
+ it { should_redirect_to :us }
167
+ it { should_remember :us }
168
+ it { should_remember_country 'US' }
192
169
  end
193
170
 
194
- describe "for a local source" do
195
- before :each do
196
- mock_request_from "IL"
197
- end
198
-
199
- it "does not redirect" do
200
- should_not_redirect
201
- end
202
-
203
- it "stores decision in session" do
204
- should_remember :il
205
- end
206
-
207
- it "stores discovered country in session" do
208
- should_remember_country "IL"
209
- end
171
+ describe 'for a local source' do
172
+ before { mock_request_from 'IL' }
173
+ it { should_not_redirect }
174
+ it { should_remember :il }
175
+ it { should_remember_country 'IL' }
210
176
  end
211
177
 
212
- describe "for an unknown source" do
213
- before :each do
214
- mock_request_from "SOMEWHERE OVER THE RAINBOW"
215
- end
216
-
217
- it "redirects to default" do
218
- should_redirect_to :default
219
- end
220
-
221
- it "stores decision in session" do
222
- should_remember :default
223
- end
224
-
225
- it "stores discovered country in session" do
226
- should_remember_country "SOMEWHERE OVER THE RAINBOW"
227
- end
178
+ describe 'for an unknown source' do
179
+ before { mock_request_from 'SOMEWHERE OVER THE RAINBOW' }
180
+ it { should_redirect_to :default }
181
+ it { should_remember :default }
182
+ it { should_remember_country 'SOMEWHERE OVER THE RAINBOW' }
228
183
  end
229
184
  end
230
185
 
231
- describe "with valid session memory" do
232
- before :each do
233
- mock_request_from "US", :session => :default
234
- end
235
-
236
- it "redirects to remembered destination" do
237
- should_redirect_to :default
238
- end
239
-
240
- it "leaves session as is" do
241
- should_remember :default
242
- end
243
-
244
- it "remembers discovered country" do
245
- should_remember_country "US"
246
- end
186
+ describe 'with valid session memory' do
187
+ before { mock_request_from 'US', session: :default }
188
+ it { should_redirect_to :default }
189
+ it { should_remember :default }
190
+ it { should_remember_country 'US' }
247
191
  end
248
192
 
249
- describe "with invalid session memory" do
250
- before :each do
251
- mock_request_from "US", :session => "foo"
252
- end
253
-
254
- it "removes invalid session data" do
255
- session['geo_redirect'].should_not eq("foo")
256
- end
257
-
258
- it "redirects to destination" do
259
- should_redirect_to :us
260
- end
193
+ describe 'with invalid session memory' do
194
+ before { mock_request_from 'US', session: 'foo' }
261
195
 
262
- it "stores decision in session" do
263
- should_remember :us
196
+ it 'removes invalid session data' do
197
+ expect(session['geo_redirect']).not_to eq('foo')
264
198
  end
265
199
 
266
- it "stores discovered country in session" do
267
- should_remember_country "US"
268
- end
200
+ it { should_redirect_to :us }
201
+ it { should_remember :us }
202
+ it { should_remember_country 'US' }
269
203
  end
270
204
 
271
- describe "with forced redirect flag" do
272
- before :each do
273
- mock_request_from "US", :force => true
274
- end
205
+ describe 'with forced redirect flag' do
206
+ before { mock_request_from 'US', force: true }
275
207
 
276
- it "rewrites the flag out" do
277
- should_redirect_to :il
278
- last_response.headers["Location"].should_not include("redirect=1")
208
+ it { should_redirect_to :il }
209
+ it 'rewrites the flag out' do
210
+ expect(last_response.headers['Location']).not_to include('redirect=1')
279
211
  end
280
212
 
281
- it "stores decision in session" do
282
- should_remember :il
283
- end
284
-
285
- it "does not store discovered country in session" do
286
- should_remember_country nil
287
- end
213
+ it { should_remember :il }
214
+ it { should_remember_country nil }
288
215
  end
289
216
 
290
- describe "with no recognizable IP" do
291
- before :each do
292
- mock_request_from nil
293
- end
294
-
295
- it "does not redirect" do
296
- should_not_redirect
297
- end
298
-
299
- it "does not store session" do
300
- should_remember nil
301
- end
302
-
303
- it "does not store discovered country in session" do
304
- should_remember_country nil
305
- end
217
+ describe 'with skip flag' do
218
+ before { mock_request_from 'US', skip: true }
219
+ it { should_not_redirect }
220
+ it { should_remember nil }
221
+ it { should_remember_country nil }
306
222
  end
307
223
 
224
+ describe 'with no recognizable IP' do
225
+ before { mock_request_from nil }
226
+ it { should_not_redirect }
227
+ it { should_remember nil }
228
+ it { should_remember_country nil }
229
+ end
308
230
  end
309
231
  end
310
232
 
311
- describe "geo_redirect:fetch_db" do
312
- include_context "rake"
233
+ describe 'geo_redirect:fetch_db' do
234
+ include_context 'rake'
313
235
 
314
- it "downloads a GeoIP db to a location" do
315
- @dbfile = Tempfile.new("db")
316
- subject.invoke(@dbfile.path)
317
- @dbfile.size.should_not be_nil
318
- @dbfile.size.should be > 0
236
+ it 'downloads a GeoIP db to a location' do
237
+ dbfile = Tempfile.new('db')
238
+ subject.invoke(dbfile.path)
239
+ expect(dbfile.size).to be > 0
319
240
  end
320
241
  end
data/spec/spec_helper.rb CHANGED
@@ -1,16 +1,16 @@
1
- require "simplecov"
1
+ require 'simplecov'
2
2
  SimpleCov.start
3
3
 
4
- require "rspec"
5
- require "rack"
6
- require "rack/test"
4
+ require 'rspec'
5
+ require 'rack'
6
+ require 'rack/test'
7
7
 
8
8
  current_dir = File.dirname(__FILE__)
9
9
  $LOAD_PATH.unshift(File.join(current_dir, '..', 'lib'))
10
10
  $LOAD_PATH.unshift(current_dir)
11
- require "geo_redirect"
11
+ require 'geo_redirect'
12
12
 
13
- Dir[File.join(current_dir, "support/**/*.rb")].each { |f| require f }
13
+ Dir[File.join(current_dir, 'support/**/*.rb')].each { |f| require f }
14
14
 
15
15
  # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
16
  RSpec.configure do |config|
@@ -18,5 +18,5 @@ RSpec.configure do |config|
18
18
  config.run_all_when_everything_filtered = true
19
19
  config.filter_run :focus
20
20
 
21
- config.order = "random"
21
+ config.order = 'random'
22
22
  end
@@ -5,7 +5,7 @@ module GeoRedirect
5
5
  end
6
6
 
7
7
  def nonexisting_file_path
8
- "/no_such_file"
8
+ '/no_such_file'
9
9
  end
10
10
 
11
11
  def app
@@ -14,16 +14,16 @@ module GeoRedirect
14
14
 
15
15
  def mock_app(options = {})
16
16
  # Simple HTTP server that always returns 'Hello world!'
17
- main_app = lambda { |env|
17
+ main_app = lambda do |env|
18
18
  Rack::Request.new(env)
19
- headers = {"Content-Type" => "text/html"}
20
- [200, headers, ["Hello world!"]]
21
- }
19
+ headers = { 'Content-Type' => 'text/html' }
20
+ [200, headers, ['Hello world!']]
21
+ end
22
22
 
23
- @logfile = Tempfile.new("log")
24
- options = { :config => fixture_path("config.yml"),
25
- :db => fixture_path("GeoIP.dat"),
26
- :logfile => @logfile.path
23
+ @logfile = Tempfile.new('log')
24
+ options = { config: fixture_path('config.yml'),
25
+ db: fixture_path('GeoIP.dat'),
26
+ logfile: @logfile.path
27
27
  }.merge(options)
28
28
 
29
29
  builder = Rack::Builder.new
@@ -38,4 +38,3 @@ module GeoRedirect
38
38
  end
39
39
  end
40
40
  end
41
-
data/spec/support/rake.rb CHANGED
@@ -1,17 +1,17 @@
1
1
  # thanks http://robots.thoughtbot.com/post/11957424161/test-rake-tasks-like-a-boss
2
2
 
3
- require "rake"
3
+ require 'rake'
4
4
 
5
- shared_context "rake" do
5
+ shared_context 'rake' do
6
6
  let(:rake) { Rake::Application.new }
7
7
  let(:task_name) { self.class.top_level_description }
8
- let(:task_path) { "lib/tasks/#{task_name.split(":").first}" }
8
+ let(:task_path) { "lib/tasks/#{task_name.split(':').first}" }
9
9
  subject { rake[task_name] }
10
10
 
11
11
  before do
12
12
  Rake.application = rake
13
- Rake.application.rake_require(task_path,
14
- [File.join(File.dirname(__FILE__), "..", "..")])
13
+ Rake.application
14
+ .rake_require(task_path, [File.join(File.dirname(__FILE__), '..', '..')])
15
15
 
16
16
  Rake::Task.define_task(:environment)
17
17
  end
metadata CHANGED
@@ -1,128 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: geo_redirect
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.3'
5
- prerelease:
4
+ version: '0.4'
6
5
  platform: ruby
7
6
  authors:
8
7
  - Sagie Maoz
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-07-18 00:00:00.000000000 Z
11
+ date: 2015-01-12 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rake
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: geoip
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: rspec
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ~>
52
46
  - !ruby/object:Gem::Version
53
- version: 2.13.0
47
+ version: 3.1.0
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - ~>
60
53
  - !ruby/object:Gem::Version
61
- version: 2.13.0
54
+ version: 3.1.0
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: rack
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
59
  - - ~>
68
60
  - !ruby/object:Gem::Version
69
- version: 1.5.2
61
+ version: 1.6.0
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
66
  - - ~>
76
67
  - !ruby/object:Gem::Version
77
- version: 1.5.2
68
+ version: 1.6.0
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rack-test
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
73
  - - ~>
84
74
  - !ruby/object:Gem::Version
85
- version: 0.6.2
75
+ version: 0.6.3
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
80
  - - ~>
92
81
  - !ruby/object:Gem::Version
93
- version: 0.6.2
94
- - !ruby/object:Gem::Dependency
95
- name: debugger
96
- requirement: !ruby/object:Gem::Requirement
97
- none: false
98
- requirements:
99
- - - ~>
100
- - !ruby/object:Gem::Version
101
- version: 1.5.0
102
- type: :development
103
- prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
- requirements:
107
- - - ~>
108
- - !ruby/object:Gem::Version
109
- version: 1.5.0
82
+ version: 0.6.3
110
83
  - !ruby/object:Gem::Dependency
111
84
  name: simplecov
112
85
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
86
  requirements:
115
87
  - - ~>
116
88
  - !ruby/object:Gem::Version
117
- version: 0.7.1
89
+ version: 0.9.1
118
90
  type: :development
119
91
  prerelease: false
120
92
  version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
93
  requirements:
123
94
  - - ~>
124
95
  - !ruby/object:Gem::Version
125
- version: 0.7.1
96
+ version: 0.9.1
126
97
  description: Geo-location based redirector
127
98
  email:
128
99
  - sagie@waze.com
@@ -132,6 +103,7 @@ extra_rdoc_files: []
132
103
  files:
133
104
  - .gitignore
134
105
  - .rspec
106
+ - .rubocop.yml
135
107
  - .travis.yml
136
108
  - Gemfile
137
109
  - LICENSE.txt
@@ -152,33 +124,26 @@ files:
152
124
  - spec/support/rake.rb
153
125
  homepage: ''
154
126
  licenses: []
127
+ metadata: {}
155
128
  post_install_message:
156
129
  rdoc_options: []
157
130
  require_paths:
158
131
  - lib
159
132
  required_ruby_version: !ruby/object:Gem::Requirement
160
- none: false
161
133
  requirements:
162
- - - ! '>='
134
+ - - '>='
163
135
  - !ruby/object:Gem::Version
164
136
  version: '0'
165
- segments:
166
- - 0
167
- hash: 3031125964627560618
168
137
  required_rubygems_version: !ruby/object:Gem::Requirement
169
- none: false
170
138
  requirements:
171
- - - ! '>='
139
+ - - '>='
172
140
  - !ruby/object:Gem::Version
173
141
  version: '0'
174
- segments:
175
- - 0
176
- hash: 3031125964627560618
177
142
  requirements: []
178
143
  rubyforge_project:
179
- rubygems_version: 1.8.24
144
+ rubygems_version: 2.4.5
180
145
  signing_key:
181
- specification_version: 3
146
+ specification_version: 4
182
147
  summary: Rack middleware to redirect clients to hostnames based on geo-location
183
148
  test_files:
184
149
  - spec/fixtures/GeoIP.dat