Skip to content

Conversation

sheepmaster
Copy link

#5030 updated the varyKeys map to use lowercased keys in order to allow case-insensitive matching. The corresponding logic in FileCacheStorage has not been updated however, which can cause an exception when upgrading from an older version to 3.3.0. This is the sequence of events:

  • An old entry exists in the cache on disk, with a varyKeys key that contains uppercase letters
  • Client updates to 3.3.0 or later
  • Updated client prepares for a request, and calls findResponse()
    • findResponse() uses header lookup (which is case-insensitive) to verify that the Vary keys match
    • Cache entry matches and the request proceeds, with revalidation
  • Client sends the request to revalidate, server responds with Not Modified
  • Client calls findAndRefresh() with the response, which calls the other variant of findResponse()
    • That variant calls CacheStorage.find(), which looks up keys directly in the varyKeys map (case-sensitive)
    • This lookup fails because the map keys are using uppercase characters, whereas the requested keys are lowercased
  • This causes an InvalidCacheStateException to be thrown because it looks like the cache entry has disappeared.

This PR updates the code in FileCacheStorage that deserializes cache entries from disk to lowercase the keys in the varyKeys map, as that's the only other "real" source of cache entries (in-memory caches need to be populated from somewhere else).

Copy link
Contributor

coderabbitai bot commented Oct 14, 2025

Walkthrough

Normalizes Vary header keys to lowercase during file cache deserialization, updates JVM tests to exercise case variations, adds a test server route returning 304 with Vary: Accept-Language, and adds a client test to verify upgrading old cache entries with case-sensitive Vary keys.

Changes

Cohort / File(s) Summary
Cache storage deserialization
ktor-client/ktor-client-core/jvm/src/io/ktor/client/plugins/cache/storage/FileCacheStorage.kt
Lowercases Vary-key names when reading from cache files to normalize keys during deserialization.
Client file cache tests (JVM)
ktor-client/ktor-client-tests/jvm/test/io/ktor/client/tests/FileCacheTest.kt
Adds testUpgradeOldCacheVersionWithCaseSensitiveVary to prepopulate a cache entry using capitalized Vary key (Accept-Language) and verify retrieval with matching Accept-Language header.
Core file storage test (JVM)
ktor-client/ktor-client-core/jvm/test/FileStorageTest.kt
Adjusts testFind to store a second entry with an uppercase key ("Key") to exercise case-insensitive lookup expectations.
Test server route
ktor-test-server/src/main/kotlin/test/server/tests/Cache.kt
Adds /vary-header-not-modified route that sets Vary: Accept-Language and responds 304 Not Modified.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • marychatte
  • osipxd

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The description explains the background and solution in narrative form but does not follow the repository’s required template since it lacks the Subsystem, Motivation, and Solution headings and does not explicitly label those sections. Please update the PR description to include the Subsystem, Motivation, and Solution headings from the template and provide the corresponding details under each section.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly captures the primary change by stating that varyKeys keys will be lowercased during file storage deserialization and references the relevant ticket, making it clear and specific for reviewers scanning the history.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ce821b and 550c6d1.

📒 Files selected for processing (1)
  • ktor-client/ktor-client-tests/jvm/test/io/ktor/client/tests/FileCacheTest.kt (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • ktor-client/ktor-client-tests/jvm/test/io/ktor/client/tests/FileCacheTest.kt

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
ktor-client/ktor-client-core/jvm/test/FileStorageTest.kt (1)

37-44: Test correctly validates case-insensitive vary-key matching.

The change from "key" to "Key" on line 41 intentionally tests that FileCacheStorage finds entries regardless of vary-key capitalization, which validates the PR's deserialization fix.

Consider adding a brief comment explaining the intentional case mismatch, or renaming the test to something like testFindCaseInsensitive to make the test's purpose more explicit.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 931540f and 0c651a4.

📒 Files selected for processing (4)
  • ktor-client/ktor-client-core/jvm/src/io/ktor/client/plugins/cache/storage/FileCacheStorage.kt (1 hunks)
  • ktor-client/ktor-client-core/jvm/test/FileStorageTest.kt (1 hunks)
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/plugins/CacheTest.kt (2 hunks)
  • ktor-test-server/src/main/kotlin/test/server/tests/Cache.kt (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{kt,kts}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{kt,kts}: Follow Kotlin official style guide for all Kotlin source and build scripts
Use star imports for io.ktor.* packages
Max line length is 120 characters
Indent with 4 spaces in Kotlin code
Include a copyright header in new Kotlin files

Files:

  • ktor-client/ktor-client-core/jvm/src/io/ktor/client/plugins/cache/storage/FileCacheStorage.kt
  • ktor-test-server/src/main/kotlin/test/server/tests/Cache.kt
  • ktor-client/ktor-client-core/jvm/test/FileStorageTest.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/plugins/CacheTest.kt
**/*.kt

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.kt: Document all public Kotlin APIs, including parameters, return types, and exceptions
Annotate internal APIs with @internalapi
Follow Kotlin error-handling conventions and use specific Ktor exceptions

Files:

  • ktor-client/ktor-client-core/jvm/src/io/ktor/client/plugins/cache/storage/FileCacheStorage.kt
  • ktor-test-server/src/main/kotlin/test/server/tests/Cache.kt
  • ktor-client/ktor-client-core/jvm/test/FileStorageTest.kt
  • ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/plugins/CacheTest.kt
🧬 Code graph analysis (2)
ktor-client/ktor-client-core/jvm/test/FileStorageTest.kt (1)
ktor-client/ktor-client-core/jvm/test/CachingCacheStorageTest.kt (1)
  • data (103-113)
ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/plugins/CacheTest.kt (1)
ktor-client/ktor-client-core/common/src/io/ktor/client/plugins/cache/HttpCache.kt (3)
  • install (161-259)
  • publicStorage (123-125)
  • privateStorage (136-138)
🔇 Additional comments (3)
ktor-test-server/src/main/kotlin/test/server/tests/Cache.kt (1)

153-156: LGTM!

The new route provides the necessary test endpoint for validating the cache upgrade scenario with case-sensitive vary keys. The implementation correctly sets the Vary header and returns a 304 Not Modified response, which will trigger the cache refresh flow being tested.

ktor-client/ktor-client-core/jvm/src/io/ktor/client/plugins/cache/storage/FileCacheStorage.kt (1)

225-225: LGTM! Vary key normalization during deserialization.

The lowercase normalization ensures backward compatibility with cache entries created before the case-insensitive vary key change (PR #5030). This prevents InvalidCacheStateException during cache upgrades when old entries with capitalized vary keys (e.g., "Accept-Language") are deserialized and then looked up with lowercase keys.

ktor-client/ktor-client-tests/common/test/io/ktor/client/tests/plugins/CacheTest.kt (1)

20-20: LGTM! Import used for test data preparation.

The import is correctly used on line 955 to convert the cached response body string to a byte array.

@sheepmaster
Copy link
Author

@coderabbitai generate docstrings

Copy link
Contributor

coderabbitai bot commented Oct 15, 2025

✅ Actions performed

Initiated docstring generation; will generate only if new commits exist.

Copy link
Contributor

coderabbitai bot commented Oct 15, 2025

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #5124

coderabbitai bot added a commit that referenced this pull request Oct 15, 2025
Docstrings generation was requested by @sheepmaster.

* #5123 (comment)

The following files were modified:

* `ktor-client/ktor-client-core/jvm/src/io/ktor/client/plugins/cache/storage/FileCacheStorage.kt`
* `ktor-test-server/src/main/kotlin/test/server/tests/Cache.kt`
@Stexxe Stexxe requested a review from marychatte October 16, 2025 03:26
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.

1 participant