Skip to content

Load the Maps API over https rather than protocol-relative - #8

Merged
LukeTowers merged 1 commit into
mainfrom
fix/addressfinder-protocol-relative-maps-url
Sep 7, 2026
Merged

LukeTowers merged 1 commit into
mainfrom
fix/addressfinder-protocol-relative-maps-url

Conversation

@LukeTowers

@LukeTowers LukeTowers commented Sep 7, 2026 •

Copy link
Copy Markdown
Member

Summary

AddressFinder::loadAssets() registers the Google Maps API with a protocol-relative URL:

$this->addJs('//maps.googleapis.com/maps/api/js?libraries=places&key='.$apiKey);

Snowboard's Url utility doesn't recognise that form. Both to() and asset() test for an explicit scheme and, when the URL doesn't match, strip every leading slash before resolving what's left against the site:

const urlRegex = /^(?:[^:]+:\/\/)[-a-z0-9@:%._+~#=]{1,256}\b([-a-z0-9()@:%_+.~#?&//=]*)/i;

if (url.match(urlRegex)) {
    return url;
}

const theUrl = url.replace(/^\/+/, '');

return `${this.assetUrl()}${theUrl}`;

So the browser requests https://<site>/maps.googleapis.com/maps/api/js?… and gets a 404.

Why it isn't noticed on a page load

AssetMaker::getAssetPath() and getAssetScheme() both pass protocol-relative URLs through untouched, so a full render emits a working <script src="//maps.googleapis.com/…">. The break only happens when the same asset arrives via X_WINTER_ASSETS and is loaded by AssetLoader.loadScript() — i.e. on any AJAX request made from a backend form containing an AddressFinder.

The symptom is worse than a missing script. loadScript() rejects its promise when the script errors, and handleUpdateResponse() awaits it, so the AJAX handler never completes. I ran into this through LukeTowers.EasyAudit, where opening an audit log entry left the popup spinning forever with nothing but the 404 in the console to go on.

The change

Requests the scheme explicitly. It costs nothing — the Maps API only serves over https anyway — and it's the smaller of the two fixes.

The underlying Url behaviour is reported separately as wintercms/winter#1538, since a protocol-relative URL is valid and shouldn't be silently rewritten into a same-origin path. That fix belongs in core; this one unblocks the plugin in the meantime and remains correct either way.

Version bumped to 2.2.2 (patch — a bug fix, no API or behaviour change).

Testing

Verified against a Winter 1.2.12 backend form containing an AddressFinder: before the change the AJAX request for the widget's assets resolved to https://<site>/maps.googleapis.com/… and 404'd, leaving the handler's response unapplied; after it, the asset loads from maps.googleapis.com and the handler completes. Confirmed the widget is the only protocol-relative asset in the plugin.

🤖 Generated with Claude Code

https://claude.ai/code/session_018icgbPJpBGE4wCuDGxsKjE

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where the Google Maps Places API could fail to load when the AddressFinder widget was rendered through AJAX.
    • AddressFinder now consistently loads the Maps API over a secure HTTPS connection, improving reliability when entering or selecting addresses.
  • Documentation

    • Updated the version history to record the fix in release 2.2.2.

Snowboard's Url utility does not recognise protocol-relative URLs: both
to() and asset() test the URL against a regex requiring an explicit
scheme and, when it does not match, strip every leading slash before
resolving the remainder against the site. So the Maps API ends up being
requested from https://<site>/maps.googleapis.com/maps/api/js, which
404s.

A normal page render is unaffected, since AssetMaker passes protocol-
relative URLs through untouched. It only breaks once the asset is
injected over AJAX and goes through AssetLoader.loadScript(), which is
every AJAX request made on a backend form carrying an AddressFinder.

The result is worse than a missing script: loadScript() rejects its
promise when the script errors and handleUpdateResponse() awaits it, so
the handler never completes and the interface waits indefinitely with
nothing but a 404 in the console to explain it.

Requesting the scheme explicitly sidesteps this, and costs nothing: the
Maps API only serves https regardless. The underlying Url behaviour is
reported separately as wintercms/winter#1538.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018icgbPJpBGE4wCuDGxsKjE
@coderabbitai

coderabbitai Bot commented Sep 7, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 4772cb53-efe4-4797-83c5-d72ab9f9b049

📥 Commits

Reviewing files that changed from the base of the PR and between 5d07ce8 and 39a7a8e.

📒 Files selected for processing (2)
  • formwidgets/AddressFinder.php
  • updates/version.yaml

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

The Google Maps API asset URL in AddressFinder::loadAssets() now uses HTTPS. The version history adds release 2.2.2 and documents the AJAX rendering fix.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Merge Risk: ⚪ Minimal · up to 39a7a

AddressFinder now loads the Google Maps API via HTTPS during AJAX rendering, preventing the same-origin asset rewrite that blocked autocomplete and form handling. The focused change is ready to merge.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: loading the Maps API over HTTPS instead of using a protocol-relative URL.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 1 files. (1 skipped: 1 …
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/addressfinder-protocol-relative-maps-url

Warning

Some tools did not complete. Review the errors below.

🔧 PHPStan (2.2.8)

Composer install failed: dependency resolution error. Check composer.json and composer.lock for version constraints.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@LukeTowers
LukeTowers merged commit f8d3aa4 into main Sep 7, 2026
5 checks passed
@LukeTowers
LukeTowers deleted the fix/addressfinder-protocol-relative-maps-url branch September 7, 2026 06:58
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

Successfully merging this pull request may close these issues.

1 participant