An id that names nothing is answered rather than refused #48
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
An id that names nothing is answered rather than refused.
Every one of these was measured against a production database, where the id is
one no row carries:
/Items?ParentId=<unknown>/Genres?ParentId=<unknown>/Studios,/Artists,/Artists/AlbumArtists,/MusicGenres— same/Items/Filters?ParentId=<unknown>/Items/<unknown>/InstantMix/Items/<unknown>/RemoteImages/Users/<unknown>/Items/<id>/Intros/Persons/<unknown name>/Items/<unknown>/CollectionsA client asking about something that is gone is told it is fine and handed an
empty answer, where upstream tells it the id is bad. The last one is the odd
member of the set — upstream refuses it as unauthorized rather than missing.
Found by replaying scenarios written for the reference library against a
different one, so every id in them named nothing. Against the fixture they all
name something, which is why this has never shown up.
The rule, read from upstream.
LibraryManager.GetParentItem(LibraryManager.cs:3109) is what every routetaking a
parentIdresolves through:and
ExceptionMiddleware.GetStatusCode(ExceptionMiddleware.cs:127) maps theexception types onto the statuses:
ArgumentExceptionAuthenticationExceptionResourceNotFoundException,FileNotFoundException,DirectoryNotFoundExceptionSo the 400s in this issue are one cause with seven call sites — the controllers
that call
GetParentItemareItems,Filter,Artists,Genres,MusicGenres,StudiosandYears. A parent id naming nothing is not a filterthat matches nothing; it is a bad argument.
The 404s are a separate group: a route that looks an item up and answers
NotFoundwhen it is not there. The one 401 (/Items/{id}/Collections) is athird, and reads as an authentication failure raised before the lookup.
Holding the change until #47, #49, #52 and #53 land — they are being fixed in
the same route files and would conflict.
A parent naming nothing is now a bad argument rather than a filter that matches
nothing.
Upstream resolves one through
LibraryManager.GetParentItem(
LibraryManager.cs:3109):and
ExceptionMiddleware.GetStatusCode(ExceptionMiddleware.cs:127) turnsArgumentExceptioninto 400,AuthenticationExceptioninto 401 and thenot-found family into 404.
So it is one cause with a fixed set of call sites, and the important half of the
work was finding which routes are not among them. Verified live against a
production instance, an id no row carries:
/Items/Genres,/MusicGenres,/Artists,/Artists/AlbumArtists,/Studios/Items/Filters/Items/Filters2/UserItems/Resume/Items/Suggestions/Search/Hints11 of 11 now agree.
/Items/Filters2is the one I got wrong first. Both filter listings share onenarrowing function here, so refusing inside it made Filters2 refuse too — and
upstream only calls
GetParentItemfromGetQueryFiltersLegacy(
FilterController.cs:71), not fromGetQueryFilters. Caught by checking everyroute against the running upstream rather than only the ones the issue named.
GetResumeItemsis the same shape: it readsparentId ?? Guid.Emptystraightinto the query and never resolves it.
There are tests both ways — the routes that refuse, and the ones that must keep
answering.
The 404 and 401 cases in this issue are separate causes: a route that looks an
item up and answers
NotFound, and one authentication failure raised before thelookup. Neither is the parent-resolution rule, and neither is fixed here.
The 404 half is done too, and 22 of 22 probes now agree with a running
upstream.
/Items/<unknown>/InstantMix,/Albums/…,/Songs/…/Items/<unknown>/RemoteImages(+/Providers)/Items/<unknown>/Collections/Users/<unknown>/Items/<unknown>/Intros/Persons/<unknown>/MusicGenres/<unknown>/InstantMix/Genres,/Studios,/Artistsby unknown nameThe rule is that a route whose feature this project excludes still resolves the
item first — upstream answers the empty listing only once it has one. A route
taking a name resolves nothing and answers whatever the name is, which is why
/MusicGenres/<unknown>/InstantMixstays 200 while the id-taking siblings donot.
A person is the single by-name route that refuses. Every other name has a row
stood up for it, because upstream's
GetItemByNamewrites one;GetPerson(
PersonsController.cs:143) answers with the person it has orNotFound.Three existing tests asserted the old answer — that an excluded feature answers
an empty listing for any id at all. They were asserting the absence of a lookup
rather than upstream's behaviour, and now use an item that exists, beside a new
test for the id that does not.
The one 401 this issue listed (
/Items/{id}/Collections) does not reproduce:upstream answers 404 there, and so do we. It was an artifact of the token the
original replay ran under.