Class: Trackdown::Providers::CloudfrontProvider

Inherits:
BaseProvider
  • Object
show all
Defined in:
lib/trackdown/providers/cloudfront_provider.rb

Overview

Provider that uses Amazon CloudFront HTTP headers for IP geolocation. This is the fastest and most lightweight option when your app is behind CloudFront (the AWS CDN) — a direct analog to the Cloudflare provider.

CloudFront resolves the viewer's location at the edge and forwards it to the origin as CloudFront-Viewer-* headers. To receive them, attach an origin request policy that forwards the CloudFront geolocation headers.

Exact AWS viewer-location header contract (names, availability, encoding): https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/adding-cloudfront-headers.html#cloudfront-headers-viewer-location Exact AWS managed-policy contents: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html#managed-origin-request-policy-all-viewer-and-cloudfront

IMPORTANT: Header presence does not authenticate CloudFront. A custom origin must reject direct traffic before an application can trust these values. AWS's exact origin-restriction guidance is: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-overview.html

Note: CloudFront does not emit a continent header. We derive #continent from the country code so it matches the 2-letter code (e.g. "NA") the other providers return. The countries gem exposes a continent name ("North America") but no code, and its names don't map by initials (Africa/Asia/Antarctica/Australia all start with "A", and it labels Oceania "Australia"), so an explicit table is the only reliable mapping.

Constant Summary collapse

CONTINENT_CODES =

ISO3166 continent name (from the countries gem) => 2-letter code used by the Cloudflare and MaxMind providers. countries gem source: https://github.com/countries/countries

{
  'Africa' => 'AF',
  'Antarctica' => 'AN',
  'Asia' => 'AS',
  'Europe' => 'EU',
  'North America' => 'NA',
  'South America' => 'SA',
  'Australia' => 'OC' # the countries gem labels Oceania "Australia"
}.freeze
COUNTRY_HEADER =

Rack exposes ordinary HTTP request headers as HTTP_* environment entries: https://github.com/rack/rack/blob/main/SPEC.rdoc#http_-headers

'HTTP_CLOUDFRONT_VIEWER_COUNTRY'
CITY_HEADER =
'HTTP_CLOUDFRONT_VIEWER_CITY'
REGION_HEADER =

CloudFront exposes both a region code ("CA") and its full name ("California"). Match the Cloudflare provider's semantics: #region is the name, #region_code the code.

'HTTP_CLOUDFRONT_VIEWER_COUNTRY_REGION_NAME'
REGION_CODE_HEADER =
'HTTP_CLOUDFRONT_VIEWER_COUNTRY_REGION'
LATITUDE_HEADER =
'HTTP_CLOUDFRONT_VIEWER_LATITUDE'
LONGITUDE_HEADER =
'HTTP_CLOUDFRONT_VIEWER_LONGITUDE'
TIMEZONE_HEADER =
'HTTP_CLOUDFRONT_VIEWER_TIME_ZONE'
POSTAL_CODE_HEADER =
'HTTP_CLOUDFRONT_VIEWER_POSTAL_CODE'
METRO_CODE_HEADER =
'HTTP_CLOUDFRONT_VIEWER_METRO_CODE'

Class Method Summary collapse

Methods inherited from BaseProvider

get_country_name, get_emoji_flag, parse_coordinate, request_provenance

Class Method Details

.available?(request: nil) ⇒ Boolean

Check if CloudFront headers are available in the request

Returns:

  • (Boolean)


84
85
86
87
88
# File 'lib/trackdown/providers/cloudfront_provider.rb', line 84

def available?(request: nil)
  return false unless request

  !extract_country_code(request).nil?
end

.locate(_ip, request: nil) ⇒ LocationResult

Locate IP using CloudFront headers

Parameters:

  • ip (String)

    The IP address (not used, as CloudFront already resolved it)

  • request (#env) (defaults to: nil)

    Rack-compatible request object with CloudFront headers

Returns:

Raises:



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/trackdown/providers/cloudfront_provider.rb', line 94

def locate(_ip, request: nil)
  raise Trackdown::Error, 'CloudfrontProvider requires a request object with CloudFront headers' unless request

  provenance = request_provenance(request)
  country_code = extract_country_code(request)

  # If no valid country code, return unknown
  return LocationResult.unavailable(:provider_returned_unknown_country, **provenance) if country_code.nil?

  build_location_result(country_code, request, **provenance)
end

.provider_nameObject



75
76
77
# File 'lib/trackdown/providers/cloudfront_provider.rb', line 75

def provider_name
  :cloudfront
end

.provider_sourceObject



79
80
81
# File 'lib/trackdown/providers/cloudfront_provider.rb', line 79

def provider_source
  :cloudfront_request_headers
end