mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
fix: give every upstream mail server request a deadline
This commit is contained in:
@@ -70,6 +70,21 @@ describe('fetchJmapServer', () => {
|
||||
expect(guardedFetch).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('gives every request a deadline unless the caller brought one', async () => {
|
||||
// A slow or silent server (with custom endpoints on, one the user chose)
|
||||
// used to be able to hold the connection open for as long as it liked.
|
||||
await fetchJmapServer('http://10.0.0.5/jmap/', { method: 'POST', body: '{}' }, true);
|
||||
expect(plainFetch.mock.calls[0][1].signal).toBeInstanceOf(AbortSignal);
|
||||
|
||||
guardedFetch.mockResolvedValueOnce(response(200, {}, 'guarded'));
|
||||
await fetchJmapServer('https://custom.example/jmap/', { method: 'GET' }, false);
|
||||
expect(guardedFetch.mock.calls[0][1].signal).toBeInstanceOf(AbortSignal);
|
||||
|
||||
const own = new AbortController().signal;
|
||||
await fetchJmapServer('http://10.0.0.5/jmap/', { method: 'GET', signal: own }, true);
|
||||
expect(plainFetch.mock.calls[1][1].signal).toBe(own);
|
||||
});
|
||||
|
||||
it('routes untrusted servers through fetchPublicUrl', async () => {
|
||||
guardedFetch.mockResolvedValueOnce(response(200, {}, 'guarded'));
|
||||
const res = await fetchJmapServer(
|
||||
|
||||
@@ -20,6 +20,8 @@ import { parseJmapServers, resolveTrustedJmapUrl } from '@/lib/admin/jmap-server
|
||||
import { fetchPublicUrl, type PublicFetchResponse } from '@/lib/security/url-guard';
|
||||
|
||||
const MAX_REDIRECTS = 5;
|
||||
/** Deadline for one upstream request when the caller sets none. */
|
||||
export const UPSTREAM_TIMEOUT_MS = 30_000;
|
||||
|
||||
export async function isTrustedJmapServerUrl(serverUrl: string): Promise<boolean> {
|
||||
await configManager.ensureLoaded();
|
||||
@@ -56,9 +58,13 @@ function headersToRecord(init: HeadersInit | undefined): Record<string, string>
|
||||
*/
|
||||
export async function fetchJmapServer(
|
||||
url: string,
|
||||
init: ServerFetchInit = {},
|
||||
givenInit: ServerFetchInit = {},
|
||||
trusted: boolean | undefined,
|
||||
): Promise<Response> {
|
||||
// Every call gets a deadline: a slow or silent server (with custom
|
||||
// endpoints on, one the user chose) must not pin a connection for as long
|
||||
// as it likes. Callers with their own signal keep it.
|
||||
const init: ServerFetchInit = givenInit.signal ? givenInit : { ...givenInit, signal: AbortSignal.timeout(UPSTREAM_TIMEOUT_MS) };
|
||||
if (trusted !== false) {
|
||||
return fetch(url, init);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user