]> git.lizzy.rs Git - plan9front.git/blob - rc/bin/hpost
hpost: fix field content mangling when newlines are present
[plan9front.git] / rc / bin / hpost
1 #!/bin/rc
2 rfork e
3 url=()
4 at=()   # text fields
5 af=()   # file fields
6 l=()
7
8 fn usage {
9         echo 'usage: hpost [ -l ] [ -[gpm] action ] [ -u ] url [ field:value | field@file ... ]' >[1=2]
10         exit usage
11 }
12
13 while(~ $1 -*){
14         switch($1){
15         case -l;        l=($l $1)
16         case -u;        shift; url=$1
17         case -g;        shift; action=$1; method=mget
18         case -p;        shift; action=$1; method=mpost
19         case -m;        shift; action=$1; method=multi
20         case *;         usage
21         }
22         shift
23 }
24
25 if(~ $#url 0){
26         url=$1
27         shift
28 }
29
30 if(~ $url '')
31         usage
32
33 while(! ~ $#* 0){
34         switch($1){
35         case *:*@*;     at=($1 $at)
36         case *@*;       af=($1 $af)
37         case *:*;       at=($1 $at)
38         case *;         usage
39         }
40         shift
41 }
42
43 hpost=(hpost $l)
44
45 fn uenc {
46         f=$1
47         for(i in $at){
48                 echo -n $"f`{urlencode /env/i | sed 's!%3A!=!; s!%00$!!'}
49                 f='&'
50         }
51         for(i in $af){
52                 echo -n $"f`{urlencode /env/i | sed 's!@.*$!=!'}
53                 urlencode `{sed 's!^[^@]+@!!' /env/i}
54                 f='&'
55         }
56 }
57 fn menc {
58         f=$1
59         cr=`{echo x | tr x \015}
60         for(i in $at){
61                 k=`{sed 's!:.*$!!; q' /env/i}
62                 echo '--'$"f$"cr
63                 echo 'Content-Disposition: form-data; name="'$"k'"'$"cr
64                 echo $"cr
65                 i=$"i$"cr
66                 sed '1s!^[^:]+:!!' /env/i
67         }
68         for(i in $af){
69                 k=`{sed 's!@.*$!!; q' /env/i}
70                 v=`{sed 's!^[^@]+@!!' /env/i}
71                 t=`{file -m $v}
72                 n=`{basename $v}
73                 echo '--'$"f$"cr
74                 echo 'Content-Disposition: form-data; name="'$"k'"; filename="'$"n'"'$"cr
75                 echo 'Content-Type: '$"t$"cr
76                 echo $"cr
77                 cat $v
78                 echo $"cr
79         }
80         echo '--'$"f'--'$"cr
81 }
82
83 fn mget {
84         a=`{uenc '?'}
85         action=$"action$"a
86         $hget -b $url $action
87 }
88 fn mpost {
89         uenc | $hget -b $url -P $action
90 }
91 fn multi {
92         f='HJBOUNDARY'
93         menc $"f | $hget -r 'Content-Type: multipart/form-data; boundary='$"f -b $url -P $action
94 }
95
96 if(! ~ $action ''){
97         hget=(hget $l)
98         $method
99         exit
100 }
101
102 # serialize $at and $af into a0=... a1=... for awk
103 # to preserve newlines and other special characters
104 n=()
105 for(i in $at $af){
106         a$#n=$i
107         n=(1 $n)
108 }
109 a$#n=''
110 hget $url | uhtml | tr '>' '
111 ' | sed '
112 s!^(TAG|ATT)! \1!g;             # escape our inline signaling
113 s!<[    ]*!\nTAG !g;            # find starttags, mark with TAG name ...
114 s!>[^>"'']*$!!g;                # remove garbage after the tag
115 # find attributes, mark with ATT name value
116 s!([a-zA-Z][a-zA-Z0-9:_]*)=("[^"]*"?|''[^'']*''?|[      ]*[^>   ]+)!\nATT \1 \2!g;
117 ' | awk -v 'hpost='$"hpost -v 'url='$"url '
118 BEGIN{
119         for(i=0; ENVIRON["a"i]!=""; i++){
120                 s=ENVIRON["a"i]
121                 x=index(s, ":"); y=index(s, "@")
122                 if(y > 1 && (x < 1 || x > y))
123                         x = y
124                 n=substr(s, 1, x-1)
125                 ainput[n]=substr(s, x+1, length(s))
126                 atypes[n]=substr(s, x, 1);
127         }
128 }
129 function qw(s){
130         if(s !~ /[\n\\#;\|\^$=`''{}\(\)<>       ]/)
131                 return s
132         gsub(/''/, "''''", s)
133         return "''"s"''"
134 }
135 function uq(s){
136         q=substr(s, 1, 1)
137         if(q=="\"" || q=="''"){
138                 s=substr(s, 2, length(s))
139                 x=index(s, q)
140                 if(x > 0) s=substr(s,1,x-1)
141         }
142         return s
143 }
144 function emitform(){
145         if(action!=""){
146                 printf hpost
147                 if(url!="") printf " -u %s", qw(url)
148                 if(method=="post"){
149                         if(enctype=="multipart/form-data")
150                                 printf " -m %s", qw(action)
151                         else
152                                 printf " -p %s", qw(action)
153                 } else
154                                 printf " -g %s", qw(action)
155                 for(n in ainput)
156                         printf " %s%s%s", n, atypes[n], qw(ainput[n])
157                 for(n in input)
158                         if(!(n in ainput))
159                                 printf " %s%s%s", n, types[n], qw(input[n])
160                 printf "\n"
161         }
162         delete input
163         delete types
164         action=""
165         method=""
166         enctype=""
167 }
168 function endtag(){
169         if(tag=="form"){
170                 action=attr["action"]
171                 method=tolower(attr["method"])
172                 enctype=tolower(attr["enctype"])
173         }
174         if(tag=="select")
175                 selectname=attr["name"]
176         if(tag=="option" && selectname!=""){
177                 if(attr["selected"]!=""){
178                         input[selectname]=attr["value"]
179                         selectname=""
180                 }
181         }
182         if(tag=="input" || tag=="textarea" || tag=="submit"){
183                 n=attr["name"]
184                 if(n!=""){
185                         if(tolower(attr["type"])=="file"){
186                                 input[n]="/dev/null"
187                                 types[n]="@"
188                         } else {
189                                 input[n]=attr["value"]
190                                 types[n]=":"
191                         }
192                 }
193         }
194         delete attr
195         tag=""
196 }
197 /^TAG \//{
198         etag=tolower(substr($2, 2, length(etag)-1))
199         endtag()
200         if(etag=="form")
201                 emitform()
202 }
203 /^TAG [^\/]/{
204         endtag()
205         tag=tolower($2)
206         if(tag=="form")
207                 emitform()
208 }
209 /^ATT/{
210         for(i=4; i<=NF; i++) $3=$3" "$i
211         attr[tolower(uq($2))]=uq($3)
212 }
213 END{
214         endtag()
215         emitform()
216 }
217 '