github.com/m-lab/locate@v0.17.6/clientgeo/user.go (about) 1 package clientgeo 2 3 import ( 4 "context" 5 "errors" 6 "math" 7 "net/http" 8 "strconv" 9 10 "github.com/m-lab/locate/static" 11 ) 12 13 // UserLocator definition for accepting user provided location hints. 14 type UserLocator struct{} 15 16 // Error values returned by Locate. 17 var ( 18 ErrNoUserParameters = errors.New("no user location parameters provided") 19 ErrUnusableUserParameters = errors.New("user provided location parameters were unusable") 20 ) 21 22 // NewUserLocator creates a new UserLocator. 23 func NewUserLocator() *UserLocator { 24 return &UserLocator{} 25 } 26 27 // Locate looks for user-provided parameters to specify the client location. 28 func (u *UserLocator) Locate(req *http.Request) (*Location, error) { 29 lat := req.URL.Query().Get("lat") 30 lon := req.URL.Query().Get("lon") 31 if lat != "" && lon != "" { 32 // Verify that these are valid floating values. 33 flat, errLat := strconv.ParseFloat(lat, 64) 34 flon, errLon := strconv.ParseFloat(lon, 64) 35 if errLat != nil || errLon != nil || 36 math.IsNaN(flat) || math.IsInf(flat, 0) || 37 math.IsNaN(flon) || math.IsInf(flon, 0) || 38 -90 > flat || flat > 90 || 39 -180 > flon || flon > 180 { 40 return nil, ErrUnusableUserParameters 41 } 42 loc := &Location{ 43 Latitude: lat, 44 Longitude: lon, 45 Headers: http.Header{}, 46 } 47 loc.Headers.Set(hLocateClientlatlon, lat+","+lon) 48 loc.Headers.Set(hLocateClientlatlonMethod, "user-latlon") 49 return loc, nil 50 } 51 if ll, ok := static.Regions[req.URL.Query().Get("region")]; ok { 52 loc, err := splitLatLon(ll) 53 loc.Headers.Set(hLocateClientlatlon, ll) 54 loc.Headers.Set(hLocateClientlatlonMethod, "user-region") 55 return loc, err 56 } 57 58 // If the user requested a specific country without strict=true, set the 59 // lat/lon to the geographic center of that country. If the user requested 60 // a specific country with strict=true, keep lat/lon as it is. 61 if ll, ok := static.Countries[req.URL.Query().Get("country")]; ok && 62 req.URL.Query().Get("strict") != "true" { 63 loc, err := splitLatLon(ll) 64 loc.Headers.Set(hLocateClientlatlon, ll) 65 loc.Headers.Set(hLocateClientlatlonMethod, "user-country") 66 return loc, err 67 } 68 return nil, ErrNoUserParameters 69 } 70 71 // Reload does nothing. 72 func (u *UserLocator) Reload(ctx context.Context) {}