diff --git a/site/src/contexts/useProxyLatency.ts b/site/src/contexts/useProxyLatency.ts index 334638bc9314d..ff8be8cd66135 100644 --- a/site/src/contexts/useProxyLatency.ts +++ b/site/src/contexts/useProxyLatency.ts @@ -15,6 +15,11 @@ export interface ProxyLatencyReport { latencyMS: number; // at is when the latency was recorded. at: Date; + /** + * nextHopProtocol can determine if HTTP/2 is being used. + * https://developer.mozilla.org/docs/Web/API/PerformanceResourceTiming/nextHopProtocol + */ + nextHopProtocol?: string; } interface ProxyLatencyAction { @@ -151,6 +156,7 @@ export const useProxyLatency = ( // https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/Resource_timing let latencyMS = 0; let accurate = false; + let nextHopProtocol: string | undefined = undefined; if ( "requestStart" in entry && (entry as PerformanceResourceTiming).requestStart !== 0 @@ -159,6 +165,7 @@ export const useProxyLatency = ( const timingEntry = entry as PerformanceResourceTiming; latencyMS = timingEntry.responseStart - timingEntry.requestStart; accurate = true; + nextHopProtocol = timingEntry.nextHopProtocol; } else { // This is the total duration of the request and will be off by a good margin. // This is a fallback if the better timing is not available. @@ -175,7 +182,8 @@ export const useProxyLatency = ( latencyMS, accurate, at: new Date(), - }, + nextHopProtocol: nextHopProtocol, + } as ProxyLatencyReport, }; dispatchProxyLatencies(update); // Also save to local storage to persist the latency across page refreshes. diff --git a/site/src/pages/UserSettingsPage/WorkspaceProxyPage/WorkspaceProxyRow.tsx b/site/src/pages/UserSettingsPage/WorkspaceProxyPage/WorkspaceProxyRow.tsx index 0005e1fe28a68..e0af17f51baa1 100644 --- a/site/src/pages/UserSettingsPage/WorkspaceProxyPage/WorkspaceProxyRow.tsx +++ b/site/src/pages/UserSettingsPage/WorkspaceProxyPage/WorkspaceProxyRow.tsx @@ -26,12 +26,30 @@ export const ProxyRow: FC = ({ proxy, latency }) => { // All users can see healthy/unhealthy, some can see more. let statusBadge = ; let shouldShowMessages = false; + const extraWarnings: string[] = []; + if (latency?.nextHopProtocol) { + switch (latency.nextHopProtocol) { + case "http/0.9": + case "http/1.0": + case "http/1.1": + extraWarnings.push( + // biome-ignore lint/style/useTemplate: easier to read short lines + `Requests to the proxy from current browser are using "${latency.nextHopProtocol}". ` + + "The proxy server might not support HTTP/2. " + + "For usability reasons, HTTP/2 or above is recommended. " + + "Pages may fail to load if the web browser's concurrent " + + "connection limit per host is reached.", + ); + } + } + if ("status" in proxy) { const wsproxy = proxy as WorkspaceProxy; statusBadge = ; shouldShowMessages = Boolean( (wsproxy.status?.report?.warnings && wsproxy.status?.report?.warnings.length > 0) || + extraWarnings.length > 0 || (wsproxy.status?.report?.errors && wsproxy.status?.report?.errors.length > 0), ); @@ -84,7 +102,10 @@ export const ProxyRow: FC = ({ proxy, latency }) => { colSpan={4} css={{ padding: "0 !important", borderBottom: 0 }} > - + )} @@ -94,9 +115,13 @@ export const ProxyRow: FC = ({ proxy, latency }) => { interface ProxyMessagesRowProps { proxy: WorkspaceProxy; + extraWarnings: string[]; } -const ProxyMessagesRow: FC = ({ proxy }) => { +const ProxyMessagesRow: FC = ({ + proxy, + extraWarnings, +}) => { const theme = useTheme(); return ( @@ -109,7 +134,7 @@ const ProxyMessagesRow: FC = ({ proxy }) => { title={ Warnings } - messages={proxy.status?.report?.warnings} + messages={[...(proxy.status?.report?.warnings ?? []), ...extraWarnings]} /> ); diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts index 3c329cb0dbf9c..5686e503eaf60 100644 --- a/site/src/testHelpers/entities.ts +++ b/site/src/testHelpers/entities.ts @@ -206,6 +206,10 @@ export const MockProxyLatencies: Record = { 100) % 250, at: new Date(), + nextHopProtocol: + proxy.id === "8444931c-0247-4171-842a-569d9f9cbadb" + ? "http/1.1" + : "h2", }; return acc; },