fix(fifa17): route the client's lowercase usermassinfo to the Rust handler
The retail client sends BOTH casings. Observed twice on staging, each time inside a genuine client sequence: 16:56:56 route=squad-active 200 16:56:56 GET /ut/game/fifa17/usermassinfo -> passthrough -> 502 16:56:56 route=userMassInfo 200 classify matched the exact literal `userMassInfo`, so the lowercase request fell through to the Python upstream. Today that is a harmless 502 because the upstream is dead and the client immediately retries with the canonical casing - but on a deployment with Python ALIVE that request would be ANSWERED there, silently splitting authority away from Rust for a route Core owns. That is the real defect, not the wasted round trip. Fixed with the smallest possible alias: this one tail is matched case-insensitively, the rest of the table stays exact since no other route has ever shown a casing variant. Paths are NOT globally lowercased. Tests cover the canonical casing, lowercase, uppercase, two adjacent tails that must NOT be swept up by the alias (`usermassinfox`, `usermass`), and method semantics (PUT/POST still passthrough). With the alias reverted the test fails.
This commit is contained in:
@@ -1079,6 +1079,38 @@ fn classify_squad_and_usermassinfo_routes() {
|
||||
classify("GET", "/ut/game/fifa17/userMassInfo"),
|
||||
Route::UserMassInfo
|
||||
);
|
||||
// The retail client sends the lowercase tail too, immediately before the
|
||||
// canonical one. It must reach the SAME Rust-owned handler: falling through
|
||||
// to Python is a 502 here and, with Python alive, an authority split.
|
||||
assert_eq!(
|
||||
classify("GET", "/ut/game/fifa17/usermassinfo"),
|
||||
Route::UserMassInfo,
|
||||
"lowercase usermassinfo is a real retail request, observed twice"
|
||||
);
|
||||
assert_eq!(
|
||||
classify("GET", "/ut/game/fifa17/USERMASSINFO"),
|
||||
Route::UserMassInfo
|
||||
);
|
||||
// Adjacent tails must NOT be swept up by the case-insensitive arm.
|
||||
assert_eq!(
|
||||
classify("GET", "/ut/game/fifa17/usermassinfox"),
|
||||
Route::Passthrough,
|
||||
"the alias must match the whole tail, not a prefix"
|
||||
);
|
||||
assert_eq!(
|
||||
classify("GET", "/ut/game/fifa17/usermass"),
|
||||
Route::Passthrough
|
||||
);
|
||||
// Method semantics are unchanged: only GET is this route.
|
||||
assert_eq!(
|
||||
classify("PUT", "/ut/game/fifa17/usermassinfo"),
|
||||
Route::Passthrough
|
||||
);
|
||||
assert_eq!(
|
||||
classify("POST", "/ut/game/fifa17/userMassInfo"),
|
||||
Route::Passthrough
|
||||
);
|
||||
|
||||
// GET /squad/active and every numeric GET are the one Core-backed current
|
||||
// squad, matching the oracle's single-squad response regardless of URL id.
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user