plan9fox/rc/bin/hpost
2020-12-22 00:16:26 +10:30

223 lines
4 KiB
Bash
Executable file

#!/bin/rc
rfork e
url=()
headers=()
action=()
method=()
at=() # text fields
af=() # file fields
l=()
fn usage {
echo 'usage: hpost [ -l ] [ -[gpm] action ] [ -r header ] [ -u ] url [ field:value | field@file ... ]' >[1=2]
exit usage
}
while(~ $1 -*){
switch($1){
case -l; l=($l $1)
case -u; shift; url=$1
case -r; shift; headers=($headers -r $1)
case -g; shift; action=$1; method=mget
case -p; shift; action=$1; method=mpost
case -m; shift; action=$1; method=multi
case *; usage
}
shift
}
if(~ $#url 0){
url=$1
shift
}
if(~ $url '')
usage
while(! ~ $#* 0){
switch($1){
case *:*@*; at=($1 $at)
case *@*; af=($1 $af)
case *:*; at=($1 $at)
case *; usage
}
shift
}
hpost=(hpost $l)
fn uenc {
f=$1
for(i in $at){
echo -n $"f`{urlencode /env/i | sed 's!%3A!=!; s!%00$!!'}
f='&'
}
for(i in $af){
echo -n $"f`{urlencode /env/i | sed 's!@.*$!=!'}
urlencode `{sed 's!^[^@]+@!!' /env/i}
f='&'
}
}
fn menc {
f=$1
cr=`{echo x | tr x \015}
for(i in $at){
k=`{sed 's!:.*$!!; q' /env/i}
echo '--'$"f$"cr
echo 'Content-Disposition: form-data; name="'$"k'"'$"cr
echo $"cr
i=$"i$"cr
sed '1s!^[^:]+:!!' /env/i
}
for(i in $af){
k=`{sed 's!@.*$!!; q' /env/i}
ifs='
' v=`{sed 's!^[^@]+@!!' /env/i}
t=`{file -m $v}
n=`{basename $v}
echo '--'$"f$"cr
echo 'Content-Disposition: form-data; name="'$"k'"; filename="'$"n'"'$"cr
echo 'Content-Type: '$"t$"cr
echo $"cr
cat $v
echo $"cr
}
echo '--'$"f'--'$"cr
}
fn mget {
a=`{uenc '?'}
action=$"action$"a
$hget -b $url $action
}
fn mpost {
uenc | $hget -b $url -P $action
}
fn multi {
f='HJBOUNDARY'
menc $"f | $hget -r 'Content-Type: multipart/form-data; boundary='$"f -b $url -P $action
}
if(! ~ $action ''){
hget=(hget $headers $l)
$method
exit
}
# serialize $at and $af into a0=... a1=... for awk
# to preserve newlines and other special characters
n=()
for(i in $at $af){
a$#n=$i
n=(1 $n)
}
a$#n=''
hget $url | uhtml | tr '>' '
' | sed '
s!^(TAG|ATT)! \1!g; # escape our inline signaling
s!<[ ]*!\nTAG !g; # find starttags, mark with TAG name ...
s!>[^>"'']*$!!g; # remove garbage after the tag
# find attributes, mark with ATT name value
s!([a-zA-Z][a-zA-Z0-9:_]*)=("[^"]*"?|''[^'']*''?|[ ]*[^> ]+)!\nATT \1 \2!g;
' | awk -v 'hpost='$"hpost -v 'url='$"url '
BEGIN{
for(i=0; ENVIRON["a"i]!=""; i++){
s=ENVIRON["a"i]
x=index(s, ":"); y=index(s, "@")
if(y > 1 && (x < 1 || x > y))
x = y
n=substr(s, 1, x-1)
ainput[n]=substr(s, x+1, length(s))
atypes[n]=substr(s, x, 1);
}
}
function qw(s){
if(s !~ /[\n\\#;\|\^$=`''{}\(\)<> ]/)
return s
gsub(/''/, "''''", s)
return "''"s"''"
}
function uq(s){
q=substr(s, 1, 1)
if(q=="\"" || q=="''"){
s=substr(s, 2, length(s))
x=index(s, q)
if(x > 0) s=substr(s,1,x-1)
}
return s
}
function emitform(){
if(action!=""){
printf hpost
if(url!="") printf " -u %s", qw(url)
if(method=="post"){
if(enctype=="multipart/form-data")
printf " -m %s", qw(action)
else
printf " -p %s", qw(action)
} else
printf " -g %s", qw(action)
for(n in ainput)
printf " %s%s%s", n, atypes[n], qw(ainput[n])
for(n in input)
if(!(n in ainput))
printf " %s%s%s", n, types[n], qw(input[n])
printf "\n"
}
delete input
delete types
action=""
method=""
enctype=""
}
function endtag(){
if(tag=="form"){
action=attr["action"]
method=tolower(attr["method"])
enctype=tolower(attr["enctype"])
}
if(tag=="select")
selectname=attr["name"]
if(tag=="option" && selectname!=""){
if(attr["selected"]!=""){
input[selectname]=attr["value"]
selectname=""
}
}
if(tag=="input" || tag=="textarea" || tag=="submit"){
n=attr["name"]
if(n!=""){
if(tolower(attr["type"])=="file"){
input[n]="/dev/null"
types[n]="@"
} else {
input[n]=attr["value"]
types[n]=":"
}
}
}
delete attr
tag=""
}
/^TAG \//{
etag=tolower(substr($2, 2, length(etag)-1))
endtag()
if(etag=="form")
emitform()
}
/^TAG [^\/]/{
endtag()
tag=tolower($2)
if(tag=="form")
emitform()
}
/^ATT/{
for(i=4; i<=NF; i++) $3=$3" "$i
attr[tolower(uq($2))]=uq($3)
}
END{
endtag()
emitform()
}
'