Compare commits

...

1 Commits

Author SHA1 Message Date
Clément Pasteau
dd8ef4058f Handle encoding image path before displaying in the app, especially for local files 2024-01-19 15:48:00 +01:00
2 changed files with 143 additions and 7 deletions

View File

@@ -12,18 +12,50 @@ type Props = {|
onLoad?: (e: any) => void,
|};
const addSearchParameterToUrl = (
export const encodeUrlAndAddEncodedSearchParameter = (
url: string,
urlEncodedParameterName: string,
urlEncodedValue: string
) => {
if (url.startsWith('data:') || url.startsWith('blob:')) {
// blob/data protocol does not support search parameters, which are useless anyway.
return url;
console.log(url);
if (
url.startsWith('http://') ||
url.startsWith('https://') ||
url.startsWith('ftp://')
) {
const urlObject = new URL(url);
urlObject.searchParams.set(urlEncodedParameterName, urlEncodedValue);
return urlObject.toString();
}
const separator = url.indexOf('?') === -1 ? '?' : '&';
return url + separator + urlEncodedParameterName + '=' + urlEncodedValue;
if (url.startsWith('file://')) {
// Local files and folders can contain special characters, which is handled badly when using
// new URL() constructor. So we do it manually.
const searchParams = url.indexOf('?') === -1 ? '' : url.split('?')[1];
const urlWithoutSearchParams = searchParams ? url.split('?')[0] : url;
const urlWithoutSearchParamsAndFileProtocol = urlWithoutSearchParams.slice(
'file://'.length
);
const encodedUrlComponents = urlWithoutSearchParamsAndFileProtocol
.split('/')
.map(component => encodeURIComponent(component));
const encodedUrlWithoutSearchParamsAndFileProtocol = encodedUrlComponents.join(
'/'
);
const newSearchParam = urlEncodedParameterName + '=' + urlEncodedValue;
const searchParamsWithNewParam = searchParams
? searchParams + '&' + newSearchParam
: newSearchParam;
return (
'file://' +
encodedUrlWithoutSearchParamsAndFileProtocol +
'?' +
searchParamsWithNewParam
);
}
// blob/data protocol or static images do not support search parameters, which are useless anyway.
return url;
};
/**
@@ -58,7 +90,7 @@ export const CorsAwareImage = (props: Props) => (
//
// Search for "cors-cache-workaround" in the codebase for the same workarounds.
props.src
? addSearchParameterToUrl(props.src, 'gdUsage', 'img')
? encodeUrlAndAddEncodedSearchParameter(props.src, 'gdUsage', 'img')
: undefined
}
/>

View File

@@ -0,0 +1,104 @@
// @flow
import { encodeUrlAndAddEncodedSearchParameter } from './CorsAwareImage';
describe('encodeUrlAndAddEncodedSearchParameter', () => {
it('should add search parameter to http url', () => {
const url = 'http://resources.gdevelop-app.com/file.png';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe(
'http://resources.gdevelop-app.com/file.png?param=value'
);
});
it('should add search parameter to http url with existing params', () => {
const url = 'http://resources.gdevelop-app.com/file.png?existing=param';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe(
'http://resources.gdevelop-app.com/file.png?existing=param&param=value'
);
});
it('should encode properly the http url', () => {
const url =
'http://resources.gdevelop-app.com/folder/my file.png?existing=param';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe(
'http://resources.gdevelop-app.com/folder/my%20file.png?existing=param&param=value'
);
});
it('should add search parameter to https url', () => {
const url = 'https://resources.gdevelop-app.com/file.png';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe(
'https://resources.gdevelop-app.com/file.png?param=value'
);
});
it('should add search parameter to https url with existing params', () => {
const url = 'https://resources.gdevelop-app.com/file.png?existing=param';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe(
'https://resources.gdevelop-app.com/file.png?existing=param&param=value'
);
});
it('should encode properly the https url', () => {
const url =
'https://resources.gdevelop-app.com/my folder/my file.png?existing=param';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe(
'https://resources.gdevelop-app.com/my%20folder/my%20file.png?existing=param&param=value'
);
});
it('should add search parameter to ftp url', () => {
const url = 'ftp://example.com/file.png';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe('ftp://example.com/file.png?param=value');
});
it('should add search parameter to ftp url with existing params', () => {
const url = 'ftp://example.com/file.png?existing=param';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe(
'ftp://example.com/file.png?existing=param&param=value'
);
});
it('should encode properly the ftp url', () => {
const url = 'ftp://example.com/my folder/my file.png?existing=param';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe(
'ftp://example.com/my%20folder/my%20file.png?existing=param&param=value'
);
});
it('should add search parameter to file url', () => {
const url = 'file://User/My folder/file.png';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe('file://User/My%20folder/file.png?param=value');
});
it('should add search parameter to file url with existing params', () => {
const url = 'file://User/My folder/file.png?existing=param';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe(
'file://User/My%20folder/file.png?existing=param&param=value'
);
});
it('should encode properly the file url', () => {
const url = 'file://User/My #folder/my #file.png?existing=param';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe(
'file://User/My%20%23folder/my%20%23file.png?existing=param&param=value'
);
});
it('should return original url for blob/data protocol or static images', () => {
const url = 'blob://example.com/file.png';
const result = encodeUrlAndAddEncodedSearchParameter(url, 'param', 'value');
expect(result).toBe(url);
});
});