77 lines
6.5 KiB
Markdown
77 lines
6.5 KiB
Markdown
# curl / wget CLI parity (Bare OS booter)
|
|
|
|
HTTP in Pear/Bare uses **WHATWG Fetch** (Node `fetch` or **`bare-fetch`** on `bare-http1` / `bare-https`), not libcurl or GNU wget (C). The lists below track how close the booter shims are to common CLI flags.
|
|
|
|
**History:** `-O` / `-o` mutual exclusion, `-I -L` with manual redirects and **`%{num_redirects}`**, and **`wget -c`** (Range / 206 / 416) landed in [`a7e08e09`](https://git.ssh.surf/snxraven/bare-operating-system/commit/a7e08e093ccfa4144493ac7428b0fdd5581d7b84). Later work added cookie jar, **`-J`**, **`--connect-timeout`**, `**--cacert` / `-k**`, **`BARE_OS_DNS_ALLOWLIST`**, Pear-safe fetch bootstrap (**`bare-os-ensure-bare-fetch.js`**), and **`wget --no-clobber`**.
|
|
|
|
## curl ([`lib/curl-cli.js`](lib/curl-cli.js))
|
|
|
|
- **URL interleaving, scheme guess (`http://`, `https:` for `//`)** — *supported* — [`http-fetch-url.js`](lib/http-fetch-url.js)
|
|
- **`-X` / `--request`** — *supported*
|
|
- **`-H` / `--header`** — *supported*
|
|
- **`-A` / `--user-agent`** — *supported* — Default `DEFAULT_CURL_USER_AGENT`; last `-A` or `-H` User-Agent wins
|
|
- **`-d`, `--data*`, `--json`** — *supported*
|
|
- **`-o` / `--output`** — *supported* — VFS path; multiple URLs → `FILE.N`
|
|
- **`-O` / `--remote-name`** — *supported* — Saves using URL basename (like curl)
|
|
- **`-T` / `--upload-file`** — *supported* — PUT
|
|
- **`-I` / `--head`** — *supported*
|
|
- **`-i` / `--include`** — *supported*
|
|
- **`-L` / `--location`** — *supported* — `-I -L` uses HEAD then GET after redirect (curl semantics); plain GET uses `redirect: follow`
|
|
- **`-f` / `--fail`** — *supported* — Exit 22
|
|
- **`-s` / `-S` / `-v`** — *supported*
|
|
- **`-u` / `--user`** — *supported* — Basic auth only
|
|
- **`-m` / `--max-time`** — *supported* — Whole-request `AbortSignal` timeout; combined with `--connect-timeout` as **`min(max-time, connect-timeout)`** when both are set
|
|
- **`-w` / `--write-out`** — *partial* — `%{http_code}`, `%{url_effective}`, `%{size_download}`; `%{num_redirects}` non-zero only for `-I -L` manual hop path
|
|
- **`-V` / `--version`, `-h` / `--help`** — *supported*
|
|
- **Cookie jar, `--cookie`, `-b`, `-c` / `--cookie-jar`** — *supported* — JSON map `hostname → { name → value }` on **`~/.config/bare-os/curl/cookies.json`** (or path from `-c`); `-b` file or `name=value`; see `curl-cli.js`
|
|
- **`--connect-timeout`** — *supported* — Seconds (integer or decimal); sets the abort deadline when used alone, or **`min`** with **`--max-time`** when both are set. `**-Y` / `-y`** remain out of scope
|
|
- **`--cacert`, `-k` / `--insecure`** — *supported* — Global `fetch`: Node **undici** `Agent`. When **`ctx.httpFetch`** is set, TLS intent is passed as **`init.bareOsCurlTls`** (`insecure`, optional **`caPem`**, optional **`pinnedSha256`** from **`BARE_OS_TLS_PIN_SHA256`**) for the host implementation
|
|
- **TLS client certs (mutual TLS)** — *out of scope* — Stack only
|
|
- **HTTP/2, HTTP/3, SOCKS, FTP, SCP** — *out of scope*
|
|
- **`-J` content-disposition filename** — *supported* — With **`-O`**; uses **`Content-Disposition`** basename only; rejects **`..`** and absolute paths in the server-provided name
|
|
|
|
## wget ([`lib/wget-cli.js`](lib/wget-cli.js))
|
|
|
|
- **URL interleaving, short clusters (`-qO-`, `-T30`)** — *supported*
|
|
- **`-O` / `--output-document`** — *supported* — `-` = stdout; one URL only with `-O`
|
|
- **`-P` / `--directory-prefix`** — *supported* — Cannot combine with `-O`
|
|
- **`-q` / `--quiet`** — *supported*
|
|
- **`-U` / `--user-agent`** — *supported* — Default `DEFAULT_WGET_USER_AGENT`
|
|
- **`-T` / `--timeout`** — *supported* — Same semantics as curl `--max-time` (whole request)
|
|
- **`--header`, `--post-data`, `--post-file`** — *supported*
|
|
- **`-c` / `--continue`** — *supported* — `Range: bytes=<existing>-` when output file exists; 206 appends, 200 replaces full file
|
|
- **`-V` / `-h`** — *supported*
|
|
- **Recursive / spider / FTP / WARC** — *out of scope*
|
|
- **`--no-clobber` / `-nc`** — *supported* — Skip download when the target file already exists and has size > 0 (not combined with `--continue`)
|
|
- **`-N` timestamping** — *out of scope*
|
|
|
|
## Fetch / bare-fetch vs curl (`-I` + `-L`)
|
|
|
|
**curl** sends **HEAD**, and after a **3xx** follows with **GET** on the new URL. **`bare-fetch`** reuses the original `Request` `init` on redirect, so **HEAD stays HEAD on every hop**, which breaks many servers/CDNs.
|
|
|
|
We **do not** depend on bare-fetch for that case: [`fetchHeadWithLocationFollow`](lib/curl-cli.js) implements manual hops (HEAD → GET after redirect). See **Upstream (bare-fetch)** below if you want this fixed in the library.
|
|
|
|
## Upstream (bare-fetch)
|
|
|
|
**Tracking:** Bare OS implements **`curl -I -L`** with manual redirects so the first hop can stay **HEAD** and a **3xx** response can be followed with **GET** (see **`fetchHeadWithLocationFollow`**). Consider an upstream **`bare-fetch`** option for “curl-like” redirect method switching so other callers get the same behavior without a custom loop.
|
|
|
|
**Issue tracker row (keep updated):**
|
|
|
|
| Area | Upstream repo | Issue / PR | Status | Last checked |
|
|
| --- | --- | --- | --- | --- |
|
|
| `HEAD` + redirect method switching (`curl -I -L` semantics) | [`holepunchto/bare-fetch`](https://github.com/holepunchto/bare-fetch) | _TBD_ (add link once filed) | open | 2026-04-26 |
|
|
|
|
When the issue is filed, replace `_TBD_` with the direct GitHub URL and keep this row current during release checklist updates.
|
|
|
|
**Suggested issue title:** Redirect following preserves original method (HEAD on every hop); optional curl-like mode?
|
|
|
|
**Body (paste into GitHub):**
|
|
|
|
> When using `fetch(url, { method: 'HEAD', redirect: 'follow' })`, redirects reuse the outer `init`, so each hop stays HEAD. Real **curl -IL** uses HEAD on the first request, then **GET** after a redirect. That behavior matters for CDNs that return 302 to a URL that only answers GET.
|
|
>
|
|
> **Request:** Document this as spec-accurate Fetch behavior, and/or add an option (e.g. on `Request` init or fetch options) to switch redirect method to GET after a redirect when the initial method was HEAD, matching common CLI expectations.
|
|
>
|
|
> **Context:** Bare OS implements a fetch-based `curl` shim and currently uses `redirect: 'manual'` plus manual hops for `-I -L` instead of `redirect: 'follow'` for that reason.
|
|
|
|
Repository: [holepunchto/bare-fetch](https://github.com/holepunchto/bare-fetch). Workspace pin is **`bare-fetch@^3.2.0`** (major 3: **`Headers.getSetCookie()`**, **`response.type`**). In-guest **`web_fetch`** forwards those fields when present.
|