Skip to content

undici transport: native header rejections, fileBody short-write detection, SOCKS proxy type #81

Description

@Wahbeh-Mohammad

Part of the audit remediation umbrella #67. Milestone 5. Severity: HIGH (first item), MEDIUM (rest). Requirements: TRANSPORT-11, TRANSPORT-12, TRANSPORT-30, BODY-13.

Current SDK behavior

  • Native header rejections escape send(). UNDICI_FORBIDDEN_HEADERS
    (packages/transport-undici/src/undici-transport.ts:58-62) drops content-length, host,
    transfer-encoding only. undici 6.28.0 (lib/core/request.js:397-409) throws
    InvalidArgumentError for keep-alive and upgrade, NotSupportedError for expect, and
    InvalidArgumentError for connection with a value other than close / keep-alive.
    toDispatchError (:221-231) maps these to a bare non-retryable TypeError; nothing is
    sent. toUndiciHeaders (:150-160) has no per-header guard, so a model-valid non-token name
    such as X Custom (core admits printable non-token bytes, ascii-validation.ts:29-33) is
    rejected by undici's isValidHTTPToken and the send fails. fetch-transport.ts:146-152 wraps
    each native.append in a try/catch and degrades to a drop; undici has no equivalent. No
    test exercises a non-token header name.
  • fileBody bypasses short-write detection. The file-body branch (:259-273) hands
    createReadStream(path, {start, end}) to undici directly. writeTo and its
    transferred === count invariant (packages/body-file/src/file-body.ts:75-78) never run.
    content-length is dropped, so undici frames the body chunked and the wire cannot detect a
    short write either. A 1 MB fileBody truncated to 10 bytes before send(): undici POSTs 10
    bytes and resolves 200; fetch raises TransportFailureError. The Phase 8a checklist (:80)
    marks BODY-13 done while recording the bypass.
  • A SOCKS proxy type throws undici's raw error. toProxyAgentOptions (:115-122) uses
    proxy.type as the URI scheme with no check. Core resolves ALL_PROXY=socks5://host:1080 to
    type: 'socks5' (config/proxy.ts:34,372-380). new ProxyAgent({uri: 'socks5://…'}) throws
    InvalidArgumentError('Invalid URL protocol: …') out of the public factory, untyped and
    undocumented.

Expected behavior

undiciTransport().send() does not throw a native error for any model-valid request. A
header the native layer cannot carry is dropped and logged, the same as in the fetch
transport. A file body that ends short of its declared length fails the send with a
TransportFailureError naming transferred-of-total on both transports. undiciTransport()
rejects an unsupported proxy type with a typed, documented error.

Notes and leads

  • Drop set: add expect, keep-alive, upgrade; drop connection values other than
    close / keep-alive. Validate each name against RFC 9110 token in toUndiciHeaders and
    degrade to a logged drop. Check FETCH_FORBIDDEN_HEADERS (fetch-transport.ts:45-50) too:
    on Node the global fetch is undici-backed and its Headers does not implement forbidden
    names, so the same rejections likely surface there as a retryable TransportFailureError.
  • File body: route through writeTo via the pumpBody path the streamed case uses, or wrap
    the read stream to count bytes and destroy with TransportFailureError when it ends short.
  • Proxy: reject proxy.type !== 'http' with a typed DexpaceError (or the documented
    TypeError), add @throws, and either record "SOCKS resolved by core, supported by neither
    transport" in docs/deviations.md or drop socks* from ProxyType before the first bump.
  • Every item gets a row in packages/transport-conformance that both transports run:
    Expect: 100-continue, Upgrade: websocket, a non-token name, truncate-after-stat.
  • Patch changesets for @dexpace/transport-undici, @dexpace/transport-fetch, and
    @dexpace/core if ProxyType changes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:transportTransport, async model, seams: TRANSPORT-* ASYNC-* SEAM-*spec:conformanceConformance-suite behavior, or a gap in the suite itselftype:bugDefect in shipped behavior

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions