#!/usr/bin/env bash # compat: +ash +bash +dash -hush +ksh +mksh +oksh +osh +posh +yash +zsh burl() ( ### @- ### turn bash into a makeshift HTTP client. ### inspired by [hackshell.sh.](https://thc.org/hs) ### also works in most other shells thanks to netcat. ### ### minimal/minified version: https://eaguru.guru/t/burl.sh (469 bytes) ### ### ``` ### $ burl httpbin.org/get ### ### HTTP/1.1 200 OK ### Date: Tue, 01 Jul 2024 00:00:00 GMT ### Content-Type: application/json ### Content-Length: 192 ### Connection: close ### Server: gunicorn/19.9.0 ### Access-Control-Allow-Origin: * ### Access-Control-Allow-Credentials: true ### ### { ### "args": {}, ### "headers": { ### "Host": "httpbin.org", ### "X-Amzn-Trace-Id": "Root=1-12345678-deadfadefeedfacebeefcafe" ### }, ### "origin": "0.0.0.0", ### "url": "http://httpbin.org/get" ### } ### ``` # shells with /dev/tcp and /dev/udp support: bash, ksh, yash. ! (set -o pipefail) 2>&- || set -o pipefail (: &- && net=y || net= [ $'' ] && r=$(printf \\r) || r=$'\r' # nc.traditional needs the -- or else it waits for input. if /usr/bin/env nc --; [ $? = 1 ] # needs absolute path to env thanks to busybox then wrapped() { process /usr/bin/env nc -- "$@" ;} elif netcat; [ $? = 1 ] then wrapped() { process netcat -- "$@" ;} elif ncat; [ $? = 1 ] then wrapped() { process ncat -- "$@" ;} elif busybox nc; [ $? = 1 ] then wrapped() { process busybox nc -- "$@" ;} elif socat /dev/null /dev/null then wrapped() { process socat - "TCP:$1:$2" ;} elif websocat; [ $? = 1 ] then wrapped() { websocat --binary - "tcp:$1:$2" ;} elif curl; [ $? = 2 ] then wrapped() { process curl "telnet://$1:$2" ;} else return 127 fi 2>&- request() { printf 'GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' "${query#/}" "$dom" ;} receive() { while IFS=$r read -r l _; [ "$l" ]; do printf %s\\n "$l"; done; echo ;} >&2 process() { request | "$@" | { receive && cat ;} ;} for url; do proto="${url%%:*}" proto="${proto##*[!a-z0-9-]*}" [ "$proto" ] && url="${url#$proto://}" || url="${url#//}" host="${url%%/*}" query="${url#"$host"}" dom="${host%:*}" [ "$host" = "${dom:?}" ] && PORT="${PORT:-80}" || PORT="${host##*:}" if [ "$net" ]; then exec 3<>"/dev/tcp/$dom/$PORT" && request >&3 && receive <&3 && cat <&3 || continue exec 3>&- else wrapped "$dom" "$PORT" || return fi done ) [ -n "${preload+-}" ] || burl "$@"