OF-3314, OF-3315 & OF-3316: Minor FaviconServlet fixes#3394
Conversation
- Guard against missing 'host' param (host==null) before hostname validation, fixing a 500/NPE in InetAddresses.isInetAddress - Read missesCache once into a local to fix a check-then-act unbox NPE (null > 1) when the entry is evicted between gets - Replace hitsCache containsKey+get with a single get - Guard all default-favicon write paths against null defaultBytes, returning 404 instead of writing null when the default is absent
LaxRedirectStrategy followed redirects transparently, so the connected-host allowlist only ever validated the initial request host. A validated S2S peer could redirect the fetch to an internal address (e.g. a link-local metadata endpoint). - Disable automatic redirect handling on the HTTP client - Follow redirects manually, re-validating each hop's scheme (http/https only) and host (must be a connected S2S server) - Resolve relative redirects against the current URL - Bound redirects to 5 hops to prevent loops - Extract host validation into isConnectedHost() for reuse - Keep the existing isImage() body check as defense-in-depth
Replace the separate "Favicon Misses" and "Favicon Hits" caches with a single "Favicon Cache" of CacheableOptional<byte[]>: a present value holds the favicon bytes, an absent value records a host that was checked and has no usable favicon. - Remove the miss-counter logic; a single cache distinguishes "never checked" (key absent) from "checked, no favicon" (absent value) - Re-checks of missing favicons now happen via the cache TTL, replacing the ad-hoc two-strikes counter - Add Cache-Control (max-age=86400) so browsers don't refetch on every page load - Log swallowed write IOExceptions at trace level instead of discarding Note: a transient fetch failure is cached as absent for the full TTL, suppressing retries until the entry expires.
|
@coderabbitai please review |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Get PR details
gh pr view 3394 --repo igniterealtime/Openfire --json title,body,files,additions,deletions
echo "=== PR DIFF ==="
gh pr diff 3394 --repo igniterealtime/OpenfireLength of output: 15409 🏁 Script executed: #!/bin/bash
# Find and read CacheableOptional class
fd -i "CacheableOptional.java" --exec cat {}
echo "=== Check cache name consistency ==="
# The code uses "Favicon Cache" but CacheFactory registers "Favicon"
rg -n "Favicon" xmppserver/src/main/java/org/jivesoftware/util/FaviconServlet.java
rg -n "Favicon" xmppserver/src/main/java/org/jivesoftware/util/cache/CacheFactory.java
echo "=== Check existing uses of `@Nonnull` ==="
rg -n "`@Nonnull`" xmppserver/src/main/java/org/jivesoftware/util/FaviconServlet.java
echo "=== Check existing import for `@Nonnull` ==="
rg -n "import.*Nonnull" xmppserver/src/main/java/org/jivesoftware/util/FaviconServlet.java
echo "=== Check for other cache XML/config files ==="
fd -e xml -e properties --exec grep -l "favicon" {} 2>/dev/null
echo "=== Check ofcache.xml or similar ==="
fd "ofcache" --exec cat {}
echo "=== Check for 'Favicon Hits' or 'Favicon Misses' references elsewhere ==="
rg -rn "Favicon Hits\|Favicon Misses\|faviconHits\|faviconMisses\|Favicon Cache\|faviconCache" --type java
echo "=== Check redirect handling - does disableRedirectHandling affect anything else ==="
rg -n "disableRedirectHandling\|LaxRedirectStrategy" --type java
echo "=== Check GraphicsUtils.isImage ==="
fd "GraphicsUtils.java" --exec cat {}Length of output: 8018 🏁 Script executed: #!/bin/bash
# Check if there are any Hazelcast/clustering cache config files that reference old cache names
fd -e xml --exec grep -l -i "favicon" {} 2>/dev/null
rg -rn "favicon" --type xml
echo "=== Check the full current FaviconServlet for context ==="
cat xmppserver/src/main/java/org/jivesoftware/util/FaviconServlet.javaLength of output: 11790
Overall AssessmentThe PR is a solid hardening of 🐛 Bug: Cache name mismatch
faviconCache = CacheFactory.createCache("Favicon Cache");
cacheNames.put("Favicon", "favicon");The servlet requests a cache named Fix: Either change the faviconCache = CacheFactory.createCache("Favicon");or update Minor observations1. 2. Redirect loop with 3. Cache size halved — The old implementation had two caches each at 1 MB (total 2 MB effective budget). The new single cache is 1 MB. Since it now holds 4. 5. The only thing that needs fixing before merge is the cache name mismatch ( ✅ Action performedReview finished.
|
📝 WalkthroughWalkthrough
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@xmppserver/src/main/java/org/jivesoftware/util/FaviconServlet.java`:
- Around line 102-103: The cache name passed to CacheFactory.createCache() in
the FaviconServlet initialization does not match the registered cache name in
CacheFactory.cacheNames, preventing the configured 1 MB size limit
(cache.favicon.size = 1_048_576) from being applied. Change the cache name
parameter in the CacheFactory.createCache() call to match the exact registered
cache name in CacheFactory.cacheNames for the Favicon cache, ensuring the
configuration property is correctly resolved instead of falling back to the
default 256 KB limit.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 833d7923-0333-4846-9552-081b7d32c7a8
📒 Files selected for processing (2)
xmppserver/src/main/java/org/jivesoftware/util/FaviconServlet.javaxmppserver/src/main/java/org/jivesoftware/util/cache/CacheFactory.java
Fishbowler
left a comment
There was a problem hiding this comment.
Approved, with 1 small question
| if (targetHost == null || !isConnectedHost(targetHost)) { | ||
| LOGGER.info("Ignoring redirect to non-connected or unparseable host: {}", location.getValue()); |
There was a problem hiding this comment.
Should this check be this strict? If we attempt to get the favicon of "xmpp.example.org", we wouldn't allow a redirect to example.org?
The FaviconServlet is used to display an icon on the admin console, when displaying server-to-server connections. The changes in this PR harden the implementation. Please refer to individual commit messages for details.
The one notable change is that this replaces the caches named "Favicon Hits" and "Favicon Misses" with one new cache: "Favicon".