fix: serve thumbnail fallback without redirecting off-host

This commit is contained in:
FengLee
2026-06-06 00:20:59 +08:00
parent e67bc062cf
commit 26cb0ddbb3
2 changed files with 12 additions and 8 deletions

View File

@@ -124,8 +124,13 @@ await runTest('local storage route uses watermark access instead of exposing raw
assert.match(source, /shouldWatermarkStorageResponse\(/);
assert.match(source, /serveWatermarkedStorageFile\(/);
assert.match(source, /getStoredThumbnailRedirect\(/);
assert.match(source, /thumbnailRedirect/);
assert.match(source, /getStoredThumbnailResponse\(/);
assert.match(source, /thumbnailResponse/);
const thumbnailResponseFunction = source.slice(
source.indexOf('async function getStoredThumbnailResponse'),
source.indexOf('function normalizeStoragePath'),
);
assert.doesNotMatch(thumbnailResponseFunction, /NextResponse\.redirect/);
assert.doesNotMatch(
source,
/shouldWatermarkStorageResponse[\s\S]+?fileExistsAsync\(/,

View File

@@ -19,8 +19,8 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
const contentType = getContentType(filePath);
if (shouldWatermarkStorageResponse(filePath, contentType, null)) {
const thumbnailRedirect = await getStoredThumbnailRedirect(filePath, contentType, request.nextUrl.origin);
if (thumbnailRedirect) return thumbnailRedirect;
const thumbnailResponse = await getStoredThumbnailResponse(filePath, contentType);
if (thumbnailResponse) return thumbnailResponse;
try {
const watermarked = await serveWatermarkedStorageFile(filePath, contentType);
@@ -65,7 +65,7 @@ function serveLocalBuffer(filePath: string, fileBuffer: Buffer, cacheControl: st
});
}
async function getStoredThumbnailRedirect(filePath: string, contentType: string, origin: string): Promise<NextResponse | null> {
async function getStoredThumbnailResponse(filePath: string, contentType: string): Promise<NextResponse | null> {
if (!contentType.startsWith('image/') || filePath.startsWith('thumbnails/')) return null;
const publicUrl = `/api/local-storage/${encodeURI(filePath)}`;
const client = await getDbClient();
@@ -82,9 +82,8 @@ async function getStoredThumbnailRedirect(filePath: string, contentType: string,
const thumbnailUrl = typeof result.rows[0]?.thumbnail_url === 'string' ? result.rows[0].thumbnail_url : '';
const thumbnailKey = thumbnailUrl ? localStorage.getKeyFromPublicUrl(thumbnailUrl) : null;
if (!thumbnailKey || !localStorage.localFileExistsOnly(thumbnailKey)) return null;
const response = NextResponse.redirect(new URL(thumbnailUrl, origin), 302);
response.headers.set('Cache-Control', 'private, max-age=300');
return response;
const watermarked = await serveWatermarkedStorageFile(thumbnailKey, getContentType(thumbnailKey));
return serveLocalBuffer(watermarked.key, watermarked.buffer, WATERMARK_CACHE_CONTROL, watermarked.contentType);
} finally {
client.release();
}