#!/usr/bin/env bash # # A simple, configurable HTTP server written in bash. # # See LICENSE for licensing information. # # Original author: Avleen Vig, 2012 # Reworked by: Josh Cartwright, 2012 warn() { echo "WARNING: $@" >&2; } recv() { echo "< $@" >&2; } send() { echo "> $@" >&2; printf '%s\r\n' "$*"; } [[ $UID = 0 ]] && warn "It is not recommended to run bashttpd as root." DATE=$(date +"%a, %d %b %Y %H:%M:%S %Z") declare -a RESPONSE_HEADERS=( "Date: $DATE" "Expires: $DATE" "Server: Slash Bin Slash Bash" ) add_response_header() { RESPONSE_HEADERS+=("$1: $2") } declare -a HTTP_RESPONSE=( [200]="OK" [400]="Bad Request" [403]="Forbidden" [404]="Not Found" [405]="Method Not Allowed" [500]="Internal Server Error" ) send_response() { local code=$1 send "HTTP/1.0 $1 ${HTTP_RESPONSE[$1]}" for i in "${RESPONSE_HEADERS[@]}"; do send "$i" done send while read -r line; do send "$line" done } send_response_ok_exit() { send_response 200; exit 0; } fail_with() { send_response "$1" <<< "$1 ${HTTP_RESPONSE[$1]}" exit 1 } serve_static_string() { add_response_header "Content-Type" "text/plain;charset=utf-8" send_response_ok_exit <<< "$1" } where () { h="$(dirname "$0")" # If $h isnt absolute, prepend working dir if [[ ! "${h:0:1}" = "/" ]] ; then h="$(pwd)/$(dirname "$0")" fi h="$(realpath "$h")" echo "$h" } main () { # Request uri must be a relative path from the exercices/corriges directory [ -x "$REQUEST_URI" ] || [ ! -d "$REQUEST_URI" ] || fail_with 404 here="$(where)" path="$(realpath "$here/exercices/corriges/$REQUEST_URI")" [[ "$path" = "$here"* ]] || fail_with 404 serve_static_string "$(basename "$path" | cut -d '.' -f 1) : $(bash "$path" 2>&1 && echo Ok || echo 'Non validé')" } # Request-Line HTTP RFC 2616 $5.1 read -r line || fail_with 400 # strip trailing CR if it exists line=${line%%$'\r'} recv "$line" read -r REQUEST_METHOD REQUEST_URI REQUEST_HTTP_VERSION <<<"$line" [ -n "$REQUEST_METHOD" ] && \ [ -n "$REQUEST_URI" ] && \ [ -n "$REQUEST_HTTP_VERSION" ] \ || fail_with 400 # Only GET is supported at this time [ "$REQUEST_METHOD" = "GET" ] || fail_with 405 declare -a REQUEST_HEADERS while read -r line; do line=${line%%$'\r'} recv "$line" # If we've reached the end of the headers, break. [ -z "$line" ] && break REQUEST_HEADERS+=("$line") done main fail_with 500