Fix link preview race condition

This commit is contained in:
Evan Hahn 2021-06-02 19:19:40 -05:00 committed by GitHub
parent 66d9bb8418
commit 6642652bdb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 2 deletions

View file

@ -597,5 +597,9 @@ export async function fetchLinkPreviewImage(
return null; return null;
} }
if (abortSignal.aborted) {
return null;
}
return { data, contentType }; return { data, contentType };
} }

View file

@ -1354,5 +1354,70 @@ describe('link preview fetching', () => {
}) })
); );
}); });
it("doesn't read the image if the request was aborted before reading started", async () => {
const abortController = new AbortController();
const fixture = await readFixture('kitten-1-64-64.jpg');
const fakeFetch = stub().callsFake(() => {
const response = new Response(fixture, {
headers: {
'Content-Type': 'image/jpeg',
'Content-Length': fixture.length.toString(),
},
});
sinon
.stub(response, 'arrayBuffer')
.rejects(new Error('Should not be called'));
sinon.stub(response, 'blob').rejects(new Error('Should not be called'));
sinon.stub(response, 'text').rejects(new Error('Should not be called'));
sinon.stub(response, 'body').get(() => {
throw new Error('Should not be accessed');
});
abortController.abort();
return response;
});
assert.isNull(
await fetchLinkPreviewImage(
fakeFetch,
'https://example.com/img',
abortController.signal
)
);
});
it('returns null if the request was aborted after the image was read', async () => {
const abortController = new AbortController();
const fixture = await readFixture('kitten-1-64-64.jpg');
const fakeFetch = stub().callsFake(() => {
const response = new Response(fixture, {
headers: {
'Content-Type': 'image/jpeg',
'Content-Length': fixture.length.toString(),
},
});
const oldArrayBufferMethod = response.arrayBuffer.bind(response);
sinon.stub(response, 'arrayBuffer').callsFake(async () => {
const data = await oldArrayBufferMethod();
abortController.abort();
return data;
});
return response;
});
assert.isNull(
await fetchLinkPreviewImage(
fakeFetch,
'https://example.com/img',
abortController.signal
)
);
});
}); });
}); });

View file

@ -4169,14 +4169,13 @@ Whisper.ConversationView = Whisper.View.extend({
url, url,
abortSignal abortSignal
); );
if (!linkPreviewMetadata) { if (!linkPreviewMetadata || abortSignal.aborted) {
return null; return null;
} }
const { title, imageHref, description, date } = linkPreviewMetadata; const { title, imageHref, description, date } = linkPreviewMetadata;
let image; let image;
if ( if (
!abortSignal.aborted &&
imageHref && imageHref &&
window.Signal.LinkPreviews.isLinkSafeToPreview(imageHref) window.Signal.LinkPreviews.isLinkSafeToPreview(imageHref)
) { ) {
@ -4186,6 +4185,9 @@ Whisper.ConversationView = Whisper.View.extend({
imageHref, imageHref,
abortSignal abortSignal
); );
if (abortSignal.aborted) {
return null;
}
if (!fullSizeImage) { if (!fullSizeImage) {
throw new Error('Failed to fetch link preview image'); throw new Error('Failed to fetch link preview image');
} }
@ -4229,6 +4231,10 @@ Whisper.ConversationView = Whisper.View.extend({
} }
} }
if (abortSignal.aborted) {
return null;
}
return { return {
title, title,
url, url,