Skip to content

Commit c7d6619

Browse files
author
pengyu
committed
worked screenshot
1 parent 78f659f commit c7d6619

File tree

3 files changed

+91
-7
lines changed

3 files changed

+91
-7
lines changed

frontend/src/app/api/media/[...path]/route.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,26 @@ import path from 'path';
44
import { getMediaDir } from 'codefox-common';
55
import { logger } from '@/app/log/logger';
66

7+
78
export async function GET(
89
request: NextRequest,
910
{ params }: { params: { path: string[] } }
1011
) {
1112
try {
1213
const mediaDir = getMediaDir();
14+
logger.info(`📁 getMediaDir = ${mediaDir}`);
1315
const filePath = path.join(mediaDir, ...params.path);
1416
const normalizedPath = path.normalize(filePath);
17+
logger.info(`📁 getMediaDir = ${mediaDir}`);
18+
logger.info(`📂 full filePath = ${filePath}`);
19+
logger.debug(`Requested path: ${params.path.join('/')}`);
20+
logger.debug(`Full resolved path: ${filePath}`);
1521

1622
if (!normalizedPath.startsWith(mediaDir)) {
17-
logger.error('Possible directory traversal attempt:', filePath);
23+
logger.warn('⛔ Directory traversal attempt blocked:', filePath);
1824
return new Response('Access denied', { status: 403 });
1925
}
2026

21-
// File extension allowlist
2227
const contentTypeMap: Record<string, string> = {
2328
'.jpg': 'image/jpeg',
2429
'.jpeg': 'image/jpeg',
@@ -27,34 +32,37 @@ export async function GET(
2732
};
2833

2934
const ext = path.extname(filePath).toLowerCase();
35+
logger.debug(`File extension: ${ext}`);
3036
if (!contentTypeMap[ext]) {
37+
logger.warn(`⛔ Forbidden file type: ${ext}`);
3138
return new Response('Forbidden file type', { status: 403 });
3239
}
3340

34-
// File existence and size check
3541
let fileStat;
3642
try {
3743
fileStat = await fs.stat(filePath);
3844
} catch (err) {
45+
logger.warn(`❌ File not found at path: ${filePath}`);
3946
return new Response('File not found', { status: 404 });
4047
}
4148

4249
if (fileStat.size > 10 * 1024 * 1024) {
43-
// 10MB limit
50+
logger.warn(`📦 File too large (${fileStat.size} bytes): ${filePath}`);
4451
return new Response('File too large', { status: 413 });
4552
}
4653

47-
// Read and return the file
4854
const fileBuffer = await fs.readFile(filePath);
55+
logger.info(`✅ Serving file: ${filePath}`);
56+
4957
return new Response(fileBuffer, {
5058
headers: {
5159
'Content-Type': contentTypeMap[ext],
5260
'X-Content-Type-Options': 'nosniff',
5361
'Cache-Control': 'public, max-age=31536000',
5462
},
5563
});
56-
} catch (error) {
57-
logger.error('Error serving media file:', error);
64+
} catch (error: any) {
65+
logger.error('🔥 Error serving media file:', error);
5866
const errorMessage =
5967
process.env.NODE_ENV === 'development'
6068
? `Error serving file: ${error.message}`
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { NextRequest } from 'next/server';
2+
import fs from 'fs/promises'; // Use promises API
3+
import path from 'path';
4+
import { getMediaDir } from 'codefox-common';
5+
import { logger } from '@/app/log/logger';
6+
7+
export async function GET(
8+
request: NextRequest,
9+
{ params }: { params: { path: string[] } }
10+
) {
11+
try {
12+
const mediaDir = getMediaDir();
13+
logger.info(`📁 getMediaDir = ${mediaDir}`);
14+
const filePath = path.join(mediaDir, ...params.path);
15+
const normalizedPath = path.normalize(filePath);
16+
logger.info(`📁 getMediaDir = ${mediaDir}`);
17+
logger.info(`📂 full filePath = ${filePath}`);
18+
logger.debug(`Requested path: ${params.path.join('/')}`);
19+
logger.debug(`Full resolved path: ${filePath}`);
20+
21+
if (!normalizedPath.startsWith(mediaDir)) {
22+
logger.warn('⛔ Directory traversal attempt blocked:', filePath);
23+
return new Response('Access denied', { status: 403 });
24+
}
25+
26+
const contentTypeMap: Record<string, string> = {
27+
'.jpg': 'image/jpeg',
28+
'.jpeg': 'image/jpeg',
29+
'.png': 'image/png',
30+
'.webp': 'image/webp',
31+
};
32+
33+
const ext = path.extname(filePath).toLowerCase();
34+
logger.debug(`File extension: ${ext}`);
35+
if (!contentTypeMap[ext]) {
36+
logger.warn(`⛔ Forbidden file type: ${ext}`);
37+
return new Response('Forbidden file type', { status: 403 });
38+
}
39+
40+
let fileStat;
41+
try {
42+
fileStat = await fs.stat(filePath);
43+
} catch (err) {
44+
logger.warn(`❌ File not found at path: ${filePath}`);
45+
return new Response('File not found', { status: 404 });
46+
}
47+
48+
if (fileStat.size > 10 * 1024 * 1024) {
49+
logger.warn(`📦 File too large (${fileStat.size} bytes): ${filePath}`);
50+
return new Response('File too large', { status: 413 });
51+
}
52+
53+
const fileBuffer = await fs.readFile(filePath);
54+
logger.info(`✅ Serving file: ${filePath}`);
55+
56+
return new Response(fileBuffer, {
57+
headers: {
58+
'Content-Type': contentTypeMap[ext],
59+
'X-Content-Type-Options': 'nosniff',
60+
'Cache-Control': 'public, max-age=31536000',
61+
},
62+
});
63+
} catch (error: any) {
64+
logger.error('🔥 Error serving media file:', error);
65+
const errorMessage =
66+
process.env.NODE_ENV === 'development'
67+
? `Error serving file: ${error.message}`
68+
: 'An error occurred while serving the file';
69+
70+
return new Response(errorMessage, { status: 500 });
71+
}
72+
}

frontend/src/components/chat/code-engine/project-context.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,10 @@ export function ProjectProvider({ children }: { children: ReactNode }) {
624624
logger.debug(`[screenshot] Sending request to ${screenshotUrl}`);
625625
const screenshotResponse = await fetch(screenshotUrl);
626626

627+
// 添加响应头调试
628+
logger.debug(`[screenshot] Response status: ${screenshotResponse.status}`);
629+
logger.debug(`[screenshot] Response content-type: ${screenshotResponse.headers.get('content-type')}`);
630+
627631
if (!screenshotResponse.ok) {
628632
throw new Error(
629633
`[screenshot] Failed to capture: ${screenshotResponse.status} ${screenshotResponse.statusText}`

0 commit comments

Comments
 (0)