Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PMTiles.io demo site fails in Safari Browser running iOS 15.5 in a Simulator #497

Open
roblabs opened this issue Nov 21, 2024 · 6 comments

Comments

@roblabs
Copy link
Contributor

roblabs commented Nov 21, 2024

Issue

While navigating to https://pmtiles.io on very old Safari on iOS versions, the PMTiles demo page does not work.

Background

While randomly testing one of the National Park Service pages that makes use of PMTiles, we found that the PMTiles data was not getting rendered on an iOS 15.5 simulator. Safari on iOS 18.1 simulators & Safari running macOS work fine.


Steps to Reproduce

This is reproducible outside of the NPS infrastructure:

  1. In Xcode, configure & launch simulator running iOS 15
  2. Go to https://pmtiles.io
  3. Pick the first demo PMTiles from the list
  4. Error as in Figure 1
  5. You should also test Raster data from the list of sample PMTiles

Safari Inspector to the Simulators browser shows this error:

[Error] Preflight response is not successful. Status code: 403
[Error] Fetch API cannot load https://demo-bucket.protomaps.com/v4.pmtiles due to access control checks.
[Error] Failed to load resource: Preflight response is not successful. Status code: 403 (v4.pmtiles, line 0)
[Error] Unhandled Promise Rejection: TypeError: Load failed. (anonymous function) (mapview.1000a05f.js:646:904675)


Figure 1: Screen capture of iOS 15.5 at the https://pmtiles.io site
image


Notes
Our PMTiles file, canmex.pmtiles, is served via our NPS fleet of servers.
We use CanMex as a way to gray out non-US states & territories, as in Figure 2

Figure 2: CanMex grays out other countries
image

@roblabs
Copy link
Contributor Author

roblabs commented Nov 21, 2024

I normally would consider this a "don't care". I am looking out for any other issues with the PMTiles stack (pmtiles generation, data, server, etc etc)


Yes, iOS 15.5 is old. See https://developer.apple.com/support/app-store for the latest data on "iOS and iPadOS usage".

@bdon
Copy link
Member

bdon commented Nov 21, 2024

Confirmed I can reproduce in BrowerStack on iOS 15 and a different failure mode 16, for the specific backend demo-bucket.protomaps.com ; others seem to work

@bdon
Copy link
Member

bdon commented Nov 25, 2024

I can reproduce this in local simulator on iOS 15, but have not found a root cause. The failure on demo-bucket.protomaps.com might be specific to the S3-like provider used (http://tigrisdata.com), since other S3 buckets work fine. What storage provider is used for the NPS .pmtiles files that are failing?

@jimmyrocks
Copy link

The pmtiles file that @roblabs is testing is runing from an NGINX server with the following config:

 # Location for PMTiles
  location ~* /pmtiles {

    # Reject users the pull the file without specifying the range
    if ($range_present = 0) {
      return 403;
    }

    # Path to the directory where PMTiles files are stored
    root /mnt;

    # Enable CORS
    add_header 'Access-Control-Allow-Origin' '*' always;
    add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always;
    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

    # Handle HTTP OPTIONS request for CORS preflight
    if ($request_method = 'OPTIONS') {
      add_header 'Access-Control-Max-Age' 1728000;
      add_header 'Content-Type' 'text/plain charset=UTF-8';
      add_header 'Content-Length' 0;
      return 204;
    }


    # Support for Range headers
    add_header 'Accept-Ranges' 'bytes';

    # Specify the type of files
    types { application/x-protobuf pmtiles; }

    add_header 'Cache-Control' 'max-age=43200';
  }

@bdon
Copy link
Member

bdon commented Dec 20, 2024

In your nginx config can you try duplicating these two lines:

add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;

Inside the preflight block, e.g.:

if ($request_method = 'OPTIONS') {
      add_header 'Access-Control-Max-Age' 1728000;
      add_header 'Content-Type' 'text/plain charset=UTF-8';
      add_header 'Access-Control-Allow-Origin' '*' always;
      add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
      add_header 'Content-Length' 0;
      return 204;
    }

The core issue here seems to be that iOS 16+ Safari considers Range a safe listed header for CORS and does not issue an OPTIONS preflight request first, which is part of the current spec, but iOS 15 may predate this so always issues an OPTIONS first.

Edit: see https://www.getpagespeed.com/server-setup/nginx/the-pitfalls-of-add_header-in-nginx-solving-inheritance-issues-with-more_set_headers/amp for explanation

@bdon
Copy link
Member

bdon commented Dec 20, 2024

The demo URL that was broken before on iOS 15 and 16 (https://pmtiles.io/?url=https%3A%2F%2Fdemo-bucket.protomaps.com%2Fv4.pmtiles#map=0.5/0/0) should now be working. This was also related to CORS misconfiguration since iOS 15 and 16 send a preflight request. TODO: improve docs about CORS preflighting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants