geoip_server 1.0.0
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.
- data/.gems +2 -0
- data/README.markdown +31 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/config.ru +6 -0
- data/lib/geoip_server.rb +73 -0
- data/test.rb +73 -0
- metadata +86 -0
data/.gems
ADDED
data/README.markdown
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# GeoIP Server
|
|
2
|
+
|
|
3
|
+
This simple Rack server is useful as a self-hosted service for making lookups to the GeoIP database from MaxMind.com
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Instant installation and deploy
|
|
7
|
+
|
|
8
|
+
* Clone this: `git clone git://github.com/JackDanger/geoip_server.git`
|
|
9
|
+
* Download the free GeoIP data files: `rake geoip:update_city_lite`
|
|
10
|
+
* Commit that data file to your clone: `git add vendor && git commit -m "adding data file"`
|
|
11
|
+
* Signup for an account at Heroku ([better details here](http://github.com/sinatra/heroku-sinatra-app))
|
|
12
|
+
* Create and name a new app where you want to host this
|
|
13
|
+
* push it to Heroku.com: `git push heroku master`
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
## HowTo
|
|
17
|
+
|
|
18
|
+
Once the server is running you can make a GET request to the server and receive lookup results in JSON format.
|
|
19
|
+
|
|
20
|
+
ip = request.remote_ip
|
|
21
|
+
require 'open-uri'
|
|
22
|
+
data = JSON.decode(open("http://my-geoip-service-app.heroku.com/#{ip}").read)
|
|
23
|
+
render :text => "You're in: #{data[:city]}"
|
|
24
|
+
|
|
25
|
+
Or, straight from a terminal:
|
|
26
|
+
|
|
27
|
+
curl -X POST http://my-geoip-service-app.heroku.com/207.97.227.239
|
|
28
|
+
|
|
29
|
+
Patches welcome, forks celebrated.
|
|
30
|
+
|
|
31
|
+
Copyright (c) 2010 [Jack Danger Canty](http://jåck.com). Released under the MIT License.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'jeweler'
|
|
3
|
+
Jeweler::Tasks.new do |gem|
|
|
4
|
+
gem.name = "geoip_server"
|
|
5
|
+
gem.summary = %Q{Query the MaxMind GeoIP data records via a web service}
|
|
6
|
+
gem.description = %Q{Query the MaxMind GeoIP data records via a web service}
|
|
7
|
+
gem.email = "gitcommit@6brand.com"
|
|
8
|
+
gem.homepage = "http://github.com/JackDanger/geoip_server"
|
|
9
|
+
gem.authors = ["Jack Danger Canty"]
|
|
10
|
+
gem.add_development_dependency "shoulda", ">= 0"
|
|
11
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
|
12
|
+
end
|
|
13
|
+
Jeweler::GemcutterTasks.new
|
|
14
|
+
rescue LoadError
|
|
15
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
task :default => :test
|
|
21
|
+
|
|
22
|
+
require 'rake/testtask'
|
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
|
24
|
+
test.libs << '.'
|
|
25
|
+
test.pattern = 'test.rb'
|
|
26
|
+
test.verbose = true
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
namespace :geoip do
|
|
33
|
+
desc "Update GeoIP City data file"
|
|
34
|
+
task :update_city_lite => :vendor do
|
|
35
|
+
%x{wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz && gzip -d GeoLiteCity.dat.gz && mv GeoLiteCity.dat ./vendor}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
desc "Update GeoIP Country data file"
|
|
39
|
+
task :update_country_lite => :vendor do
|
|
40
|
+
%x{wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz && gzip -d GeoIP.dat.gz && mv GeoIP.dat ./vendor}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
task :vendor do
|
|
44
|
+
%x{mkdir -p vendor}
|
|
45
|
+
end
|
|
46
|
+
end
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.0
|
data/config.ru
ADDED
data/lib/geoip_server.rb
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
## Resources
|
|
2
|
+
gem 'sinatra', :version => '1.0'
|
|
3
|
+
require 'sinatra'
|
|
4
|
+
require 'geoip'
|
|
5
|
+
require 'json'
|
|
6
|
+
|
|
7
|
+
data_file = File.expand_path(File.join(File.dirname(__FILE__), '..', 'vendor', 'GeoLiteCity.dat'))
|
|
8
|
+
|
|
9
|
+
## Application
|
|
10
|
+
|
|
11
|
+
get '/' do
|
|
12
|
+
%Q{
|
|
13
|
+
<html><title>Detect a computer's location by IP address</title>
|
|
14
|
+
<body style='line-height: 1.8em; font-family: Archer, Museo, Helvetica, Georgia; font-size 25px; text-align: center; padding-top: 20%;'>
|
|
15
|
+
Lookup a location by IP address. Example:
|
|
16
|
+
<pre style='font-family: Iconsolata, monospace;background-color:#EEE'>curl http://#{request.host}/207.97.227.239</pre>
|
|
17
|
+
<br />
|
|
18
|
+
<form action=/ method=GET onsubmit='if(\"\"==this.ip.value)return false;else{this.action=\"/\"+this.ip.value}'>
|
|
19
|
+
<input type=text name='ip' value='#{request.env['HTTP_X_REAL_IP']}' />
|
|
20
|
+
<input type=submit value='Lookup!' />
|
|
21
|
+
</form>
|
|
22
|
+
<div>None of this would be possible without <a href='http://www.maxmind.com/app/geolitecity'>MaxMind</a></div>
|
|
23
|
+
</body></html>
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
get '/:ip' do
|
|
28
|
+
pass unless params[:ip] =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
|
|
29
|
+
|
|
30
|
+
data = GeoIP.new(data_file).city(params[:ip])
|
|
31
|
+
|
|
32
|
+
content_type 'application/json'
|
|
33
|
+
headers['Cache-Control'] = "public; max-age=#{365*24*60*60}"
|
|
34
|
+
|
|
35
|
+
return "{}" unless data
|
|
36
|
+
|
|
37
|
+
encode(data).to_json
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def encode data
|
|
42
|
+
{
|
|
43
|
+
# * The host or IP address string as requested
|
|
44
|
+
:ip => data.shift,
|
|
45
|
+
# * The IP address string after looking up the host
|
|
46
|
+
:ip_lookup => data.shift,
|
|
47
|
+
# * The GeoIP country-ID as an integer
|
|
48
|
+
# :country_id => data.shift,
|
|
49
|
+
# * The ISO3166-1 two-character country code
|
|
50
|
+
:country_code => data.shift,
|
|
51
|
+
# * The ISO3166-2 three-character country code
|
|
52
|
+
:country_code_long => data.shift,
|
|
53
|
+
# * The ISO3166 English-language name of the country
|
|
54
|
+
:country => data.shift,
|
|
55
|
+
# * The two-character continent code
|
|
56
|
+
:continent => data.shift,
|
|
57
|
+
# * The region name
|
|
58
|
+
:region => data.shift,
|
|
59
|
+
# * The city name
|
|
60
|
+
:city => data.shift,
|
|
61
|
+
# * The postal code
|
|
62
|
+
:postal_code => data.shift,
|
|
63
|
+
# * The latitude
|
|
64
|
+
:lat => data.shift,
|
|
65
|
+
# * The longitude
|
|
66
|
+
:lng => data.shift,
|
|
67
|
+
# * The USA dma_code and area_code, if available (REV1 City database)
|
|
68
|
+
:dma_code => data.shift,
|
|
69
|
+
:area_code => data.shift,
|
|
70
|
+
# Timezone, if available
|
|
71
|
+
:timezone => data.shift
|
|
72
|
+
}
|
|
73
|
+
end
|
data/test.rb
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'test/unit'
|
|
5
|
+
require 'shoulda'
|
|
6
|
+
require 'rack/test'
|
|
7
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'lib/geoip_server'))
|
|
8
|
+
|
|
9
|
+
class GeoipServerTest < Test::Unit::TestCase
|
|
10
|
+
include Rack::Test::Methods
|
|
11
|
+
|
|
12
|
+
def app
|
|
13
|
+
Sinatra::Application
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context "on GET to /" do
|
|
17
|
+
setup {
|
|
18
|
+
get '/'
|
|
19
|
+
}
|
|
20
|
+
should "return ok" do
|
|
21
|
+
assert last_response.ok?
|
|
22
|
+
end
|
|
23
|
+
should "have some kind of welcome" do
|
|
24
|
+
assert last_response.body =~ /curl/
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "on GET to /:ip" do
|
|
29
|
+
setup {
|
|
30
|
+
get '/67.161.92.71'
|
|
31
|
+
}
|
|
32
|
+
should "return ok" do
|
|
33
|
+
assert last_response.ok?
|
|
34
|
+
end
|
|
35
|
+
should "return json content-type" do
|
|
36
|
+
assert_equal 'application/json', last_response.headers['Content-Type']
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context "converting array" do
|
|
41
|
+
setup {
|
|
42
|
+
array = [
|
|
43
|
+
"67.161.92.71",
|
|
44
|
+
"67.161.92.71",
|
|
45
|
+
"US",
|
|
46
|
+
"USA",
|
|
47
|
+
"United States",
|
|
48
|
+
"NA",
|
|
49
|
+
"WA",
|
|
50
|
+
"Seattle",
|
|
51
|
+
"98117",
|
|
52
|
+
47.6847,
|
|
53
|
+
-122.3848,
|
|
54
|
+
819,
|
|
55
|
+
206,
|
|
56
|
+
"America/Los_Angeles"
|
|
57
|
+
]
|
|
58
|
+
@hash = encode(array)
|
|
59
|
+
}
|
|
60
|
+
should "find city" do
|
|
61
|
+
assert_equal 'Seattle', @hash[:city]
|
|
62
|
+
end
|
|
63
|
+
should "find country" do
|
|
64
|
+
assert_equal 'United States', @hash[:country]
|
|
65
|
+
end
|
|
66
|
+
should "find lat" do
|
|
67
|
+
assert_equal 47.6847, @hash[:lat]
|
|
68
|
+
end
|
|
69
|
+
should "find lng" do
|
|
70
|
+
assert_equal -122.3848, @hash[:lng]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: geoip_server
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: 23
|
|
5
|
+
prerelease: false
|
|
6
|
+
segments:
|
|
7
|
+
- 1
|
|
8
|
+
- 0
|
|
9
|
+
- 0
|
|
10
|
+
version: 1.0.0
|
|
11
|
+
platform: ruby
|
|
12
|
+
authors:
|
|
13
|
+
- Jack Danger Canty
|
|
14
|
+
autorequire:
|
|
15
|
+
bindir: bin
|
|
16
|
+
cert_chain: []
|
|
17
|
+
|
|
18
|
+
date: 2010-11-27 00:00:00 -08:00
|
|
19
|
+
default_executable:
|
|
20
|
+
dependencies:
|
|
21
|
+
- !ruby/object:Gem::Dependency
|
|
22
|
+
name: shoulda
|
|
23
|
+
prerelease: false
|
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
hash: 3
|
|
30
|
+
segments:
|
|
31
|
+
- 0
|
|
32
|
+
version: "0"
|
|
33
|
+
type: :development
|
|
34
|
+
version_requirements: *id001
|
|
35
|
+
description: Query the MaxMind GeoIP data records via a web service
|
|
36
|
+
email: gitcommit@6brand.com
|
|
37
|
+
executables: []
|
|
38
|
+
|
|
39
|
+
extensions: []
|
|
40
|
+
|
|
41
|
+
extra_rdoc_files:
|
|
42
|
+
- README.markdown
|
|
43
|
+
files:
|
|
44
|
+
- .gems
|
|
45
|
+
- README.markdown
|
|
46
|
+
- Rakefile
|
|
47
|
+
- VERSION
|
|
48
|
+
- config.ru
|
|
49
|
+
- lib/geoip_server.rb
|
|
50
|
+
- test.rb
|
|
51
|
+
has_rdoc: true
|
|
52
|
+
homepage: http://github.com/JackDanger/geoip_server
|
|
53
|
+
licenses: []
|
|
54
|
+
|
|
55
|
+
post_install_message:
|
|
56
|
+
rdoc_options:
|
|
57
|
+
- --charset=UTF-8
|
|
58
|
+
require_paths:
|
|
59
|
+
- lib
|
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
61
|
+
none: false
|
|
62
|
+
requirements:
|
|
63
|
+
- - ">="
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
hash: 3
|
|
66
|
+
segments:
|
|
67
|
+
- 0
|
|
68
|
+
version: "0"
|
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
|
+
none: false
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
hash: 3
|
|
75
|
+
segments:
|
|
76
|
+
- 0
|
|
77
|
+
version: "0"
|
|
78
|
+
requirements: []
|
|
79
|
+
|
|
80
|
+
rubyforge_project:
|
|
81
|
+
rubygems_version: 1.3.7
|
|
82
|
+
signing_key:
|
|
83
|
+
specification_version: 3
|
|
84
|
+
summary: Query the MaxMind GeoIP data records via a web service
|
|
85
|
+
test_files: []
|
|
86
|
+
|