Skip to content

fix(uri): keep a trailing slash on the base URL so proxied sub-paths survive - #356

Open
OsamaAnsar wants to merge 1 commit into
tursodatabase:mainfrom
OsamaAnsar:fix/http-base-url-drops-last-path-segment
Open

fix(uri): keep a trailing slash on the base URL so proxied sub-paths survive#356
OsamaAnsar wants to merge 1 commit into
tursodatabase:mainfrom
OsamaAnsar:fix/http-base-url-drops-last-path-segment

Conversation

@OsamaAnsar

Copy link
Copy Markdown

Problem

Closes #296.

When a client is pointed at a libSQL server hosted behind a reverse proxy on a
sub-path, the last path segment is silently dropped from every request:

createClient({ url: "libsql://example.com/some/sub/path" });
// requests go to  https://example.com/some/sub/v2/pipeline
// expected        https://example.com/some/sub/path/v2/pipeline

The reporter's workaround — appending a trailing / to the URL — is the clue to
the cause.

Cause

encodeBaseUrl builds the base URL with no trailing slash on the path
(https://example.com/some/sub/path). The Hrana client then resolves each
endpoint against it:

new URL(endpoint.pipelinePath /* "v2/pipeline" */, baseUrl);

Per the WHATWG URL resolver, a relative reference resolved against a base whose
path does not end in / replaces the base's last segment. So path is
dropped and v2/pipeline takes its place.

Fix

encodeBaseUrl now appends a trailing slash to a non-empty path, so the base URL
is safe for relative resolution.

  • "" and "/" are unchanged (the common Turso Cloud case,
    libsql://db-org.turso.io, is unaffected).
  • wss: / ws: callers receive the same normalized URL. The Hrana WebSocket
    handshake connects to the URL directly and isn't sensitive to the trailing
    slash, so this is a no-op there; a directory-style base is also the correct
    shape for a proxied WS deployment.

Tests

packages/libsql-client/src/__tests__/uri.test.ts:

  • Updated the three encodeBaseUrl() cases that carry a path to expect the
    trailing slash.
  • Added a regression test that resolves v2/pipeline and v3-protobuf/pipeline
    against the encoded base and asserts the full sub-path is preserved, plus the
    root case still resolves to /v2/pipeline.

npx jest --runInBand uri config — green (uri 10, config 23). tsc --noEmit
clean for @libsql/core and @libsql/client.

…survive

`encodeBaseUrl` returned a base URL whose path had no trailing slash
(e.g. `https://host/db/prod`). The Hrana client resolves endpoint paths
against it with `new URL("v2/pipeline", baseUrl)`, and per the WHATWG URL
resolver that replaces the last path segment when the base does not end
in `/`. So a client pointed at a libSQL server behind a reverse proxy on
a sub-path sent every request one segment short
(`https://host/db/v2/pipeline` instead of `https://host/db/prod/v2/pipeline`),
which is why appending a `/` to the URL was the known workaround.

Append a trailing slash to a non-empty path in `encodeBaseUrl` so the
base URL is safe for relative resolution. The root case (`""` / `"/"`)
is unchanged. The `wss:`/`ws:` clients get the same normalized URL; the
Hrana WebSocket handshake is not sensitive to the trailing slash.

Closes tursodatabase#296
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.

client strips last url path segment

1 participant