Example #1
0
func makeHandler() http.HandlerFunc {
	db, err := sql.Open("sqlite3", databaseFile)
	if err != nil {
		panic(err)
	}
	mc := memcache.New(memcacheServer)
	return func(w http.ResponseWriter, req *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		req.RemoteAddr = trimPort(req.RemoteAddr)
		// Check quota
		el, err := mc.Get(req.RemoteAddr)
		if err == memcache.ErrCacheMiss {
			err = mc.Set(&memcache.Item{
				Key: req.RemoteAddr, Value: []byte("1"),
				Expiration: expirySeconds})
		}
		if err != nil {
			// Service Unavailable
			if debug {
				log.Println("[debug] memcache", err.Error())
			}
			http.Error(w, http.StatusText(503), 503)
			return
		}
		if el != nil {
			count, _ := strconv.Atoi(string(el.Value))
			if count < maxRequestsPerIP {
				mc.Increment(req.RemoteAddr, 1)
			} else {
				// Out of quota
				http.Error(w, http.StatusText(403), 403)
				return
			}
		}
		Lookup(w, req, db)
	}
}
Example #2
0
func Lookup(w http.ResponseWriter, req *http.Request, db *sql.DB) {
	format, addr := req.Vars[0], req.Vars[1]
	if addr == "" {
		addr = req.RemoteAddr // port number previously removed
	} else {
		addrs, err := net.LookupHost(addr)
		if err != nil {
			http.Error(w, http.StatusText(404), 404)
			return
		}
		addr = addrs[0]
	}
	IP := net.ParseIP(addr)
	reserved := false
	for _, net := range reservedIPs {
		if net.Contains(IP) {
			reserved = true
			break
		}
	}
	geoip := GeoIP{Ip: addr}
	if reserved {
		geoip.CountryCode = "RD"
		geoip.CountryName = "Reserved"
	} else {
		q := "SELECT " +
			"  city_location.country_code, country_blocks.country_name, " +
			"  city_location.region_code, region_names.region_name, " +
			"  city_location.city_name, city_location.postal_code, " +
			"  city_location.latitude, city_location.longitude, " +
			"  city_location.metro_code, city_location.area_code " +
			"FROM city_blocks " +
			"  NATURAL JOIN city_location " +
			"  INNER JOIN country_blocks ON " +
			"    city_location.country_code = country_blocks.country_code " +
			"  INNER JOIN region_names ON " +
			"    city_location.country_code = region_names.country_code " +
			"    AND " +
			"    city_location.region_code = region_names.region_code " +
			"WHERE city_blocks.ip_start <= ? " +
			"ORDER BY city_blocks.ip_start DESC LIMIT 1"
		stmt, err := db.Prepare(q)
		if err != nil {
			if debug {
				log.Println("[debug] SQLite", err.Error())
			}
			http.Error(w, http.StatusText(500), 500)
			return
		}
		defer stmt.Close()
		var uintIP uint32
		b := bytes.NewBuffer(IP.To4())
		binary.Read(b, binary.BigEndian, &uintIP)
		err = stmt.QueryRow(uintIP).Scan(
			&geoip.CountryCode,
			&geoip.CountryName,
			&geoip.RegionCode,
			&geoip.RegionName,
			&geoip.CityName,
			&geoip.ZipCode,
			&geoip.Latitude,
			&geoip.Longitude,
			&geoip.MetroCode,
			&geoip.AreaCode)
		if err != nil {
			http.Error(w, http.StatusText(404), 404)
			return
		}
	}
	switch format[0] {
	case 'c':
		w.Header().Set("Content-Type", "application/csv")
		fmt.Fprintf(w, `"%s","%s","%s","%s","%s","%s",`+
			`"%s","%0.4f","%0.4f","%s","%s"`+"\r\n",
			geoip.Ip,
			geoip.CountryCode, geoip.CountryName,
			geoip.RegionCode, geoip.RegionName,
			geoip.CityName, geoip.ZipCode,
			geoip.Latitude, geoip.Longitude,
			geoip.MetroCode, geoip.AreaCode)
	case 'j':
		resp, err := json.Marshal(geoip)
		if err != nil {
			if debug {
				log.Println("[debug] JSON", err.Error())
			}
			http.Error(w, http.StatusText(404), 404)
			return
		}
		callback := req.FormValue("callback")
		if callback != "" {
			w.Header().Set("Content-Type", "text/javascript")
			fmt.Fprintf(w, "%s(%s);\n", callback, resp)
		} else {
			w.Header().Set("Content-Type", "application/json")
			fmt.Fprintf(w, "%s\n", resp)
		}
	case 'x':
		w.Header().Set("Content-Type", "application/xml")
		resp, err := xml.MarshalIndent(geoip, "", " ")
		if err != nil {
			if debug {
				log.Println("[debug] XML", err.Error())
			}
			http.Error(w, http.StatusText(500), 500)
			return
		}
		fmt.Fprintf(w, xml.Header+"%s\n", resp)
	}
}