mirror of
https://github.com/screego/server.git
synced 2026-11-02 20:12:06 +08:00
The room id was read from the query string with a hand-rolled parser that
never decoded it, while the id was written back into the URL without any
encoding:
getFromURL = (key, search) =>
search.slice(1).split('&')
.find((param) => param.startsWith(`${key}=`))?.split('=')[1];
window.history.pushState({roomId: id}, '', id ? `?room=${id}` : '?');
Browsers percent-encode non-ASCII characters when a URL is serialized, so a
room named "不辞" is shared as `?room=%E4%B8%8D%E8%BE%9E`, but the client then
joins the literal `%E4%B8%8D%E8%BE%9E` room, which does not exist:
-> {"type":"join","payload":{"id":"%E4%B8%8D%E8%BE%9E"}}
<- close 1000 "room with id %E4%B8%8D%E8%BE%9E does not exist"
The same asymmetry also broke ids containing `&`, `=`, `+`, `#` or `%`, and
made ids that already contain percent escapes gain another encoding level on
every write, producing broken (double encoded) share links.
Use the platform URL API, which decodes on read and encodes on write exactly
once:
new URLSearchParams(search).get(key) ?? undefined
const params = new URLSearchParams();
params.set('room', id);
window.history.pushState({roomId: id}, '', `?${params.toString()}`);
No server change is needed: the room id stays the raw, human-readable string
that the ws `create`/`join` payload and the server-side room map already use,
and existing share links keep working.
Verified: URL round-trip for 不辞 / "my room" / "a+b" / "a&b=c" / "100%",
protocol-level e2e against a live server (encoded id -> "does not exist",
decoded id -> joins, cleanup on owner leave), `yarn build` (tsc + vite) and
`prettier --check src/useRoomID.ts`.