Permalink
Browse files

Merge branch 'master' of git://github.com/Sjlver/geokit-gem

  • Loading branch information...
2 parents 5fe4ee6 + ba9239f commit e6ff6d614bd6fce16a489146f025bab9dc233857 Andre Lewis committed Sep 21, 2009
Showing with 64 additions and 11 deletions.
  1. +32 −1 lib/geokit/geocoders.rb
  2. +32 −10 test/test_ipgeocoder.rb
View
@@ -1,4 +1,5 @@
require 'net/http'
+require 'ipaddr'
require 'rexml/document'
require 'yaml'
require 'timeout'
@@ -556,14 +557,35 @@ def self.parse_xml(xml)
# as community contributions.
class IpGeocoder < Geocoder
+ # A number of non-routable IP ranges.
+ #
+ # --
+ # Sources for these:
+ # RFC 3330: Special-Use IPv4 Addresses
+ # The bogon list: http://www.cymru.com/Documents/bogon-list.html
+
+ NON_ROUTABLE_IP_RANGES = [
+ IPAddr.new('0.0.0.0/8'), # "This" Network
+ IPAddr.new('10.0.0.0/8'), # Private-Use Networks
+ IPAddr.new('14.0.0.0/8'), # Public-Data Networks
+ IPAddr.new('127.0.0.0/8'), # Loopback
+ IPAddr.new('169.254.0.0/16'), # Link local
+ IPAddr.new('172.16.0.0/12'), # Private-Use Networks
+ IPAddr.new('192.0.2.0/24'), # Test-Net
+ IPAddr.new('192.168.0.0/16'), # Private-Use Networks
+ IPAddr.new('198.18.0.0/15'), # Network Interconnect Device Benchmark Testing
+ IPAddr.new('224.0.0.0/4'), # Multicast
+ IPAddr.new('240.0.0.0/4') # Reserved for future use
+ ].freeze
+
private
# Given an IP address, returns a GeoLoc instance which contains latitude,
# longitude, city, and country code. Sets the success attribute to false if the ip
# parameter does not match an ip address.
def self.do_geocode(ip, options = {})
- return GeoLoc.new if '0.0.0.0' == ip
return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
+ return GeoLoc.new if self.private_ip_address?(ip)
url = "http://api.hostip.info/get_html.php?ip=#{ip}&position=true"
response = self.call_geocoder_service(url)
response.is_a?(Net::HTTPSuccess) ? parse_body(response.body) : GeoLoc.new
@@ -592,6 +614,15 @@ def self.parse_body(body) # :nodoc:
res.success = !(res.city =~ /\(.+\)/)
res
end
+
+ # Checks whether the IP address belongs to a private address range.
+ #
+ # This function is used to reduce the number of useless queries made to
+ # the geocoding service. Such queries can occur frequently during
+ # integration tests.
+ def self.private_ip_address?(ip)
+ return NON_ROUTABLE_IP_RANGES.any? { |range| range.include?(ip) }
+ end
end
# -------------------------------------------------------------------------------------------
View
@@ -4,8 +4,8 @@
class IpGeocoderTest < BaseGeocoderTest #:nodoc: all
IP_FAILURE=<<-EOF
- Country: (Private Address) (XX)
- City: (Private Address)
+ Country: SWITZERLAND (CH)
+ City: (Unknown City)
Latitude:
Longitude:
EOF
@@ -24,10 +24,22 @@ class IpGeocoderTest < BaseGeocoderTest #:nodoc: all
Longitude: 12.9167
EOF
- def setup
- super
- @success.provider = "hostip"
- end
+ PRIVATE_IPS_TO_TEST = [
+ '10.10.10.10',
+ '172.16.1.3',
+ '172.22.3.42',
+ '172.30.254.164',
+ '192.168.1.1',
+ '0.0.0.0',
+ '127.0.0.1',
+ '240.3.4.5',
+ '225.1.6.55'
+ ].freeze
+
+ def setup
+ super
+ @success.provider = "hostip"
+ end
def test_successful_lookup
success = MockSuccess.new
@@ -64,24 +76,34 @@ def test_unicoded_lookup
def test_failed_lookup
failure = MockSuccess.new
failure.expects(:body).returns(IP_FAILURE)
- url = 'http://api.hostip.info/get_html.php?ip=10.10.10.10&position=true'
+ url = 'http://api.hostip.info/get_html.php?ip=128.178.0.0&position=true'
GeoKit::Geocoders::IpGeocoder.expects(:call_geocoder_service).with(url).returns(failure)
- location = GeoKit::Geocoders::IpGeocoder.geocode("10.10.10.10")
+ location = GeoKit::Geocoders::IpGeocoder.geocode("128.178.0.0")
assert_not_nil location
assert !location.success?
end
+ def test_private_ips
+ GeoKit::Geocoders::IpGeocoder.expects(:call_geocoder_service).never
+ PRIVATE_IPS_TO_TEST.each do |ip|
+ location = GeoKit::Geocoders::IpGeocoder.geocode(ip)
+ assert_not_nil location
+ assert !location.success?
+ end
+ end
+
def test_invalid_ip
+ GeoKit::Geocoders::IpGeocoder.expects(:call_geocoder_service).never
location = GeoKit::Geocoders::IpGeocoder.geocode("blah")
assert_not_nil location
assert !location.success?
end
def test_service_unavailable
failure = MockFailure.new
- url = 'http://api.hostip.info/get_html.php?ip=10.10.10.10&position=true'
+ url = 'http://api.hostip.info/get_html.php?ip=12.215.42.19&position=true'
GeoKit::Geocoders::IpGeocoder.expects(:call_geocoder_service).with(url).returns(failure)
- location = GeoKit::Geocoders::IpGeocoder.geocode("10.10.10.10")
+ location = GeoKit::Geocoders::IpGeocoder.geocode("12.215.42.19")
assert_not_nil location
assert !location.success?
end

0 comments on commit e6ff6d6

Please sign in to comment.