feat(server): custom HTTP headers for reverse-proxy gates (#1095) (#1156)

This commit is contained in:
cucadmuh
2026-06-22 16:25:28 +03:00
committed by GitHub
parent 2c9b2eeb46
commit 15cecb5d7d
83 changed files with 2452 additions and 327 deletions
+17 -16
View File
@@ -9,6 +9,7 @@ import {
vi.mock('@/api/subsonic', () => ({
pingWithCredentials: vi.fn(),
pingWithCredentialsForProfile: vi.fn(),
scheduleInstantMixProbeForServer: vi.fn(),
}));
@@ -16,7 +17,7 @@ vi.mock('@/utils/perf/perfFlags', () => ({
usePerfProbeFlags: () => ({ disableBackgroundPolling: false }),
}));
import { pingWithCredentials } from '@/api/subsonic';
import { pingWithCredentialsForProfile } from '@/api/subsonic';
import { useDevOfflineBrowseStore } from '@/store/devOfflineBrowseStore';
import { useConnectionStatus } from './useConnectionStatus';
@@ -24,7 +25,7 @@ beforeEach(() => {
resetAuthStore();
invalidateReachableEndpointCache();
useDevOfflineBrowseStore.getState().setForceOffline(false);
vi.mocked(pingWithCredentials).mockReset();
vi.mocked(pingWithCredentialsForProfile).mockReset();
});
afterEach(() => {
@@ -49,7 +50,7 @@ describe('useConnectionStatus.isLan', () => {
// LAN endpoint answers — alternateUrl is the LAN side here, so a
// primary-url-only check would say "public". We assert it says "local"
// (active endpoint kind).
vi.mocked(pingWithCredentials).mockImplementation(async url =>
vi.mocked(pingWithCredentialsForProfile).mockImplementation(async (_profile, url) =>
url === 'http://192.168.0.10'
? { ok: true, type: 'navidrome', serverVersion: '0.55.0', openSubsonic: true }
: { ok: false },
@@ -63,7 +64,7 @@ describe('useConnectionStatus.isLan', () => {
it('falls back to public when only the public address answers', async () => {
vi.useFakeTimers();
seedDualAddressServer();
vi.mocked(pingWithCredentials).mockImplementation(async url =>
vi.mocked(pingWithCredentialsForProfile).mockImplementation(async (_profile, url) =>
url === 'https://music.example.com'
? { ok: true, type: 'navidrome', serverVersion: '0.55.0', openSubsonic: true }
: { ok: false },
@@ -88,7 +89,7 @@ describe('useConnectionStatus.isLan', () => {
seedDualAddressServer();
// Don't resolve the ping — the hook is still in the `checking` state.
let _resolve: ((v: PickReachableResult) => void) | null = null;
vi.mocked(pingWithCredentials).mockReturnValue(
vi.mocked(pingWithCredentialsForProfile).mockReturnValue(
new Promise(r => {
_resolve = ((res: PickReachableResult) => {
if (res.ok) {
@@ -116,7 +117,7 @@ describe('useConnectionStatus online event', () => {
it('flushes the reachable-endpoint cache when the browser fires online', async () => {
seedDualAddressServer();
// Initial probe: LAN answers.
vi.mocked(pingWithCredentials).mockImplementation(async url =>
vi.mocked(pingWithCredentialsForProfile).mockImplementation(async (_profile, url) =>
url === 'http://192.168.0.10'
? { ok: true, type: 'navidrome', serverVersion: '0.55.0', openSubsonic: true }
: { ok: false },
@@ -129,8 +130,8 @@ describe('useConnectionStatus online event', () => {
// fire in this test; we trigger the online event instead. The handler
// invalidates the sticky cache so the next probe goes LAN-first and
// flips over to public when LAN refuses.
vi.mocked(pingWithCredentials).mockClear();
vi.mocked(pingWithCredentials).mockImplementation(async url =>
vi.mocked(pingWithCredentialsForProfile).mockClear();
vi.mocked(pingWithCredentialsForProfile).mockImplementation(async (_profile, url) =>
url === 'https://music.example.com'
? { ok: true, type: 'navidrome', serverVersion: '0.55.0', openSubsonic: true }
: { ok: false },
@@ -147,14 +148,14 @@ describe('useConnectionStatus online event', () => {
await waitFor(() => expect(result.current.isLan).toBe(false));
// Both endpoints were probed (LAN refused, public answered).
expect(vi.mocked(pingWithCredentials).mock.calls.length).toBeGreaterThanOrEqual(2);
expect(vi.mocked(pingWithCredentialsForProfile).mock.calls.length).toBeGreaterThanOrEqual(2);
});
});
describe('useConnectionStatus DEV offline toggle', () => {
it('does not probe again on mount beyond the polling effect', async () => {
seedDualAddressServer();
vi.mocked(pingWithCredentials).mockResolvedValue({
vi.mocked(pingWithCredentialsForProfile).mockResolvedValue({
ok: true,
type: 'navidrome',
serverVersion: '0.55.0',
@@ -162,15 +163,15 @@ describe('useConnectionStatus DEV offline toggle', () => {
});
renderHook(() => useConnectionStatus());
await waitFor(() => expect(vi.mocked(pingWithCredentials).mock.calls.length).toBeGreaterThanOrEqual(1));
const callsAfterMount = vi.mocked(pingWithCredentials).mock.calls.length;
await waitFor(() => expect(vi.mocked(pingWithCredentialsForProfile).mock.calls.length).toBeGreaterThanOrEqual(1));
const callsAfterMount = vi.mocked(pingWithCredentialsForProfile).mock.calls.length;
await new Promise(r => setTimeout(r, 20));
expect(vi.mocked(pingWithCredentials).mock.calls.length).toBe(callsAfterMount);
expect(vi.mocked(pingWithCredentialsForProfile).mock.calls.length).toBe(callsAfterMount);
});
it('disconnects on force-offline toggle without an extra probe', async () => {
seedDualAddressServer();
vi.mocked(pingWithCredentials).mockResolvedValue({
vi.mocked(pingWithCredentialsForProfile).mockResolvedValue({
ok: true,
type: 'navidrome',
serverVersion: '0.55.0',
@@ -179,10 +180,10 @@ describe('useConnectionStatus DEV offline toggle', () => {
const { result } = renderHook(() => useConnectionStatus());
await waitFor(() => expect(result.current.status).toBe('connected'));
const callsBeforeToggle = vi.mocked(pingWithCredentials).mock.calls.length;
const callsBeforeToggle = vi.mocked(pingWithCredentialsForProfile).mock.calls.length;
act(() => useDevOfflineBrowseStore.getState().setForceOffline(true));
await waitFor(() => expect(result.current.status).toBe('disconnected'));
expect(vi.mocked(pingWithCredentials).mock.calls.length).toBe(callsBeforeToggle);
expect(vi.mocked(pingWithCredentialsForProfile).mock.calls.length).toBe(callsBeforeToggle);
});
});