fix(web): omit referrer when loading message images

Set no-referrer on message thumbnails and previews to prevent
QQ image requests from returning 400 and triggering ORB.

Add browser coverage for image loading and request headers.
This commit is contained in:
BiFangKNT
2026-10-21 12:03:00 +08:00
parent fc62f2ee13
commit 726ad5530f
3 changed files with 65 additions and 0 deletions
@@ -87,6 +87,7 @@ export function MessageContentRenderer({
<span key={index} className="inline-block align-middle mx-1">
<img
src={imageUrl}
referrerPolicy="no-referrer"
alt="Message attachment"
className="w-20 h-20 object-cover rounded cursor-pointer hover:opacity-80 transition-opacity border"
onClick={(e) => {
@@ -35,6 +35,7 @@ export default function ImagePreviewDialog({
{/* 图片 */}
<img
src={imageUrl}
referrerPolicy="no-referrer"
alt="Preview"
className="max-w-[50vw] max-h-[50vh] object-contain rounded-lg shadow-2xl bg-white"
onClick={(e) => e.stopPropagation()}
@@ -24,6 +24,69 @@ const pageOf = (
next_offset = items.length,
) => ({ items, has_more, next_offset });
test('loads external input images and previews without sending a referrer', async ({
page,
}) => {
await installLangBotApiMocks(page, {
authenticated: true,
monitoringData: monitoring,
});
const imageUrl = 'https://images.example.test/attachment.png';
const referrers: (string | undefined)[] = [];
await page.route(imageUrl, async (route) => {
const referrer = route.request().headers().referer;
referrers.push(referrer);
// Match providers that return JSON errors for embedded requests.
if (referrer) {
await route.fulfill({ status: 400, json: { error: 'Invalid referrer' } });
return;
}
await route.fulfill({
contentType: 'image/png',
headers: { 'Cache-Control': 'no-store' },
body: Buffer.from(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aX1sAAAAASUVORK5CYII=',
'base64',
),
});
});
await page.route('**/api/v1/monitoring/executions/*/*?*', async (route) => {
await route.fulfill({
json: {
code: 0,
data: {
source: 'pipeline',
row,
pages: {
inputs: pageOf([
{ id: 'image', content: [{ type: 'Image', url: imageUrl }] },
]),
outputs: pageOf([]),
deliveries: pageOf([]),
errors: pageOf([]),
},
},
},
});
});
await page.goto('/home/monitoring');
await page
.getByRole('button')
.filter({ hasText: 'Open this execution' })
.click();
const thumbnail = page.getByRole('img', { name: 'Message attachment' });
await expect
.poll(() => thumbnail.evaluate((img: HTMLImageElement) => img.naturalWidth))
.toBe(1);
await thumbnail.click();
const preview = page.getByRole('img', { name: 'Preview', exact: true });
await expect(preview).toBeVisible();
await expect
.poll(() => preview.evaluate((img: HTMLImageElement) => img.naturalWidth))
.toBe(1);
expect(referrers).toEqual([undefined, undefined]);
});
test('loads collapsed history on demand, retries and pages without reloading it on reopen', async ({
page,
}) => {