KTOR-8443 Respect parameters in contentType and accept route selectors#5600
KTOR-8443 Respect parameters in contentType and accept route selectors#5600fru1tworld wants to merge 4 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThis PR adds a private HeaderValue.toContentType() helper that parses header entries into ContentType excluding the q parameter; ContentTypeHeaderRouteSelector and HttpMultiAcceptRouteSelector now use it. Two tests verify matching behavior with parameters. ChangesContent Negotiation Parameter Handling
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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
🧹 Nitpick comments (1)
ktor-server/ktor-server-tests/common/test/io/ktor/tests/server/routing/RoutingProcessingTest.kt (1)
683-688: ⚡ Quick winAdd one
Acceptregression with an extension afterq.The new test locks the
qcase itself, but it still misses the valid form where extra accept-ext params appear afterq. Adding something likeapplication/soap+xml; action=foo; q=0.5; trace=1would pin the intended selector behavior and catch the current delimiter bug immediately.🤖 Prompt for 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. In `@ktor-server/ktor-server-tests/common/test/io/ktor/tests/server/routing/RoutingProcessingTest.kt` around lines 683 - 688, Add a regression test variant to cover the Accept header form that has accept-ext parameters after the q parameter; specifically, in the RoutingProcessingTest (the existing client.get block using header(HttpHeaders.Accept, "application/soap+xml; action=foo; q=0.5")), add another request that uses a header like "application/soap+xml; action=foo; q=0.5; trace=1" (or similar) and assert the same outcome (assertEquals("matched", it.bodyAsText())); this ensures the selector logic that parses Accept parameters handles extra accept-ext entries following q.
🤖 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
`@ktor-server/ktor-server-core/common/src/io/ktor/server/routing/RouteSelector.kt`:
- Around line 831-834: The current HeaderValue.toContentType() reconstructs
media parameters after a "q" token and treats "q" case-sensitively, which breaks
Accept handling; change the helper to accept a stopAtQuality: Boolean (default
false) and when stopAtQuality is true skip the "q" parameter (case-insensitive)
and stop processing any subsequent params (i.e., ignore params after the first
param whose name equals "q" ignoring case) while still folding earlier params
into ContentType.parse(value); keep existing behavior (stopAtQuality=false) for
Content-Type usage and call the new stopAtQuality=true when parsing Accept
values so accept-exts are not reinterpreted as media parameters (refer to
HeaderValue.toContentType(), params, and ContentType.parse in your changes).
---
Nitpick comments:
In
`@ktor-server/ktor-server-tests/common/test/io/ktor/tests/server/routing/RoutingProcessingTest.kt`:
- Around line 683-688: Add a regression test variant to cover the Accept header
form that has accept-ext parameters after the q parameter; specifically, in the
RoutingProcessingTest (the existing client.get block using
header(HttpHeaders.Accept, "application/soap+xml; action=foo; q=0.5")), add
another request that uses a header like "application/soap+xml; action=foo;
q=0.5; trace=1" (or similar) and assert the same outcome
(assertEquals("matched", it.bodyAsText())); this ensures the selector logic that
parses Accept parameters handles extra accept-ext entries following q.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 99686339-b25e-4ce3-bf61-05f9d1304a53
📒 Files selected for processing (2)
ktor-server/ktor-server-core/common/src/io/ktor/server/routing/RouteSelector.ktktor-server/ktor-server-tests/common/test/io/ktor/tests/server/routing/RoutingProcessingTest.kt
| private fun HeaderValue.toContentType(): ContentType = | ||
| params.asSequence() | ||
| .filter { it.name != "q" } | ||
| .fold(ContentType.parse(value)) { acc, p -> acc.withParameter(p.name, p.value) } |
There was a problem hiding this comment.
Stop reconstructing Accept media parameters after q.
This helper is now shared by both Content-Type and Accept, but Accept treats q as the boundary between media parameters and accept-exts. Filtering out only "q" means a valid header like application/soap+xml; action=foo; q=0.5; trace=1 is reconstructed with trace=1 as a media parameter, which can make accept(...) reject a request it should match. The comparison should also treat q case-insensitively. A small split between Content-Type and Accept handling would avoid regressing one while fixing the other.
💡 Possible direction
-private fun HeaderValue.toContentType(): ContentType =
- params.asSequence()
- .filter { it.name != "q" }
+private fun HeaderValue.toContentType(stopAtQuality: Boolean): ContentType =
+ params.asSequence()
+ .let { sequence ->
+ if (stopAtQuality) sequence.takeWhile { !it.name.equals("q", ignoreCase = true) } else sequence
+ }
.fold(ContentType.parse(value)) { acc, p -> acc.withParameter(p.name, p.value) }Then use stopAtQuality = false for Content-Type and true for Accept.
🤖 Prompt for 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.
In
`@ktor-server/ktor-server-core/common/src/io/ktor/server/routing/RouteSelector.kt`
around lines 831 - 834, The current HeaderValue.toContentType() reconstructs
media parameters after a "q" token and treats "q" case-sensitively, which breaks
Accept handling; change the helper to accept a stopAtQuality: Boolean (default
false) and when stopAtQuality is true skip the "q" parameter (case-insensitive)
and stop processing any subsequent params (i.e., ignore params after the first
param whose name equals "q" ignoring case) while still folding earlier params
into ContentType.parse(value); keep existing behavior (stopAtQuality=false) for
Content-Type usage and call the new stopAtQuality=true when parsing Accept
values so accept-exts are not reinterpreted as media parameters (refer to
HeaderValue.toContentType(), params, and ContentType.parse in your changes).
bjhham
left a comment
There was a problem hiding this comment.
Thanks for the fix! One little optimization
…/RouteSelector.kt Co-authored-by: Bruce Hamilton <150327496+bjhham@users.noreply.github.com>
…/RouteSelector.kt Co-authored-by: Bruce Hamilton <150327496+bjhham@users.noreply.github.com>
Head branch was pushed to by a user without write access
|
Thanks For Feedback ! |
Resolve conflict in ContentTypeHeaderRouteSelector: combine plural contentTypes API from main with parameter-aware matching from PR (header.match(route) direction).
Subsystem
ktor-server
Motivation
https://youtrack.jetbrains.com/issue/KTOR-8443
Solution
Preserve Content-Type parameters when matching
contentTypeandacceptroute selectors.