git: 9front

Download patch

ref: f13524ba3fc523030921a7b4539a937f430aae2a
parent: 5bdf27884fe8b69125fb1a0f512e29327792a334
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Sun Oct 14 02:28:58 EDT 2012

formpost becomes hpost

--- a/rc/bin/formpost
+++ /dev/null
@@ -1,191 +1,0 @@
-#!/bin/rc
-rfork e
-argv0=$0
-fn usage {
-	echo usage: $argv0 '[-d] [-M] [ -u url ] [ -g action | -p action | -m action ] [ name:value | name:@value ]' ... >[1=2]
-	exit usage
-}
-d=()
-g=()
-M=()
-m=()
-p=()
-u=()
-while(~ $1 -*){
-	switch($1){
-	case -d
-		d=1
-	case -g
-		g=1
-		a=$2
-		shift
-	case -M
-		M=1
-	case -m
-		m=1
-		a=$2
-		shift
-	case -p
-		p=1
-		a=$2
-		shift
-	case -u
-		u=$2
-		shift
-	case *
-		usage
-	}
-	shift
-}
-if(~ $#M 0 && ~ $#u 0)
-	usage
-fn geth{
-	hget $u |
-	sed 's/ACTION\=/action\=/g;
-		s/ENCTYPE\=/enctype\=/g;
-		s/FORM/form/g;
-		s/INPUT/input/g;
-		s/METHOD\=/method\=/g;
-		s/NAME\=/name\=/g;
-		s/OPTION/option/g;
-		s/SELECT/select/g;
-		s/TEXTAREA/textarea/g;
-		s/TYPE\=/type\=/g' |
-	awk '/<([ ]|[	])*form/,/<\/form>/ {print}' |
-	sed 's/<\/form>/&\nHJFORMEND\n/g;
-		s/<([ ]|[	])*/HJBOUNDARY/g;
-		s/>(\n)*([ ]|[	])*HJBOUNDARY/\n/g;
-		s/([ ]|[	])*HJBOUNDARY//g;
-		s/^form/HJFORMSTART\n&/g' |
-	grep -e '(^HJFORM|^form|^input|^option|^select|^textarea)' >$1
-}
-fn getf{
-	a=`{grep -e '^form' $1 | sed 's/^.*action\=//g; s/^(\''|\"|[ ]*)//g; s/(\''|\"|[ ]|>).*$//g'}
-	e=`{grep -e '^form' $1 | sed 's/^.*enctype\=//g; s/^(\''|\"|[ ]*)//g; s/(\''|\"|[ ]|>).*$//g'}
-	m=`{grep -e '^form' $1 | sed 's/^.*method\=//g; s/^(\''|\"|[ ]*)//g; s/(\''|\"|[ ]|>).*$//g'}
-	f=$a
-	if(~ $#f 0)
-		f=/
-	if(~ $e multipart/form-data)
-		f=($f m)
-	if not if(~ $m post)
-		f=($f p)
-	if not
-		f=($f g)
-	ifs='
-' {
-	for(j in `{grep -e '(^input|^select|^textarea)' $1}){
-		if(~ $d 1)
-			echo $"j >>formpost.log #debug
-		if(~ $j *name'='*)
-			jname=`{echo $"j |
-				sed 's/^.*name\=//g;
-					s/^(\''|\"|[ ]*)//g;
-					s/(\''|\"|[ ]|>).*$//g;
-					s/^.*\=.*$//g'}
-		if(~ $j *value'='*)
-			jvalue=`{echo $"j |
-				sed 's/^.*value\=//g;
-					s/^(\''|\"|[ ]*)//g;
-					s/(\''|\"|[ ]|>).*$//g;
-					s/^.*\=.*$//g;
-					s/[ ]/HJSPACE/g'}
-		ff=`{echo $"jname':'$"jvalue |
-			sed 's/^.*\=.*:/:/g;
-				s/:.*\=.*$/:/g'}
-		if(! ~ $ff :*)
-			f=($"f $"ff)
-		jname=()
-		jvalue=()
-	}
-}
-	echo $"f
-}
-fn mencode{
-	f=()
-	cr=`{echo x | tr x \015}
-	while(! ~ $#1 0){
-		switch($1){
-		case *:*
-			f=($f $1)
-		case *
-			usage
-		}
-		shift
-	}
-	for(i in $f){
-		echo '--HJBOUNDARY'^$"cr
-		fname=`{echo $"i | awk -F ':' '{print $1}'}
-		fvalue=`{echo $"i | awk -F ':' '{print $2}'}
-		if(~ $fvalue @*){
-			fvalue=`{echo $"fvalue | sed 's/@//g'}
-			echo 'Content-Disposition: form-data; name="'$"fname'"; filename="'^`{basename $fvalue}^'"'$"cr
-			echo Content-Type: `{file -m $fvalue}^$"cr
-			echo $cr
-			cat $fvalue
-			echo $cr
-		}
-		if not{
-			echo 'Content-Disposition: form-data; name="'$"fname'"'$"cr
-			echo $"cr
-			echo $"fvalue^$"cr
-		}
-	}
-	echo '--HJBOUNDARY--'$"cr
-}
-fn uencode{
-	f=()
-	for(i){
-		fname=`{echo $"i | awk -F ':' '{print $1}'}
-		fvalue=`{echo $"i | awk -F ':' '{$1=""; print substr($0, 2)}' |
-			sed 's/HJSPACE/ /g' |
-			urlencode |
-			sed 's/%0A$//g'}
-		f=$"f^$"fname'='$"fvalue
-		if(! ~ $"i $*($#*))
-			f=$"f^'&'
-	}
-	echo $"f
-}
-fn print{
-	if(~ $d 1)
-		echo $"f >>formpost.log #debug
-	a=`{echo $"a | sed 's/^\///g'}
-	if(~ $a http*)
-		u=$a
-	if not
-		u=$"u/$"a
-	if(~ $M 1)
-		mencode `{for(i in $f){echo $"i}}
-	if not if(~ $m 1)
-		echo formpost -M `{for(i in $f){echo ''''$"i''''}} '| hget -P -r ''Content-Type: multipart/form-data, boundary=HJBOUNDARY''' $"u
-	if not if(~ $p 1)
-		echo 'hget -p '''^`{uencode $f}^''' '^$"u
-	if not
-		echo hget ''''$"u^'?'^`{uencode $f}^''''
-}
-if(~ $#M 0 && ~ $#g 0 && ~ $#m 0 && ~ $#p 0){
-	file=/tmp/formpost.$pid
-	geth $file
-	while(grep -s -e '^HJFORMSTART$' $file){
-		f=`{getf $file}
-		a=$f(1)
-		if(~ $f(2) g)
-			g=1
-		if not if(~ $f(2) m)
-			m=1
-		if not if(~ $f(2) p)
-			p=1
-		f=$f(3-)
-		print
-		{ echo /HJFORMSTART/,/HJFORMEND/d
-			echo w
-			echo q
-		} | sam -d $file >[2]/dev/null
-	}
-	rm -f $file
-}
-if not{
-	f=$*
-	print
-}
--- /dev/null
+++ b/rc/bin/hpost
@@ -1,0 +1,207 @@
+#!/bin/rc
+rfork e
+argv0=$0
+url=()
+at=()	# text fields
+af=()	# file fields
+
+fn usage {
+	echo $argv0 '[ -u ] url [ -[gpm] action ] [ field:value | field@file ... ]' >[1=2]
+	exit usage
+}
+
+# tired of typing -u
+if(~ $1 http://* https://*){
+	url=$1
+	shift
+}
+
+while(! ~ $#* 0){
+	switch($1){
+	case -u;	shift; url=$1
+	case -g;	shift; action=$1; method=mget
+	case -p;	shift; action=$1; method=mpost
+	case -m;	shift; action=$1; method=multi
+	case *:*@*;	at=($1 $at)
+	case *@*;	af=($1 $af)
+	case *:*;	at=($1 $at)
+	case *;		usage
+	}
+	shift
+}
+
+if(~ $#url 0)
+	usage
+
+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!:.*$!!' /env/i}
+		echo '--'$"f$"cr
+		echo 'Content-Disposition: form-data; name="'$"k'"'$"cr
+		echo $"cr
+		i=$"i$"cr
+		sed 's!^[^:]+:!!' /env/i
+	}
+	for(i in $af){
+		k=`{sed 's!@.*$!!' /env/i}
+		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 ''){
+	$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 | 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 'argv0='$"argv0 -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 argv0
+		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()
+}
+'
--- a/sys/man/1/hget
+++ b/sys/man/1/hget
@@ -1,6 +1,6 @@
 .TH HGET 1
 .SH NAME
-hget, formpost \- retrieve, post to a web page corresponding to a url
+hget, hpost \- retrieve, post to a web page corresponding to a url
 .SH SYNOPSIS
 .B hget
 [
@@ -23,15 +23,12 @@
 ]
 .I url
 .PP
-.B formpost
+.B hpost
 [
-.B -d
-] [
-.B -M
-] [
 .B -u
+]
 .I url
-] [
+[
 .B -g
 .I action
 ] [
@@ -43,7 +40,7 @@
 ] [
 .I name:value
 |
-.I name:@value
+.I name@file
 ]
 .I ...
 .SH DESCRIPTION
@@ -97,39 +94,33 @@
 .B -m
 overrides the HTTP method used for the request.
 .PP
-.I Formpost
+.I Hpost
 retrieves the web page specified by the URL
 .I url,
 parses its HTML for form data, then prints
-.I hget
-commands to submit forms to the
-.I url.
-If the
-.B -M, -g, -p
+.IR rc (1)
+commands to submit the forms with default field
+values.
+If an
+.I action
+URL is provided with the
+.B -g, -p
 or
 .B -m
-flags are set, the
+flags, then
 .I hget
-commands are assembled without first retrieving and interpreting the
-target HTML.
+is invoked to execute the transaction submitting the form data.
 .PP
-If the
-.B -d
-flag is specified, debugging information is written
-to the file
-.B formpost.log
-in the current directory.
-.PP
 The
-.B -M
-flag applies multipart/form-data encoding to the
-remaining arguments and prints the result on
-the standard output.
-.PP
-The
 .B -u
 flag sets the target URL to
 .I url.
+As the
+.I url
+parameter is always required, it can be optionally specified
+in the first argument without the
+.B -u
+flag.
 .PP
 The
 .B -g
@@ -137,49 +128,50 @@
 .B -p
 flags set the form method to GET and POST, respectively. The
 .B -m
-flag sets the form method to POST and its enctype to multipart/form-data.
-In all cases, the form action is set to
+flag sets the form method to POST and its enctype to
+.B multipart/form-data.
+In all cases, the form action URL is set to
 .I action.
 .PP
 The remaining arguments of the form
 .B name:value
-are interpreted as form field names and values to be submitted. An
+are interpreted as text form field names and values to be submitted. An
 argument of the form
-.B name:@value
+.B name@file
 is interpreted as a file upload, with the information following the
 .B @
 symbol treated as the full path to the location of the file.
 .SH EXAMPLES
-Retrieve the
-.I hget
-command needed to submit a form, which may then be
+Download a file from the web.
+.IP
+.EX
+% hget http://9front.org/img/nix-on.jpg >/tmp/nix-on.jpg
+.EE
+.PP
+Retrieve the commands needed to submit a form, which may then be
 edited and sent.
 .IP
 .EX
-% formpost -u http://p.intma.in
-hget -p 'text=' http://p.intma.in/paste.cgi
+% hpost http://p.intma.in
+/bin/hpost -u http://p.intma.in -p paste.cgi text:
 .EE
 .PP
-Manually specify options to be sent to a given
+Manually specify fields to be sent to a given
 .I url.
 .IP
 .EX
-% formpost -u http://p.intma.in -p paste.cgi 'text:test post'
-hget -p 'text=test+post' http://p.intma.in/paste.cgi
+% hpost -u http://p.intma.in -p paste.cgi text:'test post'
 .EE
 .PP
 Upload a file.
 .IP
 .EX
-% formpost -M file:@/tmp/screen.png | \\
-hget -P \\
--r 'Content-Type: multipart/form-data, boundary=HJBOUNDARY' \\
-http://i.intma.in/up.cgi
+% hpost http://i.intma.in file@/tmp/screen.png | rc >/dev/null
 .EE
 .SH SOURCE
 .B /rc/bin/hget
 .br
-.B /rc/bin/formpost
+.B /rc/bin/hpost
 .SH "SEE ALSO"
 .IR webfs (4) ,
 .IR ftpfs (4)
@@ -190,8 +182,3 @@
 service mounted on
 .B /mnt/web
 to work.
-.SH BUGS
-.I Formpost
-does not attempt to insert default values for
-.B <select>
-tags.
--