Improve image upload error handling and validation (#17188)

- Add URL validation in getImageBufferFromUrl utility
- Add response status validation and content-type checking
- Add timeout and connection error handling with specific error messages
- Validate buffer is not empty before processing
- Validate file type detection results before proceeding
- Ensure detected file type is actually an image format
- Add proper type safety for Axios error handling

This improves robustness when uploading images from URLs by:
- Preventing invalid URLs from being processed
- Providing clear error messages for different failure scenarios
- Ensuring only valid image files are processed
- Handling network errors gracefully

---------

Co-authored-by: GitTensor Miner <miner@gittensor.io>
This commit is contained in:
Angel98518
2026-01-19 16:40:02 +08:00
committed by GitHub
parent 5cef07af45
commit 92a080b704
4 changed files with 82 additions and 7 deletions
@@ -105,6 +105,8 @@ export class LoginPage {
}
async typeEmail(email: string) {
// Wait for the email field to be visible before trying to interact
await this.emailField.waitFor({ state: 'visible' });
await expect(this.emailField).toBeVisible();
await this.emailField.fill(email);
@@ -47,6 +47,8 @@ test('Create workflow', async ({ page }) => {
.getByTestId('top-bar-title')
.getByText(NEW_WORKFLOW_NAME);
// Wait for the name to be visible and not hidden
await workflowName.waitFor({ state: 'visible' });
await expect(workflowName).toBeVisible();
await expect(page).toHaveURL(`/object/workflow/${newWorkflowId}`);
@@ -120,10 +120,22 @@ export class FileUploadService {
const type = await FileType.fromBuffer(buffer);
if (!type || !type.ext || !type.mime) {
throw new Error(
'Unable to detect image type from buffer. The file may not be a valid image format.',
);
}
if (!type.mime.startsWith('image/')) {
throw new Error(
`Detected file type is not an image: ${type.mime}. Please provide a valid image URL.`,
);
}
return await this.uploadImage({
file: buffer,
filename: `${v4()}.${type?.ext}`,
mimeType: type?.mime,
filename: `${v4()}.${type.ext}`,
mimeType: type.mime,
fileFolder,
workspaceId,
});
+64 -5
View File
@@ -1,4 +1,4 @@
import { type Axios } from 'axios';
import { type Axios, type AxiosError } from 'axios';
const cropRegex = /([w|h])([0-9]+)/;
@@ -26,9 +26,68 @@ export const getImageBufferFromUrl = async (
url: string,
axiosInstance: Axios,
): Promise<Buffer> => {
const response = await axiosInstance.get(url, {
responseType: 'arraybuffer',
});
if (!url || typeof url !== 'string' || url.trim().length === 0) {
throw new Error('Invalid URL provided: URL must be a non-empty string');
}
return Buffer.from(response.data, 'binary');
try {
const response = await axiosInstance.get(url, {
responseType: 'arraybuffer',
validateStatus: (status) => status >= 200 && status < 300,
maxRedirects: 5,
timeout: 30000,
});
if (!response.data) {
throw new Error('Received empty response from image URL');
}
const bufferLength = Buffer.isBuffer(response.data)
? response.data.length
: response.data.byteLength;
if (bufferLength === 0) {
throw new Error('Received empty response from image URL');
}
const contentType = response.headers['content-type'];
if (contentType && !contentType.startsWith('image/')) {
throw new Error(
`Invalid content type: expected image/*, got ${contentType}`,
);
}
return Buffer.from(response.data, 'binary');
} catch (error) {
const axiosError = error as AxiosError;
const axiosResponse = axiosError.response;
if (axiosResponse) {
throw new Error(
`Failed to fetch image: HTTP ${axiosResponse.status} from ${url}`,
);
}
if (error instanceof Error) {
if (
axiosError.code === 'ECONNABORTED' ||
error.message.includes('timeout')
) {
throw new Error(
`Request timeout while fetching image from URL: ${url}`,
);
}
if (
axiosError.code === 'ENOTFOUND' ||
axiosError.code === 'ECONNREFUSED' ||
error.message.includes('ENOTFOUND') ||
error.message.includes('ECONNREFUSED')
) {
throw new Error(`Failed to connect to image URL: ${url}`);
}
throw new Error(`Failed to fetch image from URL: ${error.message}`);
}
throw new Error(`Failed to fetch image from URL: ${url}`);
}
};