formpost becomes hpost

This commit is contained in:
cinap_lenrek 2012-10-14 06:28:58 +02:00
parent 45c0c41280
commit 143fcc0a42
3 changed files with 246 additions and 243 deletions

View file

@ -1,191 +0,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
}

207
rc/bin/hpost Executable file
View file

@ -0,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()
}
'

View file

@ -1,6 +1,6 @@
.TH HGET 1 .TH HGET 1
.SH NAME .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 .SH SYNOPSIS
.B hget .B hget
[ [
@ -23,15 +23,12 @@ hget, formpost \- retrieve, post to a web page corresponding to a url
] ]
.I url .I url
.PP .PP
.B formpost .B hpost
[ [
.B -d
] [
.B -M
] [
.B -u .B -u
]
.I url .I url
] [ [
.B -g .B -g
.I action .I action
] [ ] [
@ -43,7 +40,7 @@ hget, formpost \- retrieve, post to a web page corresponding to a url
] [ ] [
.I name:value .I name:value
| |
.I name:@value .I name@file
] ]
.I ... .I ...
.SH DESCRIPTION .SH DESCRIPTION
@ -97,39 +94,33 @@ Option
.B -m .B -m
overrides the HTTP method used for the request. overrides the HTTP method used for the request.
.PP .PP
.I Formpost .I Hpost
retrieves the web page specified by the URL retrieves the web page specified by the URL
.I url, .I url,
parses its HTML for form data, then prints parses its HTML for form data, then prints
.I hget .IR rc (1)
commands to submit forms to the commands to submit the forms with default field
.I url. values.
If the If an
.B -M, -g, -p .I action
URL is provided with the
.B -g, -p
or or
.B -m .B -m
flags are set, the flags, then
.I hget .I hget
commands are assembled without first retrieving and interpreting the is invoked to execute the transaction submitting the form data.
target HTML.
.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 .PP
The The
.B -u .B -u
flag sets the target URL to flag sets the target URL to
.I url. .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 .PP
The The
.B -g .B -g
@ -137,49 +128,50 @@ and
.B -p .B -p
flags set the form method to GET and POST, respectively. The flags set the form method to GET and POST, respectively. The
.B -m .B -m
flag sets the form method to POST and its enctype to multipart/form-data. flag sets the form method to POST and its enctype to
In all cases, the form action is set to .B multipart/form-data.
In all cases, the form action URL is set to
.I action. .I action.
.PP .PP
The remaining arguments of the form The remaining arguments of the form
.B name:value .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 argument of the form
.B name:@value .B name@file
is interpreted as a file upload, with the information following the is interpreted as a file upload, with the information following the
.B @ .B @
symbol treated as the full path to the location of the file. symbol treated as the full path to the location of the file.
.SH EXAMPLES .SH EXAMPLES
Retrieve the Download a file from the web.
.I hget .IP
command needed to submit a form, which may then be .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. edited and sent.
.IP .IP
.EX .EX
% formpost -u http://p.intma.in % hpost http://p.intma.in
hget -p 'text=' http://p.intma.in/paste.cgi /bin/hpost -u http://p.intma.in -p paste.cgi text:
.EE .EE
.PP .PP
Manually specify options to be sent to a given Manually specify fields to be sent to a given
.I url. .I url.
.IP .IP
.EX .EX
% formpost -u http://p.intma.in -p paste.cgi 'text:test post' % hpost -u http://p.intma.in -p paste.cgi text:'test post'
hget -p 'text=test+post' http://p.intma.in/paste.cgi
.EE .EE
.PP .PP
Upload a file. Upload a file.
.IP .IP
.EX .EX
% formpost -M file:@/tmp/screen.png | \\ % hpost http://i.intma.in file@/tmp/screen.png | rc >/dev/null
hget -P \\
-r 'Content-Type: multipart/form-data, boundary=HJBOUNDARY' \\
http://i.intma.in/up.cgi
.EE .EE
.SH SOURCE .SH SOURCE
.B /rc/bin/hget .B /rc/bin/hget
.br .br
.B /rc/bin/formpost .B /rc/bin/hpost
.SH "SEE ALSO" .SH "SEE ALSO"
.IR webfs (4) , .IR webfs (4) ,
.IR ftpfs (4) .IR ftpfs (4)
@ -190,8 +182,3 @@ requires
service mounted on service mounted on
.B /mnt/web .B /mnt/web
to work. to work.
.SH BUGS
.I Formpost
does not attempt to insert default values for
.B <select>
tags.