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
+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}`);
}
};