. "$BST_LIB" # wget is the GNU HTTP/FTP retriever. It is the first network CLIENT on this # image: ethtool/iproute2/net-tools inspect and configure the stack, wget drives # a TCP connection end to end and speaks an application protocol over it. # # busybox ships a wget applet at the SAME update-alternatives link name # (/usr/bin/wget), so a bare `wget` exists even on an image where this port # failed to install. `require` below therefore only guards ABSENCE; the identity # case straight after it is what proves priority 100 took the link. A # present-but-busybox wget is `not ok`, never `skip` -- it is the tool being # broken, not the tool being missing. # # This build carries TLS: openssl 3.5.7 (BRINTOS-295) is the backend and # ca-certificates (BRINTOS-304) is the trust store. hwjs-cc#4 -- the static # merged-module refuse that denied this arm any TLS backend at all, and the # reason wget shipped --without-ssl until now -- closed 2026-07-12. What this # image still cannot offer is a TLS PEER; see the handshake case at the end. require wget wget/present # check_fail -- wget signals through its exit # STATUS as much as its diagnostic (1 generic, 4 network, 8 server error), so an # error case is only right when both halves are. check_out cannot express it: # it requires rc 0. check_fail() { _id=$1; _want=$2; _needle=$3; shift 3 _out=$("$@" 2>&1); _rc=$? case "$_out" in *"$_needle"*) _hit=1 ;; *) _hit=0 ;; esac if [ "$_rc" -eq "$_want" ] && [ "$_hit" -eq 1 ]; then bst_ok "$_id" else bst_notok "$_id" "rc=$_rc want=$_want needle:'$_needle' got:'$(_bst_1line "$_out")'"; fi } # has -- substring assertion over a value already read. has() { case "$3" in *"$2"*) bst_ok "$1" ;; *) bst_notok "$1" "want:'$2' got:'$(_bst_1line "$3")'" ;; esac } # --- identity: which wget answers to the name -------------------------------- # The busybox applet has no --version at all, so "GNU Wget" coming back from a # BARE `wget` is the update-alternatives assertion, not a version formality. check_out wget/version-gnu "GNU Wget" wget --version check_out wget/version-release "GNU Wget 1.21.4" wget --version check_out wget/help "-O, --output-document" wget --help # --- the TLS build contract -------------------------------------------------- # --version's feature list is generated from the preprocessor state of the build # that produced this binary (src/build_info.c), so these read the actual # configure outcome rather than a claim about it. "ssl" is a CHOICE group there: # it prints the backend it resolved to, so +ssl/openssl says which library is # linked, not merely that some TLS exists. check_out wget/feature-ssl-openssl "+ssl/openssl" wget --version check_out wget/feature-https "+https" wget --version # -ipv6 is load-bearing, not incidental: --disable-ipv6 is what routes a numeric # host through inet_addr() instead of getaddrinfo, keeping every case below out # of the static-glibc NSS trap (BRINTOS-77). check_out wget/feature-no-ipv6 "-ipv6" wget --version # The feature list is a claim the binary makes about itself; this is the case # that makes it falsifiable. An https:// URL now survives URL parsing and the # fetch reaches a real TCP connect, so with nothing listening on 443 the honest # answer is the NETWORK failure (exit 4). The pre-TLS build answered "HTTPS # support not compiled in" and exited 1 (URLERROR) without ever opening a socket # -- so rc 4 here, and not rc 1, is what separates a linked backend from a # renamed one. check_fail wget/https-connects 4 "Connection refused" \ wget -O /dev/null --tries=1 https://127.0.0.1:443/x # --- CLI contract ------------------------------------------------------------ check_fail wget/missing-url 1 "missing URL" wget # --- the network path: a real HTTP transaction over lo ----------------------- # The machine has no route off loopback and no second interface, so the only # server wget can reach is one this suite stands up. data/wget-httpd.tcl is that # server AND the client runs against it in one process -- see its header for why # a backgrounded server cannot work on a target whose sleep is a no-op. if command -v tclsh >/dev/null 2>&1; then out=$(tclsh "$BST_DATA/wget-httpd.tcl" 2>&1); rc=$? w() { printf '%s\n' "$out" | awk -v k="W-$1" '$1==k{sub(/^[^ ]+ /,"");print;exit}'; } # whole-payload gate first: everything after it reads values the payload only # prints if it got that far. case "$out" in *ALL-WGET-OK*) all=1 ;; *) all=0 ;; esac if [ "$rc" -eq 0 ] && [ "$all" -eq 1 ]; then bst_ok wget/httpd-payload else bst_notok wget/httpd-payload "rc=$rc $(_bst_1line "$out")"; fi # GET: status, and the body byte-for-byte as the server wrote it. check_eq wget/http-get-rc 0 "$(w get-rc)" check_eq wget/http-get-body "wget-loopback-ok" "$(w get-body)" # -O to a file, and the length wget wrote against the Content-Length it was # told -- the read loop, not just the connect. check_eq wget/http-outfile-rc 0 "$(w big-rc)" check_eq wget/http-outfile-size 4096 "$(w big-size)" # 404: exit 8 is "server issued an error response", distinct from 4 (network) # below. A tool that collapsed the two would pass one and fail the other. check_eq wget/http-404-rc 8 "$(w 404-rc)" has wget/http-404-msg "ERROR 404" "$(w 404-msg)" # --spider issues HEAD rather than GET: the server answers headers only and # wget must still call that success. check_eq wget/http-spider-rc 0 "$(w spider-rc)" # 302 -> /hello, followed to the same body as the direct GET. check_eq wget/http-redirect-rc 0 "$(w redirect-rc)" check_eq wget/http-redirect-body "wget-loopback-ok" "$(w redirect-body)" # --compression is registered only under HAVE_LIBZ, so accepting it at all # proves the zlib link; decoding a gzip Content-Encoding back to the plain # body proves the link works. if [ "$(w gzip-rc)" = "skip" ]; then bst_skip wget/http-gzip "this tclsh has no zlib command to build the payload" else check_eq wget/http-gzip-rc 0 "$(w gzip-rc)" check_eq wget/http-gzip-body "wget-loopback-ok" "$(w gzip-body)" fi # Nothing listening: ECONNREFUSED is a network failure, exit 4. check_eq wget/conn-refused-rc 4 "$(w refused-rc)" has wget/conn-refused-msg "Connection refused" "$(w refused-msg)" # Counted from the server's side, which is the only place the redirect and the # HEAD are visible as separate requests: GET /hello, GET /big, GET /missing, # HEAD /hello, GET /redirect, the GET /hello it led to, and GET /gzip. Seven, # or six when the gzip case above skipped. The refused run never gets here, # which is the point of it. if [ "$(w gzip-rc)" = "skip" ]; then _want_served=6; else _want_served=7; fi check_eq wget/httpd-served "$_want_served" "$(w served)" else bst_skip wget/http-loopback "tclsh not installed; no server on this image to fetch from" fi # --- what this image cannot cover -------------------------------------------- # The handshake itself is unreachable here, and the reason is size, not TLS. There # is no route off lo, so a peer would have to be local -- and the only TLS server # on the image is `openssl s_server`, a 59.5 MiB exec, while wget is now 48.7 MiB. # Two large images cannot be staged at once against the 64 MiB exec reservation, so # whichever starts second dies "Cannot allocate memory". Measured 2026-08-04: the # cert generation leg (openssl req -x509 -newkey rsa:2048) SUCCEEDS -- so RSA keygen # and the entropy path are fine -- and it is only the concurrent server that fails. bst_skip wget/tls-handshake "no TLS peer can be resident beside wget: openssl s_server is a second large exec and gets ENOMEM (linux-in-the-browser#100)" # A hostname (even "localhost", which /etc/hosts would resolve) goes through # gethostbyname to static-glibc NSS, which traps and takes the process with it. bst_skip wget/host-by-name "name resolution traps in static-glibc NSS (BRINTOS-77); numeric hosts only" # ftp:// is compiled in, but nothing on this image serves FTP and there is no # route off lo to reach one. bst_skip wget/ftp "ftp:// is built in but no FTP server is reachable from this machine" # --use-askpass is the one wget path that spawns a helper, via posix_spawnp; # glibc posix_spawn is ENOSYS on this arm (BRINTOS-181). bst_skip wget/use-askpass "--use-askpass needs posix_spawn, ENOSYS on this arm (BRINTOS-181)"