Safari: revert websocket redirect workaround (#28753)
This commit is contained in:
parent
0e36680ec9
commit
196c56fab7
2 changed files with 1 additions and 61 deletions
|
|
@ -33,9 +33,6 @@ import HelpModal from "../components/HelpModal.vue";
|
|||
import collector from "../mixins/collector";
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
const WS_OPEN_TIMEOUT_MS = 5000;
|
||||
const WS_RETRY_PARAM = "wsRetry";
|
||||
|
||||
// assume offline if not data received for 5 minutes
|
||||
let lastDataReceived = new Date();
|
||||
const maxDataAge = 60 * 1000 * 5;
|
||||
|
|
@ -67,7 +64,6 @@ export default defineComponent({
|
|||
data: () => {
|
||||
return {
|
||||
reconnectTimeout: null as number | null,
|
||||
openTimeout: null as number | null,
|
||||
ws: null as WebSocket | null,
|
||||
authNotConfigured: false,
|
||||
};
|
||||
|
|
@ -150,34 +146,6 @@ export default defineComponent({
|
|||
window.clearTimeout(this.reconnectTimeout);
|
||||
}
|
||||
},
|
||||
// Safari 26 bug: with hash fragment URLs the HTTP upgrade
|
||||
// request is sometimes silently dropped when serving from cache.
|
||||
// Recover by navigating without hash, once (wsRetry guards against loops).
|
||||
startOpenTimeout() {
|
||||
const url = new URL(window.location.href);
|
||||
if (url.searchParams.has(WS_RETRY_PARAM)) return;
|
||||
this.openTimeout = window.setTimeout(() => {
|
||||
console.warn("websocket open timeout, forcing navigation");
|
||||
this.ws?.close();
|
||||
url.hash = "";
|
||||
url.searchParams.set(WS_RETRY_PARAM, "true");
|
||||
window.location.href = url.href;
|
||||
}, WS_OPEN_TIMEOUT_MS);
|
||||
},
|
||||
clearOpenTimeout(success = false) {
|
||||
if (this.openTimeout) {
|
||||
window.clearTimeout(this.openTimeout);
|
||||
this.openTimeout = null;
|
||||
}
|
||||
if (success) {
|
||||
const url = new URL(window.location.href);
|
||||
if (url.searchParams.has(WS_RETRY_PARAM)) {
|
||||
console.warn("websocket open timeout recovered, clearing retry param");
|
||||
url.searchParams.delete(WS_RETRY_PARAM);
|
||||
window.history.replaceState(window.history.state, "", url.href);
|
||||
}
|
||||
}
|
||||
},
|
||||
pageShowHandler(event: PageTransitionEvent) {
|
||||
if (event.persisted) {
|
||||
this.clearReconnectTimeout();
|
||||
|
|
@ -201,7 +169,6 @@ export default defineComponent({
|
|||
}, 2500);
|
||||
},
|
||||
disconnect() {
|
||||
this.clearOpenTimeout();
|
||||
if (this.ws) {
|
||||
this.ws.onerror = null;
|
||||
this.ws.onopen = null;
|
||||
|
|
@ -228,22 +195,17 @@ export default defineComponent({
|
|||
|
||||
const loc = new URL("ws", window.location.href);
|
||||
loc.protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||
|
||||
this.ws = new WebSocket(loc.href);
|
||||
|
||||
this.startOpenTimeout();
|
||||
|
||||
this.ws.onerror = () => {
|
||||
console.log({ message: "Websocket error. Trying to reconnect." });
|
||||
this.clearOpenTimeout();
|
||||
this.ws?.close();
|
||||
};
|
||||
this.ws.onopen = () => {
|
||||
this.clearOpenTimeout(true);
|
||||
console.log("websocket connected");
|
||||
window.app.setOnline();
|
||||
};
|
||||
this.ws.onclose = () => {
|
||||
this.clearOpenTimeout();
|
||||
window.app.setOffline();
|
||||
this.reconnect();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,25 +43,3 @@ test("show offline when websocket is closed", async ({ page }) => {
|
|||
await expect(page.getByText("Not connected to a server.")).toBeVisible();
|
||||
await expect(page.getByRole("link", { name: "Let's start configuration" })).toBeHidden();
|
||||
});
|
||||
|
||||
test("force navigation after websocket open timeout", async ({ page }) => {
|
||||
// Replace WebSocket with a mock that never fires onopen,
|
||||
// simulating Safari's bug where the upgrade request is silently dropped.
|
||||
await page.addInitScript(() => {
|
||||
(window as any).WebSocket = class {
|
||||
readyState = 0;
|
||||
onopen: (() => void) | null = null;
|
||||
onclose: ((ev: CloseEvent) => void) | null = null;
|
||||
onerror: (() => void) | null = null;
|
||||
onmessage: (() => void) | null = null;
|
||||
close() {
|
||||
this.readyState = 3;
|
||||
this.onclose?.(new CloseEvent("close"));
|
||||
}
|
||||
send() {}
|
||||
};
|
||||
});
|
||||
await page.goto("/");
|
||||
// after the 5s open timeout the app navigates to strip the hash fragment
|
||||
await page.waitForURL(/wsRetry/, { timeout: 10000 });
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue