Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 28 additions & 25 deletions bashttpd
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
#
# Original author: Avleen Vig, 2012
# Reworked by: Josh Cartwright, 2012
# QA: Jacob Hrbek, 2019

warn() { echo "WARNING: $@" >&2; }
warn() { printf 'WARNING %s\n' "$@" >&2; }

[ -r bashttpd.conf ] || {
[ ! -e bashttpd.conf ] && {
cat >bashttpd.conf <<'EOF'
#
# bashttpd.conf - configuration for bashttpd
Expand Down Expand Up @@ -104,13 +105,15 @@ EOF
exit 1
}

recv() { echo "< $@" >&2; }
send() { echo "> $@" >&2;
printf '%s\r\n' "$*"; }
recv() { printf "< %s\n" "$@" >&2; }
send() {
printf "> %s\n" "$@" >&2
printf '%s\r\n' "$*"
}

[[ $UID = 0 ]] && warn "It is not recommended to run bashttpd as root."
[ -z "$(id -u)" ] && warn "It is not recommended to run bashttpd as root."

DATE=$(date +"%a, %d %b %Y %H:%M:%S %Z")
DATE="$(date +"%a, %d %b %Y %H:%M:%S %Z")"
declare -a RESPONSE_HEADERS=(
"Date: $DATE"
"Expires: $DATE"
Expand All @@ -131,7 +134,7 @@ declare -a HTTP_RESPONSE=(
)

send_response() {
local code=$1
local code="$1"
send "HTTP/1.0 $1 ${HTTP_RESPONSE[$1]}"
for i in "${RESPONSE_HEADERS[@]}"; do
send "$i"
Expand All @@ -150,9 +153,9 @@ fail_with() {
}

serve_file() {
local file=$1
local file="$1"

CONTENT_TYPE=
CONTENT_TYPE=""
case "$file" in
*\.css)
CONTENT_TYPE="text/css"
Expand Down Expand Up @@ -180,7 +183,7 @@ serve_dir_with_tree()
add_response_header "Content-Type" "text/html"

# The --du option was added in 1.6.0.
read x tree_vers x < <(tree --version)
read -r x tree_vers x < <(tree --version)
[[ $tree_vers == v1.6* ]] && tree_opts="--du"

send_response_ok_exit < \
Expand All @@ -189,7 +192,7 @@ serve_dir_with_tree()

serve_dir_with_ls()
{
local dir=$1
local dir="$1"

add_response_header "Content-Type" "text/plain"

Expand All @@ -198,7 +201,7 @@ serve_dir_with_ls()
}

serve_dir() {
local dir=$1
local dir="$1"

# If `tree` is installed, use that for pretty output.
which tree &>/dev/null && \
Expand All @@ -210,22 +213,22 @@ serve_dir() {
}

serve_dir_or_file_from() {
local URL_PATH=$1/$3
local URL_PATH="$1/$3"
shift

# sanitize URL_PATH
URL_PATH=${URL_PATH//[^a-zA-Z0-9_~\-\.\/]/}
[[ $URL_PATH == *..* ]] && fail_with 400
URL_PATH="${URL_PATH//[^a-zA-Z0-9_~\-\.\/]/}"
[[ "$URL_PATH" == *..* ]] && fail_with 400

# Serve index file if exists in requested directory
[[ -d $URL_PATH && -f $URL_PATH/index.html && -r $URL_PATH/index.html ]] && \
[ -d "$URL_PATH" ] && [ -f "$URL_PATH/index.html" ] && [ -r "$URL_PATH/index.html" ] && \
URL_PATH="$URL_PATH/index.html"

if [[ -f $URL_PATH ]]; then
[[ -r $URL_PATH ]] && \
if [ -f "$URL_PATH" ]; then
[ -r "$URL_PATH" ] && \
serve_file "$URL_PATH" "$@" || fail_with 403
elif [[ -d $URL_PATH ]]; then
[[ -x $URL_PATH ]] && \
elif [ -d "$URL_PATH" ]; then
[ -x "$URL_PATH" ] && \
serve_dir "$URL_PATH" "$@" || fail_with 403
fi

Expand All @@ -238,10 +241,10 @@ serve_static_string() {
}

on_uri_match() {
local regex=$1
local regex="$1"
shift

[[ $REQUEST_URI =~ $regex ]] && \
[[ "$REQUEST_URI" =~ $regex ]] && \
"$@" "${BASH_REMATCH[@]}"
}

Expand All @@ -253,7 +256,7 @@ unconditionally() {
read -r line || fail_with 400

# strip trailing CR if it exists
line=${line%%$'\r'}
line="${line%%$'\r'}"
recv "$line"

read -r REQUEST_METHOD REQUEST_URI REQUEST_HTTP_VERSION <<<"$line"
Expand All @@ -269,7 +272,7 @@ read -r REQUEST_METHOD REQUEST_URI REQUEST_HTTP_VERSION <<<"$line"
declare -a REQUEST_HEADERS

while read -r line; do
line=${line%%$'\r'}
line="${line%%$'\r'}"
recv "$line"

# If we've reached the end of the headers, break.
Expand Down