refactor: extract the channel context, share Accept parsing, and fold duplicated blocks - #6
Open
ctxswitch wants to merge 1 commit into
Conversation
… duplicated blocks ChannelContext is now a FromRequestParts extractor, so the four-line resolve prologue leaves 18 handlers and the channel field leaves all seven per-route path structs. put_reference takes its context as a Result and resolves the rejection in the body: extractors run before the body, so rejecting early would answer a syntactically broken request with a channel error instead of a 400. negotiate_python and negotiate_npm shared roughly 25 byte-identical lines, and the two tie-breaks turn out to be the same function once the variables are renamed. Both now share media_range, offer, acceptable, and outranks, leaving each negotiator its media-type table and one call. The per-protocol default for a wildcard covering both representations -- Python serves JSON, npm abbreviated -- now lives visibly in the argument order. Also folds the OutOfSpace arm into cache_write_failure so all three PUT paths share it, replaces unix_time with the injected Clock, extracts fresh_outcome and revalidated from fetch_url, collapses the fetch_npm chain and the three select! blocks, shares publish_temporary, upstream_response, content_type, and content_length, merges the NotFound and Deleting response arms, and has SpaceLedger::new call refresh instead of repeating its match.
3 tasks
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.
Summary
Second half of phase four. Based on
cleanup/phase-4a-metrics-errors(#5). Net−118 lines across 9 files.
ChannelContextis now aFromRequestPartsextractor. The four-lineresolveprologue leaves 18 handlers (11 in
mod.rs, 7 inpackages.rs) and thechannel: Option<String>field leaves all seven per-route path structs. Six handlersstop taking
HeaderMapentirely andcargo_confignow takes onlyChannelContext.The two Accept-header negotiators now share their parsing.
media_range,offer,acceptable, andoutranksare extracted, leaving each negotiator its media-typetable plus one call. The two tie-breaks turned out to be byte-identical once the
variables are renamed, so
outranks(preferred, other)covers both — Python callsoutranks(json, html), npm callsoutranks(abbreviated, full). The per-protocoldefault for a wildcard range covering both representations now lives visibly in the
argument order rather than in two separately-maintained comparisons, which is what let
them drift apart in the first place.
Plus a dozen smaller folds: the
OutOfSpacearm is absorbed intocache_write_failureso all three PUT paths share it;unix_timeis replaced by theinjected
Clock;fresh_outcomeandrevalidatedcome out offetch_url(~40 linesshorter); the
fetch_npm→fetch_encoded→fetch_encoded_url→fetch_encoded_url_with_suffixchain collapses andProxyService::urlgoes private;publish_temporary,upstream_response,content_type, andcontent_lengthareshared;
proxy::header_lengthis deleted as a character-identical twin; the threetokio::select!blocks collapse into onebiasedblock; theNotFound/Deletingresponse arms merge; and
SpaceLedger::newcallsrefresh()instead of repeating itsmatch.
Verification
make ciclean, includingclippy --all-targets -- -D warnings; 138 tests.tests/integration/channels.rs(961 lines, both route forms, protected and openaccess, every data route) passes unchanged — it is the real check on the extractor
refactor, the rest of which the compiler validates.
wildcard_accept_ranges_never_outrank_a_named_representationpasses unchanged. Itis table-driven over both npm and python and pins the differing
application/*defaults that had to survive the merge.
Channel expiry and lifecycle tests pass after the
Clockinjection.Behaviour was verified against the vendored axum 0.8.9:
PathreadsUrlParamsviaextensions.get()rather thanremove(so a handler can take bothChannelContextand its ownPath<T>), the path deserializer maps structs throughMapDeserializerwithdeserialize_ignored_anyfor unknown keys (soArtifactPathignores the
channelcapture), andinsert_url_paramsalways inserts even forzero-capture routes.
make ciDocumentation and examples are accurate
New or changed behavior has test coverage
Operational impact
One log message changed. The two copies of the cache-write failure path had drifted
and logged different text —
"artifact publication failed"and"build-cache write failed". The shared helper logs"cache write failed", so both former messages aregone.
One error-body change on a pathological input: if a path segment percent-decodes to
invalid UTF-8, the 400 now carries the
invalid_channelJSON body fromChannelContextrather than axum's plain-textPathrejection. Still a 400; no testcovers it either way.
No metric, route, storage format, configuration, or security boundary changes.
Review notes
Start at
put_reference(src/transport/http/mod.rs:554) — it is the one handlerthat could not take a plain
ChannelContext. Extractors run before the body, sorejecting there turned
malformed_json_still_precedes_protected_channel_authorization(
tests/integration/channels.rs:694) from a 400 into a 401. It takesResult<ChannelContext, Response>and resolves the rejection after the body parses,which preserves the ordering exactly. That existing test is what caught it.
Two plan items were declined, both reported rather than forced:
checked()was extracted inchannel/service.rs. The plan asked for one, butthe existing
authorizealready is that function verbatim — addingchecked()would have been a third name for the same three lines.
authorize_with_leasenowcalls
authorize. The pre-gate check is kept, with the comment the plan asked forexplaining that it is what stops
ChannelGates::gate()inserting a permanentDashMapentry per unknown channel id.rewrite_metadata'sTransform::Nonearm stays. It is genuinely dead, butremoving it cleanly means splitting
TransformintoNoneplus a three-variantMetadataTransform, touching both constructors,upstream_accept,cache_variant,rewrite_metadata,cached_outcome'smatches!, and thefetch_urldispatch — anew type and six edit sites to delete one zero-cost line. It was not replaced with
unreachable!()either, since that is the same dead code by another name.Noted for a later phase, not addressed here:
put_reference'sReference::parseandArtifactId::parsefailures return JSONapi_errorbodies whileput_artifact'sequivalents return bare status codes — sibling routes with inconsistent error-response
policy.