fix: match the endpoint method filter case-insensitively - #345
Open
FrameAutomata wants to merge 1 commit into
Open
fix: match the endpoint method filter case-insensitively#345FrameAutomata wants to merge 1 commit into
FrameAutomata wants to merge 1 commit into
Conversation
getHTTPEndpoint concatenates http.request.method verbatim, so rows like
"get /api/lowercase" genuinely exist. The dropdown only ever offers the
7 canonical uppercase methods and normalizeMethodFilter upper-cases what
it is given, so no selection could reach those rows on any backend:
they were in the list, counted in the unfiltered total, and invisible the
moment a method was picked.
Upper-cases the column rather than trusting the value's case, so the
result cannot depend on how the caller cased its argument:
embedded SUBSTR(endpoint, 1, N) = :method
-> UPPER(SUBSTR(endpoint, 1, N)) = :method
ClickHouse startsWith(endpoint, ?)
-> startsWith(upper(endpoint), ?)
SUBSTR stays rather than LIKE: methodFilter reaches SQL as a value, and
LIKE would read % and _ in it as wildcards. upper() rather than
upperUTF8() on ClickHouse because SQLite's UPPER is ASCII-only, and ASCII
is the whole of the method-token range RFC 9110 allows -- so all three
backends answer identically.
This replaces the exclusion TestEndpointRepository_FindGroupedByEndpoint_
MethodFilter asserted. That assertion was deliberate when written
(c7a5dca aligned the embedded backends onto ClickHouse's long-standing
case sensitivity), so it is worth being explicit that this is a decision
reversed, not a bug: the reachability problem it left is #321. "GETAWAY
/api/cars" still must not match -- the comparison is a whole
space-terminated token, not a string prefix -- and that stays asserted.
Verified against a running backend with GET/get/Get/GETAWAY/POST rows
seeded: /api/endpoints/grouped and /api/endpoints/chart both return the
same three GET-family rows for "GET", "get" and "GeT", POST returns one,
and GETAWAY is excluded from all of them.
Closes #321.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #321. Implements option 2 from the issue discussion — "I'd honestly do case insensitive querying".
The problem
getHTTPEndpoint(trace_converter.go) concatenateshttp.request.methodverbatim with noToUpper, soget /api/lowercaserows genuinely exist. The dropdown only ever offers the 7 canonical uppercase methods, andnormalizeMethodFilterupper-cases whatever it is given — so no dropdown selection could ever reach such a row, on any backend. They appeared in the unfiltered list, counted toward the total, and vanished the moment a method was picked.The fix
Upper-case the column, not the caller's argument, so the result can't depend on how the request cased its input:
SUBSTR(endpoint, 1, N) = :methodUPPER(SUBSTR(endpoint, 1, N)) = :methodstartsWith(endpoint, ?)startsWith(upper(endpoint), ?)Two deliberate choices:
SUBSTRstays,LIKEis still avoided.methodFilterreaches SQL as a value, andLIKEwould read a%or_in it as a wildcard. KeepingSUBSTRkeeps that property while adding the case fold.upper(), notupperUTF8(), on ClickHouse. SQLite'sUPPERis ASCII-only, and ASCII is the entire range RFC 9110 allows in a method token — so all three backends answer identically rather than diverging on non-ASCII input.This reverses a deliberate decision, not a bug
c7a5dcaeshippedTestEndpointRepository_FindGroupedByEndpoint_MethodFilterassertingget /api/lowercaseis excluded, as part of aligning the embedded backends onto ClickHouse's long-standing case sensitivity. That alignment was right; the reachability hole it left is what #321 is about. Worth flagging explicitly so the changed assertion doesn't read as an accident.What stays asserted:
GETAWAY /api/carsmust still not matchGET. The comparison is a whole space-terminated token, not a string prefix.A second test covers the argument side —
GET,getandGeTall return the same three rows.Verification
Unit tests pass on both embedded backends (default build and
-tags telemetry_duckdb); the ClickHouse variant builds and vets under-tags 'transactional_pg telemetry_ch'(no CH server here to run it against).Then against a running backend on a scratch SQLite DB, with
GET /api/users,get /api/lowercase,Get /api/mixed,GETAWAY /api/carsandPOST /api/usersseeded:Left alone on purpose
Option 3 from the issue —
ToUpperat ingest ingetHTTPEndpoint— is not done here. It would not reach rows already stored (which is the actual complaint), and it merges two endpoint groups that are currently distinct, which is a data-shape change rather than a filter fix. Still open if you want canonical storage going forward; it composes with this rather than replacing it.Also unchanged: the list still groups
get /xandGET /xas two rows. Only the filter folds case; the grouping is what ingest decided.🤖 Generated with Claude Code