diff --git a/404.html b/404.html
new file mode 100644
index 0000000..6c51e5b
--- /dev/null
+++ b/404.html
@@ -0,0 +1,10 @@
+
+
+
+ Not found
+
+
+ Not found
+ The resource [path] was not found on server [host].
+
+
diff --git a/home/hello-world.sh b/home/hello-world.sh
new file mode 100755
index 0000000..181e45a
--- /dev/null
+++ b/home/hello-world.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+statusContainer=$1
+eval "declare -A settings="${2#*=}
+eval "declare -A headers="${3#*=}
+
+echo 200 > $statusContainer
+
+cat <
+
+
+ Hello World
+
+
+ Hello World
+
+
+
+EOF
diff --git a/home/info.sh b/home/info.sh
new file mode 100755
index 0000000..5172c9f
--- /dev/null
+++ b/home/info.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+statusContainer=$1
+eval "declare -A settings="${2#*=}
+eval "declare -A headers="${3#*=}
+
+echo 200 > $statusContainer
+
+cat <
+
+
+ Info
+
+
+ Settings
+EOF
+for key in "${!settings[@]}"; do
+ echo "$key -> ${settings[$key]}
"
+done
+cat <Headers
+EOF
+for key in "${!headers[@]}"; do
+ echo "$key -> ${headers[$key]}
"
+done
+cat << EOF
+
+
+
+EOF
diff --git a/home/stuff/add.sh b/home/stuff/add.sh
new file mode 100755
index 0000000..5360896
--- /dev/null
+++ b/home/stuff/add.sh
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+statusContainer=$1
+eval "declare -A settings="${2#*=}
+eval "declare -A headers="${3#*=}
+
+
+if test "${headers[query]}" == ""; then
+ echo 200 > $statusContainer
+
+ cat<
+
+
+ Add to guestbook
+
+
+ Add something to the guestbook
+
+
+
+EOF
+ exit
+fi
+
+name=""
+text=""
+
+fields=$(echo ${headers[query]} | tr "&" "\n")
+for field in $fields; do
+ key=$(echo $field | awk -F= '{ print $1 }')
+ value=$(echo $field | awk -F= '{for (i=2; i<=NF; i++) print $i}')
+
+ if test "$key" = "name"; then
+ name=$value
+ elif test "$key" = "text"; then
+ text=$value
+ fi
+done
+
+if test "$name" = "" -o "$text" = ""; then
+ echo 400 > $statusContainer
+ echo 400 - Bad Request
+ exit
+fi
+
+cat >> ./guestbook.txt < $statusContainer
+echo "Location: ./guestbook.txt" >> $statusContainer
diff --git a/home/stuff/guestbook.txt b/home/stuff/guestbook.txt
new file mode 100644
index 0000000..8b04d42
--- /dev/null
+++ b/home/stuff/guestbook.txt
@@ -0,0 +1,6 @@
+
+===============================
+Sat Nov 18 01:20:41 CET 2017: overflow
+
+Welcome. : )
+
diff --git a/home/test/cgi-test.c b/home/test/cgi-test.c
new file mode 100644
index 0000000..4fbf4ef
--- /dev/null
+++ b/home/test/cgi-test.c
@@ -0,0 +1,8 @@
+#include
+
+int main() {
+
+ printf("Hello World");
+
+ return 0;
+}
diff --git a/home/test/cgi-test.cgi b/home/test/cgi-test.cgi
new file mode 100755
index 0000000..f2e944b
Binary files /dev/null and b/home/test/cgi-test.cgi differ
diff --git a/home/test/non-executeable-script.sh b/home/test/non-executeable-script.sh
new file mode 100644
index 0000000..a9f4e38
--- /dev/null
+++ b/home/test/non-executeable-script.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+echo Hello World
diff --git a/home/test/php-test.php b/home/test/php-test.php
new file mode 100755
index 0000000..e542041
--- /dev/null
+++ b/home/test/php-test.php
@@ -0,0 +1,4 @@
+#!/usr/bin/php
+ $statusContainer
+echo "Location: ../stuff/guestbook.txt" >> $statusContainer
diff --git a/index.sh b/index.sh
new file mode 100755
index 0000000..c6906aa
--- /dev/null
+++ b/index.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+server="$1"
+host="$2"
+rpath="$3"
+path="$4"
+statuscontainer=$5
+
+echo 200 > $statuscontainer
+
+cat <
+
+
+ Index of $rpath
+
+
+ Index of $rpath
+
+
+
+
+ Name
+ |
+
+ Type
+ |
+
+ Executeable
+ |
+
+ Size
+ |
+
+EOF
+
+for file in $(ls -a $path); do
+ if test "$file" = ".." -a "$rpath" = "/"; then
+ continue;
+ fi
+ cat <
+
+ $file
+ |
+
+ $(file -b $path/$file)
+ |
+
+ $(if test ! -d $path/$file; then if test -x $path/$file; then echo yes; else echo no; fi; fi)
+ |
+
+ $(if test ! -d $path/$file; then du -kh $path/$file | cut -f1; fi)
+ |
+
+EOF
+done
+
+cat <
+
+ $host ($server)
+
+
+EOF
diff --git a/response.sh b/response.sh
new file mode 100755
index 0000000..7fe4ab9
--- /dev/null
+++ b/response.sh
@@ -0,0 +1,133 @@
+#!/bin/bash
+
+settingsfile=$1
+eval "$(cat $settingsfile)" # declare settings array
+
+declare -A headers
+first=1
+while true; do
+ IFS=$'\r' read header
+ if test "$header" = ""; then
+ break
+ fi
+ if test $first = 1; then
+ headers[method]=$(echo "$header" | awk '{ print $1 }')
+ headers[http]=$(echo "$header" | awk '{ print $3 }' | awk -F/ '{ print $2} ')
+ headers[path]=$(echo "$header" | awk '{ print $2 }')
+ first=0
+ continue
+ fi
+ headers[$(echo $header | awk -F: '{ print $1}')]="$(echo "$header" | awk '{for (i=2; i<=NF; i++) print $i}')"
+done
+
+rpath="$(realpath -sm "${headers[path]}")"
+headers[query]="$(echo "$rpath" | awk -F? '{for (i=2; i<=NF; i++) print $i}')"
+rpath="$(echo "$rpath" | awk -F? '{ print $1 }')"
+
+path="${settings[home]}${rpath}"
+path="$(realpath -sm "$path")"
+
+urlencode() {
+ python -c "import urllib, sys; print urllib.quote(sys.argv[1])" "$1"
+}
+
+placeholder() {
+ declare -A tokens
+ tokens[path]="$rpath ($path)"
+ tokens[host]="${headers[Host]}"
+ tokens[server]="${settings[server]}"
+
+ text="$(cat)"
+
+ for key in "${!tokens[@]}"; do
+ key="$(echo "$key" | sed -e 's/[]\/$*.^|[]/\\&/g')"
+ value="$(echo "${tokens[$key]}" | sed -e 's/[]\/$*.^|[]/\\&/g')"
+
+ text=$(echo "$text" | sed -e "s/\[$key\]/$value/g")
+
+ done
+
+ echo "$text"
+}
+
+addStatusContainer() {
+ i=0
+ container="/dev/shm/st-cont-$$-";
+ while true; do
+ if test -f $container$i; then
+ i=$(($i+1))
+ continue
+ fi
+ container=$container$i
+ break
+ done
+ touch $container
+ echo $container
+}
+removeStatusContainer() {
+ container=$1
+ rm $container
+}
+
+isExecutable() {
+ path=$1
+ if test ! -x $path -o ! -f $path; then
+ return 1
+ fi
+ ext="$(echo $path | awk -F. '{ print $NF }')"
+ for i in ${settings[executeable]}; do
+ if test "$ext" = "$i"; then
+ return 0
+ fi
+ done
+ return 1
+}
+
+status=500
+content=""
+declare -A responseHeaders
+responseHeaders[Content-Type]="text/html"
+responseHeaders[Server]="${settings[server]}"
+
+
+if test ! -e "$path"; then
+ status=404
+
+ content="$(placeholder < ./404.html)"
+
+elif test ${settings[index]} = true -a -d "$path"; then
+ container=$(addStatusContainer)
+ content=$(./index.sh "${settings[server]}" "${headers[Host]}" "$rpath" "$path" "$container")
+ status=$(cat $container)
+ removeStatusContainer $container
+
+elif $(isExecutable $path); then
+ container=$(addStatusContainer)
+ pushd "$(dirname $path)" > /dev/null
+ content=$($path $container "$(declare -p settings)" "$(declare -p headers)")
+ popd > /dev/null
+ status=$(head -n 1 $container)
+ if test "$status" = ""; then
+ status=200
+ fi
+ while read line; do
+ responseHeaders[$(echo $line | awk -F: '{ print $1 }')]="$(echo "$line" | awk '{for (i=2; i<=NF; i++) print $i}')"
+ done <<< $(tail -n 1 $container)
+
+ removeStatusContainer $container
+else
+ status=200
+ responseHeaders['Content-Type']="$(file -b --mime-type $path)"
+ content=$(cat $path)
+fi
+
+length=$(printf "%s" "$content" | wc -c)
+
+echo -en "HTTP/1.1 $status $(./statusString.sh $status)\r\n"
+echo -en "Content-Length: $length\r\n"
+for key in ${!responseHeaders[@]}; do
+ echo -en "$(urlencode "$key"): $(urlencode "${responseHeaders[$key]}")\r\n"
+done
+echo -en "\r\n"
+printf "%s" "$content"
+
diff --git a/server.sh b/server.sh
new file mode 100755
index 0000000..ba1096b
--- /dev/null
+++ b/server.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+EXIT_FAILURE=1
+EXIT_SUCCESS=0
+
+port=-1
+progname="server"
+
+help() {
+ cat << EOF
+usage: $progname --port=PORT
+
+Options:
+ -p, --port=PORT set port
+ -h, --home=HOME set home directory
+ -v, --verbose set to verbose mode
+ -q, --quiet don't output anything
+EOF
+}
+
+verboselevel=0
+echoOnVerbose() {
+ if test "$verboselevel" -ge $1; then
+ echo -n "$2"
+ fi
+}
+
+progname="$0"
+
+OPTS=$(getopt -o "p:vqh:" -l "port:,verbose,quiet,home:" -- $@)
+if test $? != 0; then
+ exit $EXIT_FAILURE
+fi
+
+eval set -- "$OPTS"
+
+home="./home/"
+
+while true; do
+ case "$1" in
+ -p|--port) port=$2; shift 2;;
+ -v|--verbose) verboselevel=$(($verboselevel+1)); shift;;
+ -q|--quiet) verboselevel=-1; shift;;
+ -h|--home) home=$2; shift 2;;
+ --) shift; break;;
+ esac
+done
+
+if test "$port" -lt 1; then
+ help
+ exit $EXIT_FAILURE
+fi
+
+settingsfile="/dev/shm/wserver-$$"
+declare -A settings
+settings[home]=$home
+settings[verbose]=$verboselevel
+settings[executeable]="sh php py cgi"
+settings[server]="server"
+settings[index]="true"
+declare -p settings > $settingsfile
+
+echo "Starting... "
+socat $(echoOnVerbose 2 "-vv") tcp-listen:$port,reuseaddr,fork SYSTEM:"./response.sh $settingsfile" > /dev/null
+
+if test $? != 0; then
+ exit $EXIT_FAILURE
+fi
diff --git a/statusString.sh b/statusString.sh
new file mode 100755
index 0000000..8ced6a3
--- /dev/null
+++ b/statusString.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+status=$1
+
+case $status in
+ 100) echo Continue ;;
+ 101) Switching Protocols ;;
+ 102) Processing ;;
+
+ 200) echo OK ;;
+ 201) echo Created ;;
+ 202) echo Accepted ;;
+ 203) echo Non-Authoritative Information ;;
+ 204) echo No Content ;;
+ 205) echo Reset Content ;;
+ 206) echo Partial Content ;;
+ 207) echo Multi-Status ;;
+ 208) echo Already Reported ;;
+ 226) echo IM Used ;;
+
+ 300) echo Multiple Choices ;;
+ 301) echo Moved Permanently ;;
+ 302) echo Found ;;
+ 303) echo See Other ;;
+ 304) echo Not Modified ;;
+ 305) echo Use Proxy ;;
+ 306) echo Switch Proxy ;;
+ 307) echo Temporary Redirect ;;
+ 308) echo Permanent Redirect ;;
+
+ 400) echo Bad Request ;;
+ 401) echo Unauthorized ;;
+ 402) echo Payment Required ;;
+ 403) echo Forbidden ;;
+ 404) echo Not Found ;;
+ 405) echo Method Not Allowed ;;
+ 406) echo Not Acceptable ;;
+ 407) echo Proxy Authentication Required ;;
+ 408) echo Request Timeout ;;
+ 409) echo Conflict ;;
+ 410) echo Gone ;;
+ 411) echo Length Required ;;
+ 412) echo Precondition Failed ;;
+ 413) echo Payload Too Large ;;
+ 414) echo URI Too Long ;;
+ 415) echo Unsupported Media Type ;;
+ 416) echo Range Not Satisfiable ;;
+ 417) echo Expectation Failed ;;
+ 418) echo I\'m a teapot ;;
+ 421) echo Misdirected Request ;;
+ 422) echo Unprocessable Entity ;;
+ 423) echo Locked ;;
+ 424) echo Failed Dependency ;;
+ 426) echo Upgrade Required ;;
+ 428) echo Precondition Required ;;
+ 429) echo Too Many Requests ;;
+ 431) echo Request Header Fields Too Large ;;
+ 451) echo Unavailable For Legal Reasons ;;
+
+ 500) echo Internal Server Error ;;
+ 501) echo Not Implemented ;;
+ 502) echo Bad Gateway ;;
+ 503) echo Service Unavailable ;;
+ 504) echo Gateway Timeout ;;
+ 505) echo HTTP Version Not Supported ;;
+ 506) echo Variant Also Negotiates ;;
+ 507) echo Insufficient Storage ;;
+ 508) echo Loop Detected ;;
+ 510) echo Not Extended ;;
+ 511) echo Network Authentication Required ;;
+ *) echo Unknown
+esac
diff --git a/test-response.sh b/test-response.sh
new file mode 100755
index 0000000..90fc9ca
--- /dev/null
+++ b/test-response.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+echo "Start response.sh" 1>&2
+
+settingsfile=$1
+eval "$(cat $settingsfile)" # declare settings array
+
+declare -A headers
+first=1
+while true; do
+ IFS=$'\r' read header
+ if test "$header" = ""; then
+ break
+ fi
+ if test $first = 1; then
+ headers[method]=$(echo "$header" | awk '{ print $1 }')
+ headers[http]=$(echo "$header" | awk '{ print $3 }' | awk -F/ '{ print $2} ')
+ headers[path]=$(echo "$header" | awk '{ print $2 }')
+ first=0
+ continue
+ fi
+ headers[$(echo $header | awk -F: '{ print $1}')]="$(echo "$header" | awk '{for (i=2; i<=NF; i++) print $i}')"
+done
+
+content="
+
+
+ Test
+
+
+ Hallo Welt
+ $(for key in ${!headers[@]}; do echo "$key" "->" "${headers[$key]}" "
"; done)
+
+
+ $(for key in ${!settings[@]}; do echo "$key" "->" "${settings[$key]}" "
"; done)
+
+
+"
+
+length=$(printf "%s" "$content" | wc -c)
+
+echo "$length" 1>&2
+echo "$content" 1>&2
+
+echo -en "HTTP/1.1 200 OK\r\n"
+echo -en "Content-Type: text/html\r\n"
+echo -en "Server: testserver\r\n"
+echo -en "Content-Length: $length\r\n"
+echo -en "\r\n"
+printf "%s" "$content"
+