瀏覽代碼

Merge pull request #9 from krader1961/master

Implement default values if no geo data
Andrey Blinov 6 年之前
父節點
當前提交
084ac7fec1
共有 3 個文件被更改,包括 117 次插入11 次删除
  1. 18 1
      README.md
  2. 30 10
      setup.go
  3. 69 0
      setup_test.go

+ 18 - 1
README.md

@@ -1,7 +1,9 @@
 [![Build Status](https://travis-ci.org/kodnaplakal/caddy-geoip.svg?branch=master)](https://travis-ci.org/kodnaplakal/caddy-geoip)
 ## Overview
 
-`geoip` is a Caddy plugin that allow to determine user Geolocation by IP address using MaxMind database.
+`geoip` is a Caddy plugin that allow to determine
+user Geolocation by IP address using a
+[MaxMind database](https://www.maxmind.com/en/geoip2-services-and-databases).
 
 ## Placeholders
 
@@ -20,6 +22,15 @@ The following placeholders are available:
   geoip_geohash - Geohash of latitude and longitude
 ```
 
+## Missing geolocation data
+
+If there is no geolocation data for an IP address most of the placeholders
+listed above will be empty. The exceptions are `geoip_country_code`,
+`geoip_country_name`, and `geoip_city_name`. If the request originated over
+the system loopback interface (e.g., 127.0.0.1) those vars will be set
+to `**`, `Loopback`, and `Loopback` respectively. For any other address,
+including private addresses such as 192.168.0.1, the values will be `!!`,
+`No Country`, and `No City` respectively.
 
 ## Examples
 
@@ -47,6 +58,12 @@ proxy / localhost:3000 {
 }
 ```
 
+(3) Include the geolocation info in the access log:
+
+```
+log / {$HOME}/log/access.log "{when_iso} {status} {method} {latency_ms} ms {size} bytes {geoip_country_code} {remote} {host} {proto} \"{uri}\" \"{>User-Agent}\""
+```
+
 ## Contributing
 
 1. [Fork it](https://github.com/kodnaplakal/caddy-geoip/fork)

+ 30 - 10
setup.go

@@ -10,9 +10,9 @@ import (
 
 	"github.com/mholt/caddy"
 	"github.com/mholt/caddy/caddyhttp/httpserver"
-	"github.com/oschwald/maxminddb-golang"
 	"github.com/mmcloughlin/geohash"
-	)
+	"github.com/oschwald/maxminddb-golang"
+)
 
 // GeoIP represents a middleware instance
 type GeoIP struct {
@@ -80,15 +80,9 @@ func (gip GeoIP) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error)
 }
 
 func (gip GeoIP) lookupLocation(w http.ResponseWriter, r *http.Request) {
-	clientIP, _ := getClientIP(r, true)
-	replacer := newReplacer(r)
-
-	var record = GeoIPRecord{}
-	err := gip.DBHandler.Lookup(clientIP, &record)
-	if err != nil {
-		log.Println(err)
-	}
+	record := gip.fetchGeoipData(r)
 
+	replacer := newReplacer(r)
 	replacer.Set("geoip_country_code", record.Country.ISOCode)
 	replacer.Set("geoip_country_name", record.Country.Names["en"])
 	replacer.Set("geoip_country_eu", strconv.FormatBool(record.Country.IsInEuropeanUnion))
@@ -105,6 +99,32 @@ func (gip GeoIP) lookupLocation(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
+func (gip GeoIP) fetchGeoipData(r *http.Request) GeoIPRecord {
+	clientIP, _ := getClientIP(r, true)
+
+	var record = GeoIPRecord{}
+	err := gip.DBHandler.Lookup(clientIP, &record)
+	if err != nil {
+		log.Println(err)
+	}
+
+	if record.Country.ISOCode == "" {
+		record.Country.Names = make(map[string]string)
+		record.City.Names = make(map[string]string)
+		if clientIP.IsLoopback() {
+			record.Country.ISOCode = "**"
+			record.Country.Names["en"] = "Loopback"
+			record.City.Names["en"] = "Loopback"
+		} else {
+			record.Country.ISOCode = "!!"
+			record.Country.Names["en"] = "No Country"
+			record.City.Names["en"] = "No City"
+		}
+	}
+
+	return record
+}
+
 func getClientIP(r *http.Request, strict bool) (net.IP, error) {
 	var ip string
 

+ 69 - 0
setup_test.go

@@ -81,4 +81,73 @@ func TestReplacers(t *testing.T) {
 	if got, want := rr.Replacer.Replace("{geoip_country_geoname_id}"), "146669"; got != want {
 		t.Errorf("Expected custom placeholder {geoip_country_geoname_id} to be set (%s), but it wasn't; got: %s", want, got)
 	}
+
+	//
+	// Verify that a request via the loopback interface address results in
+	// the expected placeholder values.
+	//
+	var loopback_placeholders = [][2]string{
+		{"{geoip_country_code}", "**"},
+		{"{geoip_country_name}", "Loopback"},
+		{"{geoip_city_name}", "Loopback"},
+		{"{geoip_country_geoname_id}", "0"},
+		{"{geoip_city_geoname_id}", "0"},
+		{"{geoip_latitude}", "0.000000"},
+		{"{geoip_longitude}", "0.000000"},
+		{"{geoip_geohash}", "s00000000000"},
+		{"{geoip_time_zone}", ""},
+	}
+
+	r = httptest.NewRequest("GET", "/", strings.NewReader(""))
+	r.RemoteAddr = "127.0.0.1"
+	rr = httpserver.NewResponseRecorder(testResponseRecorder{
+		ResponseWriterWrapper: &httpserver.ResponseWriterWrapper{ResponseWriter: httptest.NewRecorder()},
+	})
+
+	rr.Replacer = httpserver.NewReplacer(r, rr, "-")
+
+	l.ServeHTTP(rr, r)
+
+	for _, v := range loopback_placeholders {
+		if got, want := rr.Replacer.Replace(v[0]), v[1]; got != want {
+			t.Errorf("Expected custom placeholder %s to be set (%s), but it wasn't; got: %s", v[0], want, got)
+		}
+	}
+
+	//
+	// Verify that a request via a private address results in the expected
+	// placeholder values. Note that the MaxMind DB doesn't include
+	// location data for private addresses.
+	//
+	var private_addr_placeholders = [][2]string{
+		{"{geoip_country_code}", "!!"},
+		{"{geoip_country_name}", "No Country"},
+		{"{geoip_city_name}", "No City"},
+		{"{geoip_country_geoname_id}", "0"},
+		{"{geoip_city_geoname_id}", "0"},
+		{"{geoip_latitude}", "0.000000"},
+		{"{geoip_longitude}", "0.000000"},
+		{"{geoip_geohash}", "s00000000000"},
+		{"{geoip_time_zone}", ""},
+	}
+
+	r = httptest.NewRequest("GET", "/", strings.NewReader(""))
+	r.RemoteAddr = "192.168.0.1"
+	rr = httpserver.NewResponseRecorder(testResponseRecorder{
+		ResponseWriterWrapper: &httpserver.ResponseWriterWrapper{ResponseWriter: httptest.NewRecorder()},
+	})
+
+	rr.Replacer = httpserver.NewReplacer(r, rr, "-")
+
+	l.ServeHTTP(rr, r)
+
+	if got, want := rr.Replacer.Replace("{geoip_country_code}"), "!!"; got != want {
+		t.Errorf("Expected custom placeholder {geoip_country_code} to be set (%s), but it wasn't; got: %s", want, got)
+	}
+
+	for _, v := range private_addr_placeholders {
+		if got, want := rr.Replacer.Replace(v[0]), v[1]; got != want {
+			t.Errorf("Expected custom placeholder %s to be set (%s), but it wasn't; got: %s", v[0], want, got)
+		}
+	}
 }