code: plan9front

ref: 2eadf1fa1703e5da4a98ba9c1a2bdc23bd140d8c
dir: /rc/bin/hpost/

View raw version
#!/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()
}
'