Parckwart’s Computer Stuff

⟵ Home page

Published: June 16, 2016
Last updated: August 8, 2016

Bash and CGI: Parsing GET and POST Requests

Here’s a handy piece of code for all of the crazy ones out there who actually think about using Bash as their website’s CGI script language. I haven’t found a convenient way anywhere on the Internet to turn GET and POST requests into variables in Bash.

The closest thing I found was Philippe Kehl’s bash.cgi. However, his script has some major security flaws. A visitor of the website can just send the key of a variable as a request and the script will turn the value of the newly created variable into the value of the variable, which’s key was sent. So for example:

After telling him about this problem, I sent Philippe a suggestion on how to fix that issue but I haven’t heard back from him since.

Later I stumbled upon this very nice way by Dennis Williamson to parse the query string to handle GET requests. Based upon this parsing code and one line I copied from bash.cgi, I came up with the following way to automatically asign all GET and POST requests a bash variable:

function urldecode {
	local url_encoded="${1//+/ }"
	printf '%b' "${url_encoded//%/\\x}"
}

[ -z "$POST_STRING" -a "$REQUEST_METHOD" = "POST" -a ! -z "$CONTENT_LENGTH" ] && read -n $CONTENT_LENGTH POST_STRING

OIFS=$IFS
IFS='=&'
parm_get=($QUERY_STRING)
parm_post=($POST_STRING)
IFS=$OIFS

declare -A get
declare -A post

for ((i=0; i<${#parm_get[@]}; i+=2)); do
	get[${parm_get[i]}]=$(urldecode ${parm_get[i+1]})
done

for ((i=0; i<${#parm_post[@]}; i+=2)); do
	post[${parm_post[i]}]=$(urldecode ${parm_post[i+1]})
done

You can just copy this code into your CGI script or put it into a serate file to source and it will do all the necessary work. The variables are stored either in the associative array "get" or "post". So, for example ${get[article]} or ${post[password]}.

Update (August 8, 2016): After a few more weeks Philippe Kehl did reply to my email and updated bash.cgi, following my suggestion. The security hole should be fixed now.