fix(places): unblock MapLibre worker and fix false-positive basemap probe

Two issues kept the Photos → Places map blank once the SPA could boot:

- CSP `worker-src 'self'` blocked MapLibre GL, which spawns its web worker
  from a blob: URL, so the map never constructed. Allow `worker-src
  'self' blob:` ('self' still covers same-origin workers like delta-upload).

- `checkBasemap()` trusted `res.ok`, but the SPA fallback serves index.html
  (HTTP 200, text/html) for any missing path — so a missing basemap.pmtiles
  read as "present", and pmtiles.js then choked on HTML ("Wrong magic
  number for PMTiles archive"). Reject text/html responses so an absent
  basemap falls back cleanly to the themed blank style.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DioCrafts
2026-06-19 21:04:56 +02:00
parent 824ca03ad4
commit 5ccceb463a
2 changed files with 10 additions and 2 deletions
+6 -1
View File
@@ -51,7 +51,12 @@
if (hasBasemap !== null) return hasBasemap;
try {
const res = await fetch(BASEMAP_URL, { headers: { Range: 'bytes=0-0' } });
hasBasemap = res.ok; // 200/206 = present, 404 = absent
// The SPA fallback serves index.html (HTTP 200, text/html) for any
// missing path, so `res.ok` alone can't distinguish "basemap present"
// from "absent". A real .pmtiles is binary (octet-stream); the shell
// is HTML — treat an HTML body as "no basemap" and fall back cleanly.
const type = res.headers.get('Content-Type') ?? '';
hasBasemap = res.ok && !type.toLowerCase().includes('text/html');
} catch {
hasBasemap = false;
}
+4 -1
View File
@@ -97,6 +97,9 @@ pub fn create_web_routes() -> Router<Arc<AppState>> {
/// (`element.style.*`) for UI state — impractical to migrate to classes.
/// - `frame-src` lists `blob:` explicitly (`*` only matches network schemes) for
/// inline PDF/document viewers; `media-src` lists `blob:` for blob video/audio.
/// - `worker-src` lists `blob:` because MapLibre GL (the Places map) spawns its
/// web worker from a blob URL; `'self'` covers same-origin workers like the
/// delta-upload worker.
pub fn content_security_policy(config: &AppConfig) -> String {
let static_path = resolve_static_path(config);
let hashes = inline_script_csp_hashes(&static_path);
@@ -118,7 +121,7 @@ pub fn content_security_policy(config: &AppConfig) -> String {
format!(
"default-src 'self'; \
{script_src}; \
worker-src 'self'; \
worker-src 'self' blob:; \
style-src 'self' 'unsafe-inline'; \
img-src 'self' data: blob: https:; \
media-src 'self' blob:; \