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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions