Skip to content

Instantly share code, notes, and snippets.

@mbbx6spp
Created April 13, 2015 22:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save mbbx6spp/0ba0406afe65db556eef to your computer and use it in GitHub Desktop.
Save mbbx6spp/0ba0406afe65db556eef to your computer and use it in GitHub Desktop.
ZOMG a bash powers HTTP web service that runs via the `socat` web app container like so: socat TCP4-LISTEN:8080 EXEC:/path/to/server/script
#!/usr/bin/env bash
# Purpose: Provide HTTP server that displays the current server date to
# validate the artifact structure and play with.
declare -a _http_responses=(
[200]="OK"
[201]="Created"
[202]="Accepted"
[204]="No Content"
[301]="Moved Permanently"
[302]="Found"
[307]="Temporary Redirect"
[400]="Bad Request"
[401]="Unauthorized"
[403]="Forbidden"
[404]="Not Found"
[405]="Method Not Allowed"
[500]="Internal Server Error"
[501]="Not Implemented Error"
[502]="Bad Gateway"
[503]="Temporarily Unavailable"
)
function _recv() {
echo "< $*" >&2
}
function _send() {
printf '%s\r\n' "$*"
}
function _send_headers() {
local -r dt="$(date +"%a, %d %b %Y %H:%M:%S %Z")"
local -r hst="$(hostname -s)"
local -a hdrs=(
"Date: ${dt}"
"Expires: ${dt}"
"Content-Type: text/plain"
"Server: hello-bash@${hst}/0.0.1"
)
for h in "${hdrs[@]}"; do
_send "${h}"
done
}
function _send_body() {
_send "Yo yo yo!"
}
function _send_response() {
_send "${1}"
_send_headers
_send ""
_send_body
}
function _respond_with() {
if [ "$#" -ne 1 ]; then
>&2 "Error: Expected one argument for ${FUNCNAME}, received $#."
>&2 "Usage: ${0} CODE"
return 1
fi
local -r code="${1}"
_send_response "${code} ${_http_responses[${code}]}"
}
function _parse_request() {
if [ "$#" -ne 1 ]; then
>&2 "Error: Expected one argument for ${FUNCNAME}, received $#."
>&2 "Usage: ${0} REQUEST_LINE"
return 1
fi
local -r req="${1%%$'r'}"
read -r req_method req_uri req_http_ver <<<"${req}"
# Validate request (only support GET and / URI so far :)
if [ "${req_method}" = "GET" -a "${req_uri}" = "/" -a -n "${req_http_ver}" ]; then
_respond_with 200
elif [ "${req_uri}" != "/" ]; then
_respond_with 404
elif [ -z "${req_http_ver}" ]; then
_respond_with 400
else
_respond_with 500
fi
}
function _main() {
read -r line || _respond_with 400
_parse_request "${line}"
}
if [ "${BASH_SOURCE[0]}" != "${0}" ]; then
export -f _respond_with
export -f _parse_request
else
set -eu
_main
fi
@polynomial
Copy link

Copy link

ghost commented Apr 15, 2015

You can eliminate 2 forks if you want. Bash has both date and hostname built-in.
Also if you take the care to make dt local, the so should h.

replace:
local -r dt="$(date +"%a, %d %b %Y %H:%M:%S %Z")"
local -r hst="$(hostname -s)"
...
"Server: hello-bash@${hst}/0.0.1"

with:
local h dt
printf -v dt "%(%a, %d %b %Y %H:%M:%S %Z)T" -1
...
"Server: hello-bash@${HOSTNAME}/0.0.1"

Copy link

ghost commented Apr 15, 2015

Erm, second thought, this is not a web service after all.
The output all ends up in the content and the headers are not treated as headers by real http clients.
try:
curl -D apache_headers.txt localhost >apache_content.txt
curl -D bash_headers.txt localhost:8080 >bash_content.txt

Perhaps somehow a newline is getting output before the headers, or perhaps it's something else entirely.

Copy link

ghost commented Apr 15, 2015

It's the missing HTTP/1.0
See the example here:
https://stuff.mit.edu/afs/sipb/machine/penguin-lust/src/socat-1.7.1.2/EXAMPLES

socat -T 1 -d -d tcp-l:10081,reuseaddr,fork,crlf system:"echo -e \"\\\"HTTP/1.0 200 OK\\\nDocumentType: text/html\\\n\\\n<html>date: \$\(date\)<br>server:\$SOCAT_SOCKADDR:\$SOCAT_SOCKPORT<br>client: \$SOCAT_PEERADDR:\$SOCAT_PEERPORT\\\n<pre>\\\"\"; cat; echo -e \"\\\"\\\n</pre></html>\\\"\""

That example is also using socat to convert LF to CRLF, so, if following that example, you wouldn't need _send(), just plain echo everywhere.

We don't need to use the system: option from that example, exec: is fine, since we are using a script in a file, not shell commands directly on the commandline.

Copy link

ghost commented Apr 15, 2015

@bkw777
Copy link

bkw777 commented Jul 5, 2021

Restored my version that went away when that account was deleted (I'm the "ghost" above)
https://gist.github.com/bkw777/e026f514306065e3d4e2c5b85e911838

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment