Skip to content

fix: image preview crashing on large pdfs#6763

Merged
diegolmello merged 3 commits into
developfrom
fix.url-image-large-pdf
Nov 6, 2025
Merged

fix: image preview crashing on large pdfs#6763
diegolmello merged 3 commits into
developfrom
fix.url-image-large-pdf

Conversation

@diegolmello

@diegolmello diegolmello commented Nov 6, 2025

Copy link
Copy Markdown
Member

Proposed changes

Issue(s)

https://rocketchat.atlassian.net/browse/NATIVE-1075

How to test or reproduce

Screenshots

image

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

Summary by CodeRabbit

  • Bug Fixes

    • More reliable image detection and loading in messages to reduce broken or missing images.
  • Performance

    • Faster and more consistent image URL resolution and loading to speed up message rendering and reduce flicker.

@coderabbitai

coderabbitai Bot commented Nov 6, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Introduces a memoized getImageUrl helper and updates Urls.tsx to compute and gate image URL resolution via the helper; imageUrl state is now string | null, effect uses _imageUrl = getImageUrl() and calls axios.head(_imageUrl) before setting state, with updated dependencies.

Changes

Cohort / File(s) Change Summary
URL handling optimization
app/containers/message/Urls.tsx
Added useCallback import and a memoized getImageUrl helper to compute image URLs (from url.image, url.url, or constructed RC URLs). Changed imageUrl state to `string

Sequence Diagram(s)

sequenceDiagram
  participant Component as Urls.tsx
  participant Helper as getImageUrl()
  participant HTTP as axios.head()
  participant State as setImageUrl()

  Component->>Helper: call getImageUrl()
  Helper-->>Component: returns _imageUrl or null
  alt _imageUrl present
    Component->>HTTP: HEAD _imageUrl
    HTTP-->>Component: response (content-type / status)
    alt response is image AND API_Embed enabled
      Component->>State: setImageUrl(_imageUrl)
    else
      Component->>State: setImageUrl(null)
    end
  else _imageUrl null
    Component->>State: setImageUrl(null)
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Verify getImageUrl fallbacks and RC URL construction including auth usage.
  • Confirm nullable imageUrl is handled safely in render/consumers.
  • Ensure useEffect dependency array is correct to avoid stale closures.
  • Check axios.head error handling and content-type logic.

Suggested reviewers

  • OtavioStasiak

Poem

🐰 I sniffed the links and found a clue,
I memoized the path so fetches are few.
No more stray heads on PDFs tall,
I hop, I check, I save them all.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: image preview crashing on large pdfs' accurately summarizes the main change in the pull request, which addresses a crash issue when previewing images from large PDFs.
Linked Issues check ✅ Passed The pull request modifies Urls.tsx to prevent crashes by memoizing URL computation and gating API calls, which aligns with the objective to fix image preview crashes on large PDFs.
Out of Scope Changes check ✅ Passed All changes in Urls.tsx are focused on fixing the image preview crash issue through URL handling optimization, with no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix.url-image-large-pdf

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2d51ccf and 61f8ed9.

📒 Files selected for processing (1)
  • app/containers/message/Urls.tsx (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: ESLint and Test / run-eslint-and-test
  • GitHub Check: format
🔇 Additional comments (3)
app/containers/message/Urls.tsx (3)

1-1: LGTM! Correct import for memoization.

The addition of useCallback is appropriate for the memoized getImageUrl function introduced later in the component.


126-126: LGTM! Improved type safety.

Changing imageUrl to nullable and initializing to null clearly expresses that the image URL is unavailable until verified, improving type safety and intent.


128-134: LGTM! Proper memoization.

The memoized getImageUrl function correctly computes the image URL with appropriate dependencies, preventing unnecessary recreations on each render.

Comment on lines 128 to +152
useEffect(() => {
const verifyUrlIsImage = async () => {
try {
const imageUrl = getImageUrl();
if (!imageUrl || !API_Embed) return;
const _imageUrl = getImageUrl();
if (!_imageUrl || !API_Embed) return;

const response = await axios.head(imageUrl);
const response = await axios.head(_imageUrl);
const contentType = response.headers['content-type'];
if (contentType?.startsWith?.('image/')) {
setImageUrl(imageUrl);
setImageUrl(_imageUrl);
}
} catch {
// do nothing
}
};
verifyUrlIsImage();
}, [url.image, url.url, API_Embed]);

const getImageUrl = () => {
const _imageUrl = url.image || url.url;

if (!_imageUrl) return null;
if (_imageUrl.includes('http')) return _imageUrl;
return `${baseUrl}/${_imageUrl}?rc_uid=${user.id}&rc_token=${user.token}`;
};
}, [url.image, url.url, API_Embed, getImageUrl]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add timeout and cleanup to prevent hangs and memory leaks.

The verification approach is sound and likely fixes the PDF crash issue by checking content-type before rendering. However, two concerns:

  1. No request timeout: The axios.head call could hang indefinitely on slow or unresponsive servers
  2. No cleanup: If the component unmounts during the request, setImageUrl will be called on an unmounted component, causing React warnings

Apply this diff to add timeout and cleanup:

 	useEffect(() => {
+		let isMounted = true;
 		const verifyUrlIsImage = async () => {
 			try {
 				const _imageUrl = getImageUrl();
 				if (!_imageUrl || !API_Embed) return;
 
-				const response = await axios.head(_imageUrl);
+				const response = await axios.head(_imageUrl, { timeout: 5000 });
 				const contentType = response.headers['content-type'];
-				if (contentType?.startsWith?.('image/')) {
+				if (isMounted && contentType?.startsWith?.('image/')) {
 					setImageUrl(_imageUrl);
 				}
 			} catch {
 				// do nothing
 			}
 		};
 		verifyUrlIsImage();
+		return () => {
+			isMounted = false;
+		};
 	}, [url.image, url.url, API_Embed, getImageUrl]);

@diegolmello diegolmello force-pushed the fix.url-image-large-pdf branch from 1e1fecf to 656dfaa Compare November 6, 2025 13:17
@diegolmello diegolmello temporarily deployed to approve_e2e_testing November 6, 2025 13:17 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to experimental_android_build November 6, 2025 13:20 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to experimental_ios_build November 6, 2025 13:20 — with GitHub Actions Inactive
Comment thread app/containers/message/Urls.tsx Outdated

@OtavioStasiak OtavioStasiak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

PS: I agree with @nmagedman’s suggestion to use startsWith instead of includes.
https://github.com/RocketChat/Rocket.Chat.ReactNative/pull/6763/files#r2498967354

Co-authored-by: Noach Magedman <nmagedman@gmail.com>
@diegolmello

Copy link
Copy Markdown
Member Author

Thanks for your review, @nmagedman!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
app/containers/message/Urls.tsx (1)

136-151: Add timeout and cleanup to prevent hangs and memory leaks.

The content-type verification correctly prevents PDFs from being rendered as images (fixing the crash), but the implementation still needs timeout and cleanup handling as flagged in the previous review.

🧹 Nitpick comments (1)
app/containers/message/Urls.tsx (1)

152-152: Consider simplifying redundant dependencies.

The effect dependencies include both url.image and url.url explicitly, as well as getImageUrl which already depends on those values. When url.image or url.url changes, getImageUrl is recreated (per its dependency array), which already triggers this effect.

Apply this diff to remove the redundant dependencies:

-	}, [url.image, url.url, API_Embed, getImageUrl]);
+	}, [API_Embed, getImageUrl]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 656dfaa and 9a6324b.

📒 Files selected for processing (1)
  • app/containers/message/Urls.tsx (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: format
🔇 Additional comments (3)
app/containers/message/Urls.tsx (3)

1-1: LGTM!

The useCallback import is necessary for the new memoized getImageUrl helper and follows React best practices.


126-126: LGTM!

The type change to string | null with null initialization correctly reflects that the image URL is unknown until verified by the HEAD request.


128-134: LGTM!

The memoized helper correctly computes the image URL with proper handling for absolute URLs and credential injection. The dependency array is complete and accurate.

@github-actions

github-actions Bot commented Nov 6, 2025

Copy link
Copy Markdown

iOS Build Available

Rocket.Chat Experimental 4.67.0.107662

@diegolmello diegolmello temporarily deployed to approve_e2e_testing November 6, 2025 13:57 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to experimental_android_build November 6, 2025 14:00 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to official_ios_build November 6, 2025 14:00 — with GitHub Actions Inactive
@diegolmello diegolmello temporarily deployed to official_android_build November 6, 2025 14:00 — with GitHub Actions Inactive
@diegolmello diegolmello merged commit 3532447 into develop Nov 6, 2025
12 of 14 checks passed
@diegolmello diegolmello deleted the fix.url-image-large-pdf branch November 6, 2025 14:01
diegolmello added a commit that referenced this pull request Nov 6, 2025
* Fix image preview crashing on large pdfs

* Update snapshots

* Update app/containers/message/Urls.tsx

Co-authored-by: Noach Magedman <nmagedman@gmail.com>

---------

Co-authored-by: Noach Magedman <nmagedman@gmail.com>
@diegolmello diegolmello mentioned this pull request Nov 6, 2025
10 tasks
@nmagedman

Copy link
Copy Markdown
Contributor

I'm just recording here that among all the misc. code refactorings/tweaks, the actual bugfix itself is this:

-	const [imageUrl, setImageUrl] = useState(url.image);
+	const [imageUrl, setImageUrl] = useState(null);

The imageUrl should only be set once we actually verifyUrlIsImage.
In the old version, url.image was effectively pre-verified and verifyUrlIsImage had no effect.

@diegolmello diegolmello temporarily deployed to upload_official_android November 6, 2025 14:25 — with GitHub Actions Inactive
@github-actions

github-actions Bot commented Nov 6, 2025

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Nov 6, 2025

Copy link
Copy Markdown

Android Build Available

Rocket.Chat 4.67.0.107664

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants