Extract fast-socks5 v1.0.0's non-net lib.rs region into src/vendor/mod.rs (scaffolding-pinned root; the task's lib.rs target name corrected — a second root file would conflict, see task Notes): consts, Socks5Command (as_u8/from_u8 made pub), AuthenticationMethod, SocksError pruned to the extracted region's consumers (no anyhow/ Redaction/InvalidHeader/ReplySocks4Error/ArgumentInputError), the Result alias, ReplyError codec, UdpHeaderError + new_udp_header/ parse_udp_request. util/target_addr.rs gains TargetAddr/AddrError (minus resolve_dns + its two variants)/ToTargetAddr/Addr/read_address; util/stream.rs gains the read_exact!/ready! macros (de-exported to pub(crate) use) + ConnectError + to_reply_error. SocksServerError lands verbatim in server.rs early — SocksError's #[from] needs it before the typestate task. 16 first-party codec tests (round-trips, mapping tables, garbage-RSV/unknown-ATYP); no sockets, no env_logger. Newer-clippy style lints allowed at module level in vendored files (verbatim diff posture, rationale recorded). Verification: cargo test (16 pass) + --all-features; clippy --all-targets -D warnings (native + wasm32); cargo check --target wasm32-unknown-unknown; cargo fmt --check; cargo doc. Negative sweeps: no anyhow/log/tokio::net/socket2/tokio-stream/ async-trait under src/vendor/; no #[macro_export]; resolve_dns and the pruned error variants absent.
12 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level | |
|---|---|---|---|---|---|---|---|---|
| implementation/vendor-wire-vocabulary | Vendor — the wire vocabulary (consts, commands, codecs, errors, macros) | completed |
|
narrow | low | component | implementation |
Description
Extract the pure wire vocabulary from fast-socks5 v1.0.0 into
src/vendor/ — the RFC 1928 codecs and error enums that everything
else (typestate, client sessions, producer/consumer layers) consumes.
This is the "codecs" row of vendor.md's extraction table plus the
lib.rs non-net region. Copy from /workspace/fast-socks5 (read-only
reference checkout) and apply the extraction-time adjustments; the
result must be wasm-clean by construction (no tokio::net, no
anyhow, no log).
What is extracted (upstream file → in-tree target):
src/lib.rs→src/vendor/lib.rs(new file — upstream'slib.rscontent minus the cut regions):constsmodule verbatim (allSOCKS5_*constants).Socks5Commandenum +as_u8/from_u8(make bothpub— the producer's command dispatch and the consumer's request writer both need them; upstream keeps them private with#[allow(dead_code)]).AuthenticationMethodenum + impls (consumed by the client session'suse_streampath; keep as-is).ReplyErrorenum +as_u8/from_u8verbatim.UdpHeaderErrorenum,new_udp_header,parse_udp_requestverbatim (the ASSOCIATE datagram codec — vendor.md's codecs row).Result<T, E = SocksError>type alias.- NOT extracted: the net-heavy test module (upstream
lib.rslines 345–520 — it binds real sockets; the crate's own test task covers these edge cases), thesocks4module declaration.
src/util/target_addr.rs→src/vendor/util/target_addr.rs:AddrError,TargetAddr(+is_ip/is_domain/to_be_bytes/into_string_and_port),ToSocketAddrsimpl,Displayimpl,ToTargetAddrtrait + all impls,Addrenum,read_address— verbatim.- NOT extracted: the
resolve_dnsmethod (POC #4's gate map — it is the one net-touching member;tokio::net::lookup_hostis not in the wasm-clean graph). Delete the method;AddrError:: DNSResolutionFailed/NoDNSRecordsgo with it (see adjustments). - Drop the
debug!log calls (upstreamlog→ dropped or re-pointed attracing; these are per-octet debug traces — drop them).
src/util/stream.rs→src/vendor/util/stream.rs:read_exact!andready!macros verbatim. Adjustment: they are#[macro_export]upstream (crate-root exported, which would pollute the alksocks public API); convert to plainmacro_rules!withpub(crate) usescoping inside the vendor module so they stay internal (the wrapper's own code gets its own macros; the vendor's are implementation detail).ConnectErrorenum +to_reply_errorverbatim (the reply-code mapping vocabulary — consumed by the dial seam's error mapping).- NOT extracted:
tcp_connect/tcp_connect_with_timeout(thetokio::net::TcpStreamdialers — POC #4's gate map; the crate's local backend is first-party tokio code, ADR-008).
SocksError(insrc/vendor/lib.rs) — the error vocabulary, pruned to what the extracted region + the crate's error surface actually consumes (vendor.md: "the vendoredSocksError/SocksServerErrorstay the wire-level vocabulary"):- Keep:
Io,AuthMethodUnacceptable,UnsupportedSocksVersion,ExceededMaxDomainLen,AuthenticationRejected(String),ServerError(#[from] SocksServerError),UdpHeaderError(#[from] UdpHeaderError),AddrError(#[from] AddrError),ReplyError(#[from] ReplyError). - Drop:
Redaction,InvalidHeader(dead upstream — no consumer in the extracted region),ConnectError(#[from] ConnectError)(its only producer was the cuttcp_connect*;ConnectErroritself stays — the dial seam maps it),ReplySocks4Error(socks4 is cut),ArgumentInputError(no consumer),Other(#[from] anyhow::Error)(anyhow is dropped — vendor.md's adjustments). - Note:
AuthenticationRejected(String)onSocksErroris the client-side variant (client.rs uses it with a message);SocksServerError::AuthenticationRejected(unit) is the server-side one — both stay, each in its own enum.
- Keep:
Extraction-time adjustments (mechanical, per ADR-011 §Amendment +
vendor.md): drop anyhow wrapping, drop log calls, prune
error variants whose only producers/consumers were cut, keep
thiserror derives. No behavior change: every kept codec's wire
behavior is byte-identical to upstream v1.0.0.
Acceptance Criteria
src/vendor/lib.rs,src/vendor/util/{mod,stream,target_addr}.rsexist with the inventory above;cargo testcompiles (boundary note: the vocabulary lives insrc/vendor/mod.rs, not a second root filesrc/vendor/lib.rs— the completed scaffolding task pinned the vendor root asmod.rswith upstream file names preserved; a second root file would be an E0758 conflict. Upstream'slib.rscontent minus the cut regions is whatmod.rsnow carries.)cargo check --target wasm32-unknown-unknowncleancargo check(native, default features) clean- No
anyhow,log,tokio::net,socket2,tokio-stream,async-traitanywhere undersrc/vendor/ Socks5Command::as_u8/from_u8arepub(the wrapper needs them; upstream had them private)read_exact!/ready!are not exported at the crate root (no#[macro_export]); they resolve inside the vendor moduleTargetAddrhas noresolve_dnsmethod;AddrErrorhas noDNSResolutionFailed/NoDNSRecordsvariantsSocksErrorhas noOther(anyhow::Error), noRedaction, noInvalidHeader, noReplySocks4Error, noArgumentInputErrorvariantscargo clippy --all-targets -- -D warningsandcargo fmt --checkclean- Unit tests for the codecs pass:
to_be_bytes/read_addressround-trip (v4/v6/domain),new_udp_header/parse_udp_requestround-trip,ReplyError::as_u8/from_u8mapping table — ported from upstream's non-net test regions where extractable (vendor.md's "non-net test modules" row), adjusted to the crate's test layout (noenv_logger, no real sockets)
References
- docs/architecture/vendor.md (the extraction table + the cut table)
- docs/architecture/decisions/011-inline-vendor.md §Amendment (the mechanical adjustments)
- docs/architecture/decisions/002-protocol-base.md (the codecs are the wire vocabulary; "no second codec, ever")
- Upstream:
/workspace/fast-socks5/src/lib.rs,/workspace/fast-socks5/src/util/target_addr.rs,/workspace/fast-socks5/src/util/stream.rs - POC #4 gate map: docs/research/poc-connect-wasm-findings.md (lib.rs/util rows)
Notes
- Module placement correction: the task text says
src/vendor/lib.rs, but the completed scaffolding task pinned the vendor root assrc/vendor/mod.rs(skeleton withmod+ submodule declarations already committed,57b107b). A second root file (lib.rsalongsidemod.rs) is an E0758 conflict, so the vocabulary landed inmod.rs— upstream'slib.rscontent minus the cut regions, appended after the scaffolding module doc. The review task's file-by-file diff vs upstream is unaffected (the upstreamlib.rsregion maps tomod.rs; noted here for the reviewer). SocksServerErrorlands early:SocksErrorkeepsServerError(#[from] server::SocksServerError)per the task's keep-list, butserver.rswas a stub — a#[from]needs the type now. Upstream definesSocksServerErrorat the top ofserver.rs; it landed there verbatim (enum +to_reply_error, includingUnexpectedUdpControlGarbage) as the first item of the server-typestate task's inventory, with a module doc noting the early landing. The server task's remaining inventory is unchanged.- Verbatim-code lint posture: the copied upstream regions trip
newer-clippy style lints (
match_like_matches_macro,legacy_numeric_constantsforu8::max_value(),io_other_errorforio::Error::new(Other),needless_lifetimes,redundant_closure). Churning vendored code to satisfy a newer clippy would break the mechanical per-file diff posture (vendor.md §Maintenance Posture; review task criterion 1), so the lints are allowed at module level with the rationale recorded. Behavior is untouched. AuthenticationMethod::as_u8/from_u8stay private with upstream's#[allow(dead_code)]: the client session task'ssend_version_and_methodsconsumes them when it lands. Making them pub now would be ahead of need (the task pins pub only forSocks5Command).ready!macro: upstream's server typestate consumes it (thetransfer/wait_on_tcpregion); nothing in the vocabulary region does. It rides with#[allow(unused_macros)]/#[allow(unused_imports)]until the typestate lands — kept verbatim now so the util diff stays complete.- Tests: the vocabulary region's unit tests are first-party
(upstream's
lib.rstest module is the cut net-heavy region — none of its tests are extractable); the codec tests here follow the crate's test layout (tokio duplex forread_address, plain slice parsing forparse_udp_request, noenv_logger, no sockets).ConnectError::to_reply_errorandAddrError:: to_reply_errormappings are pinned too (the dial seam + the address-type reply mapping are wire-adjacent behavior). Vendored enums keep upstream's derives (noPartialEqwas added), so tests compare viaas_u8()/matches!rather than adding derives. - The
ToSocketAddrsimpl's error string still namesTargetAddr::resolve_dns()(upstream text preserved verbatim) even though the method is cut — noted in the module doc; a future consumer hitting that path gets the explicit-resolution message exactly as upstream produced it.
Summary
Extracted the wire vocabulary from fast-socks5 v1.0.0 per ADR-011
§Amendment + vendor.md: upstream lib.rs's non-net region (consts,
Socks5Command with pub as_u8/from_u8, AuthenticationMethod,
the pruned SocksError (no anyhow/Redaction/InvalidHeader/
ConnectError-from/ReplySocks4Error/ArgumentInputError), the
Result alias, ReplyError codec, UdpHeaderError +
new_udp_header/parse_udp_request) into src/vendor/mod.rs (the
scaffolding-pinned root; the task's lib.rs target name corrected —
see Notes), AddrError/TargetAddr/ToTargetAddr/Addr/
read_address minus resolve_dns into util/target_addr.rs, and
the read_exact!/ready! macros (de-exported to pub(crate) use)
ConnectError+to_reply_errorintoutil/stream.rs.SocksServerError(enum +to_reply_error) landed verbatim inserver.rsearly —SocksError's#[from]needs it before the typestate task lands. 16 first-party unit tests cover the codecs (v4/v6/domain round-trips, UDP header/parse incl. frag/payload/garbage RSV/unknown ATYP, reply-code mapping table, command mapping,to_reply_errormappings,ToTargetAddrconversions, domain-length cap). Verified:cargo test(16 pass),--all-features, clippy--all-targets -- -D warningsnative + wasm32,cargo check --target wasm32-unknown-unknown,cargo fmt --check,cargo doc, and the negative sweeps (no anyhow/log/tokio::net/socket2/ tokio-stream/async-trait in vendor code; no#[macro_export]; resolve_dns + the five pruned error variants absent).