fix(slicer): encode file URL in protocol-handler scheme on Windows/Linux

"Open in Slicer" emitted `orcaslicer://open?file=<URL>` and
  `bambustudio://open?file=<URL>` by plain string concatenation, relying
  on a stale comment that claimed the browser preserves URLs in the query
  string. That ignores the slicer's own `url_decode()` on the received
  query (BS post_init → url_decode + split_str; OrcaSlicer Downloader
  regex + url_decode), so any already-percent-encoded character — most
  commonly `%20` from filenames with spaces — decoded to a literal space
  and the slicer's subsequent HTTP GET returned 0 bytes or 404.

  All three URL forms now use `encodeURIComponent()` (matching what the
  macOS `bambustudioopen://` branch was already doing, which is why the
  bug didn't surface on macOS). Corrected the file-level comment to
  document the actual invariant.

  Regression test in slicer.test.ts feeds the exact issue reproduction
  URL and asserts `%2520` appears in the generated href.
This commit is contained in:
maziggy
2026-04-23 10:03:44 +02:00
parent 62f2e616a0
commit 76b997fc8a
5 changed files with 25 additions and 18 deletions
+11 -6
View File
@@ -51,7 +51,7 @@ describe('slicer utility', () => {
expect(appendSpy).toHaveBeenCalled();
expect(createdLink.href).toContain('bambustudio://open?file=');
expect(createdLink.href).toContain('http://localhost:8000/file.3mf');
expect(createdLink.href).toContain(encodeURIComponent('http://localhost:8000/file.3mf'));
expect(clickSpy).toHaveBeenCalled();
expect(removeSpy).toHaveBeenCalled();
});
@@ -78,15 +78,20 @@ describe('slicer utility', () => {
expect(createdLink.href).toContain('open?file=');
});
it('does not encode the file URL for orcaslicer', () => {
it('encodes filenames with spaces so the slicer receives %20 after url_decode (issue #1059)', () => {
vi.spyOn(navigator, 'userAgent', 'get').mockReturnValue('Mozilla/5.0 (Windows NT 10.0)');
const url = 'http://localhost:8000/api/v1/archives/1/file/My Model.3mf';
// A download URL that already contains percent-encoded spaces — this is how
// Bambuddy emits archive paths (the filename in the URL is URL-path-encoded).
const url = 'http://localhost:8000/api/v1/archives/1/dl/TOKEN/Toothpick%20Launcher%20Print-in-Place.3mf';
openInSlicer(url, 'orcaslicer');
// The href should contain the raw URL (browser may normalize it but it should not be double-encoded)
// Each %20 in the input must become %2520 in the href so that after the
// slicer's own url_decode() it comes back as %20 (preserving the original
// URL). Without this, the slicer would decode %20 → literal space and its
// subsequent HTTP fetch would fail.
expect(createdLink.href).toContain('orcaslicer://open?file=');
// Should NOT contain %253A (double-encoded colon)
expect(createdLink.href).not.toContain('%253A');
expect(createdLink.href).toContain('Toothpick%2520Launcher%2520Print-in-Place.3mf');
expect(createdLink.href).not.toContain('Toothpick%20Launcher');
});
it('defaults to bambu_studio when no slicer specified', () => {