Skip to content

Commit 0c7edc0

Browse files
chrisbobbegnprice
authored andcommitted
content: Relax image-preview parsing, notably to accept arbitrary CAMO_URI
See discussion: https://chat.zulip.org/#narrow/channel/412-api-documentation/topic/documenting.20inline.20images/near/2279454 We already test the `src == href` case, as ContentExample.imagePreviewSingleNoThumbnail, but I added a test case for an arbitrary CAMO_URI that fails before this commit.
1 parent 6ff4df3 commit 0c7edc0

File tree

2 files changed

+23
-12
lines changed

2 files changed

+23
-12
lines changed

lib/model/content.dart

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,22 +1413,17 @@ class _ZulipContentParser {
14131413
final String srcUrl;
14141414
final String? thumbnailUrl;
14151415
if (src.startsWith('/user_uploads/thumbnail/')) {
1416+
// For why we recognize this as the thumbnail form, see discussion:
1417+
// https://chat.zulip.org/#narrow/channel/412-api-documentation/topic/documenting.20inline.20images/near/2279872
14161418
srcUrl = href;
14171419
thumbnailUrl = src;
1418-
} else if (src.startsWith('/external_content/')
1419-
|| src.startsWith('https://uploads.zulipusercontent.net/')) {
1420-
// This image preview uses camo, which still happens on current servers
1421-
// (2025-10); discussion:
1422-
// https://chat.zulip.org/#narrow/channel/412-api-documentation/topic/documenting.20inline.20images/near/2279235
1423-
srcUrl = src;
1424-
thumbnailUrl = null;
1425-
} else if (href == src) {
1426-
// Probably generated by a server before the thumbnailing feature landed:
1427-
// https://chat.zulip.org/#narrow/channel/412-api-documentation/topic/documenting.20inline.20images/near/2279234
1420+
} else {
1421+
// Known cases this handles:
1422+
// - `src` starts with CAMO_URI, a server variable (e.g. on Zulip Cloud
1423+
// it's "https://uploads.zulipusercontent.net/" in 2025-10).
1424+
// - `src` matches `href`, e.g. from pre-thumbnailing servers.
14281425
srcUrl = src;
14291426
thumbnailUrl = null;
1430-
} else {
1431-
return UnimplementedBlockContentNode(htmlNode: divElement);
14321427
}
14331428

14341429
double? originalWidth, originalHeight;

test/model/content_test.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,21 @@ class ContentExample {
814814
]),
815815
]);
816816

817+
static const imagePreviewSingleExternal3 = ContentExample(
818+
'single image preview external, src starts with https://custom.camo-uri.example/',
819+
// CAMO_URI (server variable) can be set arbitrarily;
820+
// for another possible value, see imagePreviewSingleExternal2.
821+
"https://upload.wikimedia.org/wikipedia/commons/7/78/Verregende_bloem_van_een_Helenium_%27El_Dorado%27._22-07-2023._%28d.j.b%29.jpg",
822+
'<div class="message_inline_image">'
823+
'<a href="https://upload.wikimedia.org/wikipedia/commons/7/78/Verregende_bloem_van_een_Helenium_%27El_Dorado%27._22-07-2023._%28d.j.b%29.jpg">'
824+
'<img src="https://custom.camo-uri.example/99742b0f992be15283c428dd42f3b9f5db138d69/68747470733a2f2f75706c6f61642e77696b696d656469612e6f72672f77696b6970656469612f636f6d6d6f6e732f372f37382f566572726567656e64655f626c6f656d5f76616e5f65656e5f48656c656e69756d5f253237456c5f446f7261646f2532372e5f32322d30372d323032332e5f253238642e6a2e622532392e6a7067"></a></div>', [
825+
ImagePreviewNodeList([
826+
ImagePreviewNode(srcUrl: 'https://custom.camo-uri.example/99742b0f992be15283c428dd42f3b9f5db138d69/68747470733a2f2f75706c6f61642e77696b696d656469612e6f72672f77696b6970656469612f636f6d6d6f6e732f372f37382f566572726567656e64655f626c6f656d5f76616e5f65656e5f48656c656e69756d5f253237456c5f446f7261646f2532372e5f32322d30372d323032332e5f253238642e6a2e622532392e6a7067',
827+
thumbnailUrl: null, loading: false,
828+
originalWidth: null, originalHeight: null),
829+
]),
830+
]);
831+
817832
static const imagePreviewInvalidUrl = ContentExample(
818833
'single image preview with invalid URL',
819834
null, // hypothetical, to test for a risk of crashing
@@ -1833,6 +1848,7 @@ void main() async {
18331848
testParseExample(ContentExample.imagePreviewSingleLoadingPlaceholder);
18341849
testParseExample(ContentExample.imagePreviewSingleExternal1);
18351850
testParseExample(ContentExample.imagePreviewSingleExternal2);
1851+
testParseExample(ContentExample.imagePreviewSingleExternal3);
18361852
testParseExample(ContentExample.imagePreviewInvalidUrl);
18371853
testParseExample(ContentExample.imagePreviewCluster);
18381854
testParseExample(ContentExample.imagePreviewClusterNoThumbnails);

0 commit comments

Comments
 (0)