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) {}