Skip to content

Treat server-relative paths as relative in IsAbsoluteUrl on Linux/macOS - #24

Merged
gatisb merged 5 commits into
masterfrom
fix/is-absolute-url-unix-paths
Sep 29, 2026
Merged

gatisb merged 5 commits into
masterfrom
fix/is-absolute-url-unix-paths

Conversation

@gatisb

@gatisb gatisb commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Problem

On Linux and macOS, Uri.TryCreate(url, UriKind.Absolute, out _) accepts a rooted path such as /page?id=1 as an implicit file URI (file:///page%3Fid=1). So IsAbsoluteUrl("/page") returns true there, while it returns false on Windows.

The existing IsAbsoluteUrl_with_relative_url_is_false cases (/mypage, /mypage/anotherpage) already expect false. They only pass because CI runs on windows-latest.

Downstream impact: Geta.Optimizely.Extensions' RemoveHost(), which every GetFriendlyUrl() goes through, does if (url.IsAbsoluteUrl()) return new Uri(url).PathAndQuery;. On Linux this turns a relative URL with a query string into one with %3F in its path. For example, the Optimizely On-Page Editing URL /…,,123?epieditmode=true becomes /…,,123%3Fepieditmode=true, and the CMS returns HTTP 500. We hit this on a CMS 12 site hosted on Linux App Service.

RemoveHost delegates to this method, so a Geta.Net.Extensions patch fixes both Geta.Optimizely.Extensions 2.x (CMS 12) and 3.x (CMS 13) without a new release of that package.

Change

  • IsAbsoluteUrl now returns false for server-relative paths: a single leading / that Uri parsed as a file URI. On Windows this changes nothing, because TryCreate already rejects such paths.
  • //host/path (UNC or network-path reference) and explicit file: URIs behave as before.
  • IsRelativeUrl needs no change. UriKind.Relative treats /page as relative on every OS.
  • Tests: added cases for /, /mypage?query=1 and an edit-mode-style URL, plus checks that https://…?query=1 and file:///… stay absolute.
  • CI (separate commits):
    • A Test (Linux) job on ubuntu-latest, installing .NET 6 via setup-dotnet for the net6.0 test project. The existing tests would have caught this bug. Drop the commit if you'd rather not have it.
    • The Windows Build job first failed in "Set up job", because GitHub no longer serves actions/cache@v1.
      • With the actions updated, it failed next in the SonarCloud step. SONAR_TOKEN (set in 2022) no longer authenticates, and the Geta_geta-dotnet-extensions project is gone from the geta SonarCloud organization.
      • So the job now just builds and runs the tests on Windows. It installs the .NET 6 runtime that windows-latest no longer ships.
      • The stale Quality Gate badge is removed from the README.
    • Both jobs use the current Node 24 majors (actions/checkout@v7, actions/setup-dotnet@v6).
    • release.yml had the same gap: its Test step would have failed on a tag build without the .NET 6 runtime. It now installs .NET 6 and uses actions/checkout@v7.
      • It only runs on tag pushes, so it's untested in CI.
      • Its build, test and pack commands pass locally with the current SDK: 67/67 tests, and Geta.Net.Extensions.<version>.nupkg is created.
  • CHANGELOG: added a [3.0.2] entry. I suggest releasing this as v3.0.2.

Testing

  • dotnet test on Windows: 67/67 pass. The new relative-path cases also pass on Windows without the fix, because only Unix is affected.
  • The Test (Linux) job covers the Unix behaviour.

Notes

  • SonarCloud: the SONAR_TOKEN repository secret is now unused, so a repo admin can delete it.
    • To bring the analysis back: re-import the project in SonarCloud, add a fresh token, and restore the analysis steps.
    • Commit 9316ffe has an updated version of those steps (JDK 17, sonar.token) that got as far as authentication.
  • Noticed but not changed: IsRelativeUrl_with_invalid_url_is_false calls IsAbsoluteUrl() instead of IsRelativeUrl(). Note that "".IsRelativeUrl() actually returns true.

🤖 Generated with Claude Code

gatisb and others added 2 commits September 28, 2026 15:11
On Linux and macOS, Uri.TryCreate(url, UriKind.Absolute, ...) accepts a
rooted path such as "/page?id=1" as an implicit file URI
(file:///page%3Fid=1), so IsAbsoluteUrl returned true there while
Windows returns false. The existing IsAbsoluteUrl_with_relative_url_is_false
cases ("/mypage", "/mypage/anotherpage") only passed because CI runs on
Windows.

Geta.Optimizely.Extensions' RemoveHost relies on IsAbsoluteUrl and then
returns new Uri(url).PathAndQuery, which escapes the '?' to %3F. On
Linux hosting that breaks every GetFriendlyUrl() result that carries a
query string, e.g. Optimizely On-Page Editing URLs
(",,123?epieditmode=true" becomes ",,123%3Fepieditmode=true", HTTP 500).

"//host/path" and explicit file: URIs keep their current behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Uri parsing is OS-dependent, and the IsAbsoluteUrl bug fixed in the
previous commit went unnoticed because CI only ran on windows-latest.
The new job is independent of the Windows build and SonarCloud job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gatisb
gatisb marked this pull request as ready for review September 28, 2026 12:29
gatisb and others added 3 commits September 29, 2026 10:27
The job failed while setting up, because GitHub no longer serves
actions/cache@v1. Move to actions/cache@v4 and actions/checkout@v4,
and to actions/setup-java@v4 with JDK 17: the SonarCloud scanner no
longer runs on Java 11. Install the .NET 6 runtime that the net6.0 test
project needs, which windows-latest no longer ships, and pass the token
as sonar.token instead of the deprecated sonar.login.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SONAR_TOKEN no longer authenticates ("Authentication with the server
has failed"), and the Geta_geta-dotnet-extensions project is gone from
the geta SonarCloud organization, so the analysis failed on every run.
The job now just builds and runs the tests on Windows, and the stale
Quality Gate badge is removed from the README.

Also move both jobs to the current Node 24 majors (checkout v7,
setup-dotnet v6); the v4 actions are deprecated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
windows-latest no longer ships the .NET 6 runtime that the net6.0 test
project runs on, so a tag build would fail at its Test step. Also move
to actions/checkout@v7, the current Node 24 major.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gatisb
gatisb merged commit 6bcc03c into master Sep 29, 2026
2 checks passed
@gatisb
gatisb deleted the fix/is-absolute-url-unix-paths branch September 29, 2026 08:33
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.

2 participants