Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

executable file 275 lines (220 sloc) 6.312 kB
#!/bin/bash
#
# stupid proof of concept bash based AUR agent
#
shopt -s extglob
declare -a respheaders uri_list
declare -i actrpc=0 actpb=0 acttb=0
declare content_encoding=cat # NOOP decompressor
declare -r uastring="bashium 0.2 (bash ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]})"
declare -r hostname='aur.archlinux.org'
declare -r port='80' bufsiz=4096
declare -r fmt_pkgpath='/packages/%s/%s/%s.tar.gz'
declare -r fmt_rpcpath='/rpc.php?type=%s%s'
declare -r fmt_pbpath='/packages/%s/%s/PKGBUILD'
usage() {
cat <<EOF
Usage: ${0##*/} operation target...
Operations:
-d download target(s)
-g display PKGBUILD for target(s)
-i show package info for target(s) <multiinfo>
-I show package info for target(s) <info>
-m search for target(s) by maintainer <msearch>
-s search for target(s) <search>
Options:
-h display this help message and exit
-r raw output
-v show http response headers
EOF
exit 1
} >&2
die() {
error "$@"
exit 1
}
error() {
local mesg=$1; shift
printf "\033[1;31m::\033[0m $mesg\n" "$@"
}
warn() {
local mesg=$1; shift
printf "\033[1;33m::\033[0m $mesg\n" "$@"
}
info() {
local mesg=$1; shift
printf "\033[1;34m::\033[0m \033[1m$mesg\033[0m\n" "$@"
}
urlencode() {
local i= char= url=$*
declare -i len=${#url}
for (( i = 0; i < len; i++ )); do
char=${url:i:1}
case $char in
[a-zA-Z0-9.~_-]) printf "$char" ;;
' ') printf + ;;
*) printf '%%%X' "'$char" ;;
esac
done
}
build_uri_list() {
local target= encoded= qtype=$1; shift
if (( actrpc )); then
if [[ $qtype = multiinfo ]]; then
for arg; do
encoded+="&arg[]=$(urlencode "$arg")"
done
printf "$fmt_rpcpath\n" 'multiinfo' "$encoded"
else
for target; do
printf "$fmt_rpcpath\n" "$qtype" "&arg=$(urlencode "$target")"
done
fi
elif (( actpb )); then
for target; do
printf "$fmt_pbpath\n" "$(urlencode "${target:0:2}")" "$(urlencode "$target")"
done
elif (( acttb )); then
for target; do
encoded=$(urlencode "$target")
printf "$fmt_pkgpath\n" "$(urlencode "${target:0:2}")" "$encoded" "$encoded"
done
fi
}
# content handlers
json() {
type -P json_reformat >/dev/null && json_reformat || cat
}
x_tgz() {
if tar xz; then
info '%s downloaded to %s' "$target" "$PWD"
else
error 'error downloading %s' "$target"
fi
}
plain() {
less
}
# decompress handlers
gzip() {
command gzip -d
}
# connect handler
connect() {
{ exec {sock}<>/dev/tcp/$hostname/$port; } 2>/dev/null ||
die 'error: failed to connect to %s:%s\n' "$hostname" "$port"
}
# request handler
send_http_request() {
local -a headers=(
"GET $1 HTTP/1.1"
"User-Agent: $uastring"
"Host: $hostname"
"Accept-Encoding: gzip"
"Accept: */*"
"Connection: Keep-Alive"
""
)
(( verbose )) && printf '> %s\n' "http://$hostname$1" "${headers[@]}"
printf '%s\r\n' "${headers[@]}" >&$sock
}
# response handlers
read_response_code() {
read -r -u $sock header resp status
(( verbose )) && printf '< %s: %s %s\n' "$header" "$resp" "$status"
if [[ $resp ]]; then
if (( resp == 404 )); then
die "package \`%s' not found" "$target"
elif (( resp >= 300 )); then
die "server responded with HTTP %d" "$resp"
fi
# assume HTTP 200 (eww)
fi
}
read_response_headers() {
local header= value=
# read response until the end of the headers
while IFS=': ' read -r -u $sock header value; do
# end of headers
[[ $header = $'\r' ]] && break
(( verbose )) && printf '< %s: %s\n' "$header" "$value"
header=${header,,}
header=${header//-/_}
read -r -d $'\r' "$header" <<< "$value"
respheaders+=("$header")
done
(( verbose )) && printf '\n'
content_type=${content_type##*/} # trim 'application/'
# sanitize
content_type=${content_type//[.-]/_}
content_encoding=${content_encoding//[.-]/_}
if ! type -p "$content_type" &>/dev/null; then
die 'unknown/unhandled content type: %s\n' "$content_type"
fi
if ! type -p "$content_encoding" &>/dev/null; then
die 'unknown/unhandled encoding type: %s\n' "$content_encoding"
fi
}
read_buffered() {
local readlen= actual= bs= fd=$1 len=$2
while (( len > 0 )); do
(( len > bufsiz )) && readlen=$bufsiz || readlen=$len
actual=$(<&$fd dd bs=1 count=$readlen 2>/dev/null | tee >(wc -c) >&5)
(( len -= actual ))
done 5>&1
}
read_response_body() {
local len=
if (( content_length )); then
read_buffered $sock $content_length | $content_encoding | ${raw:-$content_type}
elif [[ $transfer_encoding = chunked ]]; then
while true; do
read -r -d $'\r\n' -u $sock len # read length, consume \r
read -r -n 1 -u $sock _ # consume \n
len=$(( 0x$len )) # convert hex2dec
if (( len == 0 )); then # exit condition
read -r -n 4 -u $sock _ # consume final \r\n\r\n
break
fi
read_buffered $sock $len # read chunk
read -r -n 2 -u $sock _ # consume \r\n
done | $content_encoding | ${raw:-$content_type}
else
$content_encoding <&$sock | ${raw:-$content_type}
fi
}
# shutdown socket on exit
trap '[[ $sock && -e /dev/fd/$sock ]] && exec {sock}<&-' EXIT
# main()
while getopts ':dghIimrsv' opt; do
case $opt in
d) acttb=1 ;;
g) actpb=1 ;;
h) usage ;;
I) (( ++actrpc )); qtype=info ;;
i) (( ++actrpc )); qtype=multiinfo ;;
m) (( ++actrpc )); qtype=msearch ;;
r) raw=cat ;;
s) (( ++actrpc )); qtype=search ;;
v) verbose=1 ;;
?) die '%s: invalid option -- '\''%s'\' "${0##*/}" "$OPTARG"
exit 1 ;;
esac
done
shift $(( OPTIND - 1 ))
case $(( acttb + actrpc + actpb )) in
0) die 'no operation specified (use -h for help)' ;;
[^1]) die 'cannot specify multiple operations' ;;
esac
(( $# )) || die 'no targets specified (use -h for help)'
IFS=$'\n' read -r -d '' -a uri_list < <(build_uri_list "$qtype" "$@")
connect
for uri in "${uri_list[@]}"; do
target=$1; shift
[[ $connection = close ]] && connect; # keep-alive expired
unset "${respheaders[@]}"
send_http_request "$uri"
read_response_code
read_response_headers
read_response_body
done
Jump to Line
Something went wrong with that request. Please try again.