mirror of
https://github.com/nushell/nushell.git
synced 2026-10-28 08:54:52 +08:00
Fixes #9065 ## Description `http get 'http://[fe80::13%eth0]'` (and the other `http *` commands) fail because `url::Url::parse` does not support IPv6 zone IDs (e.g. `%eth0`), per the WHATWG URL standard. `curl` handles these URLs fine. The fix now validates and drives requests with `http::Uri`, the same parser ureq uses, so nushell and ureq agree on which URLs are valid. 1. **`crates/nu-command/src/network/http/client.rs`** - `http_parse_url` validates with `http::Uri` instead of `url::Url` (which rejects zone IDs). It returns the raw URL string; the `strip_ipv6_zone_id` helper and the returned `Url` are gone. - A new `authority_is_well_formed` check rejects URLs that `http::Uri` would otherwise accept leniently, e.g. trailing garbage after an IPv6 literal (`[fe80::13%eth0]foo`) or non-numeric/out-of-range ports (`host:abc`, `host:99999`). These would silently send the request to a different host or port. - `request_set_host_header` sets the `Host` header without the zone ID (matching curl) when the authority contains one, so strict servers don't reject the request. A user-provided `Host` header is left untouched. - `transform_response_using_content_type` derives the `text/plain` file extension from `http::Uri::path()` so zone-ID URLs no longer fail after the request has been sent. 2. **`crates/nu-command/src/network/http/resolver.rs`** - `uri.host()` returns IPv6 addresses wrapped in square brackets (e.g. `[fe80::13%eth0]`), which `dns_lookup::getaddrinfo` cannot resolve. The brackets are stripped before resolution, so `getaddrinfo` handles the zone ID natively (converting the interface name to a scope ID). - The RFC 6874 `%25` form (e.g. `[fe80::1%25lo0]`) is decoded to a literal `%` before `getaddrinfo`. - `host` stays an `Option` and is passed to `getaddrinfo` as-is. ## User-facing changes (Release notes) `http get`, `http post`, and the other `http *` commands now accept **`http://`** URLs with IPv6 literals and link-local zone IDs, e.g. `http get 'http://[fe80::13%eth0]'`. Plain IPv6 literals (e.g. `http get 'http://[::1]:8080/a.txt'`) work as well. Previously these URLs failed to parse or resolve. Note: `https://` URLs with a zone ID are **not** supported. ureq builds the rustls `ServerName` from the bracket-stripped host, and `fe80::13%eth0` is neither a valid IP nor a valid DNS name, so TLS handshakes fail. This is a ureq/rustls limitation and cannot be fixed from nushell. ## Tests - `cargo check -p nu-command` passes - `cargo test -p nu-command --lib network::http` — 20 tests pass, including: - `test_http_parse_url_with_ipv6_zone_id` - `test_http_parse_url_rejects_invalid_ipv6_with_zone_id` - `test_authority_is_well_formed` - `test_request_set_host_header_strips_zone_id` - `test_request_set_host_header_leaves_other_urls_alone` - `cargo test -p nu-command --test tests -- commands::network::http` — 87 tests pass, including the new `http_get_ipv6_literal`, which binds `[::1]` and makes a real `text/plain` request through `DnsLookupResolver`. - `cargo fmt --all -- --check`, `cargo clippy -p nu-command --all-targets -D warnings` and `typos` are clean. ## Review feedback All findings from the review have been addressed: 1. **Text/plain responses fail after the request is sent** — `transform_response_using_content_type` now uses `http::Uri::path()` instead of `url::Url::parse`. 2. **Zone ID ends up in the `Host` header** — `request_set_host_header` strips it (like curl); a user-set `Host` header is respected. 3. **Validate with `http::Uri` instead of strip-and-reparse** — done; `strip_ipv6_zone_id` and the returned `Url` are removed. URLs that ureq rejects (e.g. `http://[fe80::1%lo 0]:18913/`) are now rejected up front by `http_parse_url`. 4. **RFC 6874 `%25` form can't resolve** — the resolver decodes `%25` to `%` before `getaddrinfo`. 5. **No test makes a real request to an IPv6 literal** — added `http_get_ipv6_literal`. 6. **Keep `host` as an `Option`** — done. 7. **HTTPS zone-ID URLs still fail** — a ureq/rustls limitation; the release notes above are now scoped to `http://`. --------- Co-authored-by: Jarvis-AI-42 <skyfireitdiy@gmail.com>
74 lines
841 B
Plaintext
74 lines
841 B
Plaintext
/target
|
|
/scratch
|
|
**/*.rs.bk
|
|
history.txt
|
|
tests/fixtures/nuplayground
|
|
crates/*/target
|
|
.mailmap
|
|
|
|
# Debian/Ubuntu
|
|
debian/.debhelper/
|
|
debian/debhelper-build-stamp
|
|
debian/files
|
|
debian/nu.substvars
|
|
debian/nu/
|
|
|
|
# macOS junk
|
|
.DS_Store
|
|
|
|
# JetBrains' IDE items
|
|
.idea/*
|
|
|
|
# VSCode's IDE items
|
|
.vscode/*
|
|
|
|
# JetBrains' Fleet IDE
|
|
.fleet/*
|
|
|
|
# Visual Studio Extension SourceGear Rust items
|
|
VSWorkspaceSettings.json
|
|
unstable_cargo_features.txt
|
|
|
|
# Helix configuration folder
|
|
.helix/*
|
|
.helix
|
|
wix/bin/
|
|
wix/obj/
|
|
wix/nu/
|
|
|
|
# Coverage tools
|
|
lcov.info
|
|
tarpaulin-report.html
|
|
|
|
# benchmarking
|
|
/tango
|
|
|
|
# Visual Studio
|
|
.vs/*
|
|
*.rsproj
|
|
*.rsproj.user
|
|
*.sln
|
|
*.code-workspace
|
|
|
|
# direnv
|
|
.direnv/
|
|
.envrc
|
|
|
|
# nix
|
|
/result
|
|
/scripts/nix/result
|
|
|
|
# pre-commit-hooks
|
|
.pre-commit-config.yaml
|
|
|
|
# skills
|
|
.github/skills/*
|
|
|
|
# Claude settings
|
|
.claude
|
|
|
|
# Splashboard
|
|
.splashboard.toml
|
|
|
|
.jarvis/
|