Skip to content

fix(trino): hold nextUri links to the connection's own origin - #1090

Merged
cevheri merged 2 commits into
libredb:mainfrom
chiliec:fix/trino-nexturi-origin
Sep 24, 2026
Merged

cevheri merged 2 commits into
libredb:mainfrom
chiliec:fix/trino-nexturi-origin

Conversation

@chiliec

@chiliec chiliec commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Closes #1087

What

TrinoHttpTransport.follow() requested every nextUri exactly as the coordinator sent it, with the connection's Authorization header attached. A page naming another host got the credential sent there. This holds each nextUri to the connection's own origin.

Change

  • src/lib/db/http/endpoint.ts: new rejectForeignLink(link, origin). Parses the link with URL, compares scheme, host (via the existing sameHost, so [::1] and [0:0:0:0:0:0:0:1] agree) and port (default port filled in from the scheme) against the transport's HttpOrigin. A mismatch, a non-http(s) scheme or an unparsable link throws a ConnectionError that names only the two origins, never the path or query, and says a proxy that rewrites Host is the usual cause.
  • src/lib/db/providers/sql/trino/http-transport.ts: follow() calls rejectForeignLink(next, this.origin) before this.request(next, ...). The throw happens inside query()'s existing try, so abandon() still sends the DELETE to the configured coordinator.
  • Fixtures: the captured links in tests/unit/db/trino/http-transport.test.ts (QUEUED_LINK_1, QUEUED_LINK_2, RUNNING_LINK, PARTIAL_CANCEL_LINK) were on http://localhost:8080 while makeConnection() names 127.0.0.1:8080. I changed the fixture side to 127.0.0.1 and left makeConnection() alone, with a note next to the constants. INFO_URI is untouched (it is never followed). The "sends the credential on every follow-up" test connects with ssl: require, so its pages now advertise https:// links to stay on-origin, and it additionally asserts every page was fetched.
  • Docs: docs/providers/trino.md §4.4 describes the rule instead of the residual; docs/SECURITY.md 0.6 note now lists two residuals (libSQL, Couchbase) instead of three.

Tests

New describe("TrinoHttpTransport nextUri origin"):

  • test.each over host / port / scheme mismatch: ConnectionError, message names http://127.0.0.1:8080, does not contain the query id or the slug, the foreign link never appears in calls, every recorded call is on the configured origin, and the last call is DELETE /v1/query/<id>.
  • message names both origins and never the link's path.
  • accepted: same-origin link followed as before; IPv6 spelled differently (::1 vs [0:0:0:0:0:0:0:1]); https link with the default port left out against port: 443.
  • non-http(s) link and a relative (unparsable) link are refused and the statement is cancelled.

Testing

bun tests/run-tests.ts tests/unit/db/trino/http-transport.test.ts tests/unit/db/http/endpoint.test.ts
# 2 files: 2 passed | 236 tests: 236 pass
bun tests/run-tests.ts tests/unit/db --jobs=2
# 55 files: 55 passed | 2860 tests: 2860 pass
bun tests/run-tests.ts tests/unit/db/trino tests/unit/db/http --coverage --merge-into=coverage/lcov.info
# src/lib/db/http/endpoint.ts LF:93 LH:93
tsc --noEmit -p <project tsconfig scoped to the three touched files>   # clean; the full `tsc --noEmit` OOMs on this host
bunx biome check <files>    # clean after --write
bunx oxlint <files>         # only the pre-existing no-await-in-loop warnings in http-transport.ts

RED→GREEN: with the transport change stashed, the 6 refusal tests fail (the transport follows the foreign link); with it, all 119 tests in the file pass.

Not run locally: the full bun run test (component/e2e lanes), the full-project tsc --noEmit and eslint . — the host is memory-limited (7.6 GB) and those OOM; the unit lane for tests/unit/db plus the coverage gate on the touched module ran as above. Please approve the workflow run so CI verifies the rest.

A nextUri on another scheme, host or port is refused before any request
is sent to it, the statement is cancelled on the configured coordinator,
and the ConnectionError names only the two origins.

Closes libredb#1087
The provider integration fixture advertised http://trino.test:8080 even
when the statement was posted over https, which the origin rule now
refuses. Mirror the real coordinator and derive the link from the
request the way it builds it from the Host header.
@codecov

codecov Bot commented Sep 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@cevheri cevheri added the enhancement New feature or request label Sep 23, 2026
@cevheri

cevheri commented Sep 23, 2026

Copy link
Copy Markdown
Member

Thanks, this is good and I will merge it shortly. I removed the rejectForeignLink call from follow(). The host, port, scheme, both-origins, ftp and relative tests all failed, and the DELETE assertion shows the cancel still goes to the configured coordinator.
CI is green on the required checks.

One small gap, if you want to push it first. The IPv6 test cannot fail against a plain string compare. URL already rewrites http://[0:0:0:0:0:0:0:1]:8080 to [::1], so both sides are the same string before sameHost runs. Swapping the spellings fixes that: configure host 0:0:0:0:0:0:0:1 and send the link on http://[::1]:8080/.... I tried it, and it passes on your code and fails when sameHost is replaced by ===. Please keep the existing case next to it. If this does not land soon, I will merge as is and add the test myself.

@cevheri
cevheri merged commit 952c11f into libredb:main Sep 24, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trino: hold the nextUri links to the connection's own origin

2 participants