fix crash on image with no data

This commit is contained in:
or-else
2022-01-12 17:27:39 -08:00
parent 479752036d
commit e87a36421c
8 changed files with 58 additions and 26 deletions
+21 -9
View File
@@ -349,15 +349,21 @@ function quoteImage(data) {
// Get the blob from the image data.
if (data.val) {
const blob = base64ToBlob(data.val, data.mime);
promise = blob ? Promise.resolve(blob) : Promise.reject(new Error("Invalid image"));
if (!blob) {
throw new Error("Invalid image");
}
promise = Promise.resolve(blob);
} else if (data.ref) {
promise = fetch(this.authorizeURL(sanitizeImageUrl(data.ref)))
.then(evt => {
if (evt.ok) {
return evt.blob();
} else {
throw new Error(`Image fetch unsuccessful: ${evt.status} ${evt.statusText}`);
}
});
} else {
promise = fetch(this.authorizeURL(sanitizeImageUrl(data.ref))).then(evt => {
if (evt.ok) {
return evt.blob();
} else {
throw new Error(`Image fetch unsuccessful: ${evt.status} ${evt.statusText}`);
}
});
throw new Error("Missing image data");
}
// Scale the blob.
@@ -392,7 +398,13 @@ function quoteImage(data) {
export function replyFormatter(style, data, values, key, stack) {
if (style == 'IM') {
const attr = inlineImageAttr.call(this, {key: key}, data);
attr.whenDone = cancelablePromise(quoteImage.call(this, data));
let loadedPromise;
try {
loadedPromise = cancelablePromise(quoteImage.call(this, data));
} catch (error) {
loadedPromise = cancelablePromise(error);
}
attr.whenDone = loadedPromise;
values = [React.createElement(LazyImage, attr, null), ' ', attr.alt];
return React.createElement(React.Fragment, {key: key}, values);
} else if (style == 'QQ') {
+11 -7
View File
@@ -183,19 +183,23 @@ export function deliveryMarker(received) {
}
// Wraps a promise to make it cancelable.
// The parameter can be either a promise or an error. If it's an error, the wrapped promise is
// created in a rejected state.
export function cancelablePromise(promise) {
let hasCanceled = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise.then(
result => hasCanceled ? reject({isCanceled: true}) : resolve(result),
error => hasCanceled ? reject({isCanceled: true}) : reject(error)
);
});
const wrappedPromise = promise instanceof Error ?
Promise.reject(promise) :
new Promise((resolve, reject) => {
promise.then(
result => hasCanceled ? reject({isCanceled: true}) : resolve(result),
error => hasCanceled ? reject({isCanceled: true}) : reject(error)
);
});
return {
promise: wrappedPromise,
cancel( ) {
cancel() {
hasCanceled = true;
},
};
+1 -1
View File
@@ -55,7 +55,7 @@ export default class ImagePreview extends React.PureComponent {
<div id="image-preview">
<div id="image-preview-caption-panel">
{!this.props.onSendMessage ?
<a href={this.props.content.url} download={this.props.content.name}>
<a href={this.props.content.url} download={true}>
<i className="material-icons">file_download</i> <FormattedMessage
id="download_action" defaultMessage="download" description="Call to action [download]" />
</a>
+1
View File
@@ -31,6 +31,7 @@ export default class LazyImage extends React.PureComponent {
if (prevProps.whenDone != this.props.whenDone) {
this.setState({src: 'img/placeholder.png', style: {...this.state.style, padding: '4px'}});
this.props.whenDone
.promise
.then(data => this.setState({src: data.src, style: {...this.state.style, padding: 0}}))
.catch(() => this.setState({src: 'img/broken_image.png'}));
}
+21 -6
View File
@@ -787,8 +787,13 @@ function quoteImage(data) {
if (data.val) {
const blob = (0,_blob_helpers_js__WEBPACK_IMPORTED_MODULE_6__.base64ToBlob)(data.val, data.mime);
promise = blob ? Promise.resolve(blob) : Promise.reject(new Error("Invalid image"));
} else {
if (!blob) {
throw new Error("Invalid image");
}
promise = Promise.resolve(blob);
} else if (data.ref) {
promise = fetch(this.authorizeURL((0,_utils_js__WEBPACK_IMPORTED_MODULE_8__.sanitizeImageUrl)(data.ref))).then(evt => {
if (evt.ok) {
return evt.blob();
@@ -796,6 +801,8 @@ function quoteImage(data) {
throw new Error("Image fetch unsuccessful: ".concat(evt.status, " ").concat(evt.statusText));
}
});
} else {
throw new Error("Missing image data");
}
return promise.then(blob => {
@@ -825,7 +832,15 @@ function replyFormatter(style, data, values, key, stack) {
const attr = inlineImageAttr.call(this, {
key: key
}, data);
attr.whenDone = (0,_utils_js__WEBPACK_IMPORTED_MODULE_8__.cancelablePromise)(quoteImage.call(this, data));
let loadedPromise;
try {
loadedPromise = (0,_utils_js__WEBPACK_IMPORTED_MODULE_8__.cancelablePromise)(quoteImage.call(this, data));
} catch (error) {
loadedPromise = (0,_utils_js__WEBPACK_IMPORTED_MODULE_8__.cancelablePromise)(error);
}
attr.whenDone = loadedPromise;
values = [react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_widgets_lazy_image_jsx__WEBPACK_IMPORTED_MODULE_3__["default"], attr, null), ' ', attr.alt];
return react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), {
key: key
@@ -1312,7 +1327,7 @@ function deliveryMarker(received) {
}
function cancelablePromise(promise) {
let hasCanceled = false;
const wrappedPromise = new Promise((resolve, reject) => {
const wrappedPromise = promise instanceof Error ? Promise.reject(promise) : new Promise((resolve, reject) => {
promise.then(result => hasCanceled ? reject({
isCanceled: true
}) : resolve(result), error => hasCanceled ? reject({
@@ -10331,7 +10346,7 @@ class ImagePreview extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCom
id: "image-preview-caption-panel"
}, !this.props.onSendMessage ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement("a", {
href: this.props.content.url,
download: this.props.content.name
download: true
}, react__WEBPACK_IMPORTED_MODULE_0___default().createElement("i", {
className: "material-icons"
}, "file_download"), " ", react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_intl__WEBPACK_IMPORTED_MODULE_1__.FormattedMessage, {
@@ -10684,7 +10699,7 @@ class LazyImage extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCompon
padding: '4px'
}
});
this.props.whenDone.then(data => this.setState({
this.props.whenDone.promise.then(data => this.setState({
src: data.src,
style: { ...this.state.style,
padding: 0
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long