I have found following working example of CGI with bash. If I change first two lines to
#!/bin/sh
echo "Content-type: text/html\n\n"
following the script stops working and when I browse the script in a browser the ‘foo’, ‘bar’ and ‘foobar’ declared at the bottom of the script disappears.
Any idea how can I make the same example work with sh. Actually I need to run such an example over an embedded device where I don’t have bash but sh.
#!/bin/bash
echo -e "Content-type: text/html\n\n"
echo "
<html>
<body>
<form action="http://${HTTP_HOST}:${SERVER_PORT}${SCRIPT_NAME}?foo=1234" method="POST">
<input type="text" name="bar">
<textarea name="foobar"></textarea>
<input type="submit">
</form>"
# (internal) routine to store POST data
cgi_get_POST_vars()
{
# check content type
# FIXME: not sure if we could handle uploads with this..
[ "${CONTENT_TYPE}" != "application/x-www-form-urlencoded" ] && \
echo "Warning: you should probably use MIME type "\
"application/x-www-form-urlencoded!" 1>&2
# save POST variables (only first time this is called)
[ -z "$QUERY_STRING_POST" \
-a "$REQUEST_METHOD" = "POST" -a ! -z "$CONTENT_LENGTH" ] && \
read -n $CONTENT_LENGTH QUERY_STRING_POST
return
}
# (internal) routine to decode urlencoded strings
cgi_decodevar()
{
[ $# -ne 1 ] && return
local v t h
# replace all + with whitespace and append %%
t="${1//+/ }%%"
while [ ${#t} -gt 0 -a "${t}" != "%" ]; do
v="${v}${t%%\%*}" # digest up to the first %
t="${t#*%}" # remove digested part
# decode if there is anything to decode and if not at end of string
if [ ${#t} -gt 0 -a "${t}" != "%" ]; then
h=${t:0:2} # save first two chars
t="${t:2}" # remove these
v="${v}"`echo -e \\\\x${h}` # convert hex to special char
fi
done
# return decoded string
echo "${v}"
return
}
# routine to get variables from http requests
# usage: cgi_getvars method varname1 [.. varnameN]
# method is either GET or POST or BOTH
# the magic varible name ALL gets everything
cgi_getvars()
{
[ $# -lt 2 ] && return
local q p k v s
# get query
case $1 in
GET)
[ ! -z "${QUERY_STRING}" ] && q="${QUERY_STRING}&"
;;
POST)
cgi_get_POST_vars
[ ! -z "${QUERY_STRING_POST}" ] && q="${QUERY_STRING_POST}&"
;;
BOTH)
[ ! -z "${QUERY_STRING}" ] && q="${QUERY_STRING}&"
cgi_get_POST_vars
[ ! -z "${QUERY_STRING_POST}" ] && q="${q}${QUERY_STRING_POST}&"
;;
esac
shift
s=" $* "
# parse the query data
while [ ! -z "$q" ]; do
p="${q%%&*}" # get first part of query string
k="${p%%=*}" # get the key (variable name) from it
v="${p#*=}" # get the value from it
q="${q#$p&*}" # strip first part from query string
# decode and evaluate var if requested
[ "$1" = "ALL" -o "${s/ $k /}" != "$s" ] && \
eval "$k=\"`cgi_decodevar \"$v\"`\""
done
return
}
# register all GET and POST variables
cgi_getvars BOTH ALL
echo "<pre>foo=$foo</pre>"
echo "<pre>bar=$bar</pre>"
echo "<pre>foobar=$foobar</pre>"
echo "</body>
</html>"
Update 1:
sh -x script returned following:
+ echo Content-type: text/html\n\n
Content-type: text/html
+ echo
<html>
<body>
<form action=http://:?foo=1234 method=POST>
<input type=text name=bar>
<textarea name=foobar></textarea>
<input type=submit>
</form>
<html>
<body>
<form action=http://:?foo=1234 method=POST>
<input type=text name=bar>
<textarea name=foobar></textarea>
<input type=submit>
</form>
+ cgi_getvars BOTH ALL
+ [ 2 -lt 2 ]
+ local q p k v s
+ [ ! -z ]
+ cgi_get_POST_vars
+ [ != application/x-www-form-urlencoded ]
+ echo Warning: you should probably use MIME type application/x-www-form-urlencoded!
Warning: you should probably use MIME type application/x-www-form-urlencoded!
+ [ -z -a = POST -a ! -z ]
+ return
+ [ ! -z ]
+ shift
+ s= ALL
+ [ ! -z ]
+ return
+ echo <pre>foo=</pre>
<pre>foo=</pre>
+ echo <pre>bar=</pre>
<pre>bar=</pre>
+ echo <pre>foobar=</pre>
<pre>foobar=</pre>
+ echo </body>
</html>
</body>
</html>
Bash has lots of extensions compared to POSIX specification and your script is using some of them. Your
/bin/shapparently isn’t bash (might be ash, dash, mksh or something) and does not have those extensions. You’ll have to go through the script and check each construct against documentation of your sh or the POSIX specification.Quckly looking:
function cgi_get_POST_vars(): The function keyword shouldn’t be there and the opening brace should go on the same line.read -n $CONTENT_LENGTH QUERY_STRING_POST: read (shell builtin) does not have -n option in POSIX.t="${1//+/ }%%",h=${t:0:2}: Bourne does not support either of these modifiers.but there may be some more.
Edit:
echois the most incompatible command between shells. The standard just says behaviour with\is implementation-defined. You have to useprintfinstead.