I am trying to write an httpserver using netcat. It doesn't work I dont know why ? when I remove ' read -s GET ', it works for plain text but for images it doesn't, the browser displays only the icon for broken images.
nc -l -k -p 80 -q 1 -e serverhttp.sh
serverhttp.sh
#!/bin/bash
index_page=index.html
error_page=Error.html
read -s GET # it doesn't work with this commond to be able to detect path.
resource=$(echo "$input" | grep -P -o '(?<=GET \/).*(?=\ )')
[ -z "$resource" ] && resource=$index_page || resource=$error_page
content_type=$(file -b --mime-type $resource)
case "$(echo "$content_type" | cut -d '/' -f2)" in
html)
output=$(cat "$resource")
;;
jpeg)
output=$(cat "$resource")
;;
png)
output=$(cat "$resource")
;;
*)
echo 'Unknown type'
esac
content_length=$(stat -c '%s' $resource)
echo -ne "HTTP 200 OK\r\n"
echo -ne "Content-Length: $content_length\r\n"
echo -ne "Content-Type: $content_type\r\n\n$output\n"
The reason it does not work with image files is because these are binary data and the Shell cannot store binary into variables like here:
output=$(cat "$resource")
Also as stated by Shawn, here there are code pitfalls that would be shown to you with a code check from https://shellcheck.net/
Here is how you could deal with binary files:
#!/usr/bin/env bash
# Function to stream a binary file as HTTP body
send_body () {
printf '\r\n'
cat "$1" 2>/dev/null || : # Can stream binary data
printf '\r\n'
}
input=$1
index_page=index.html
error_page=Error.html
# Parses the request string with Bash's built-in Regex engine
[[ "$input" =~ ^GET[[:space:]]/(.*)/?[[:space:]]HTTP/1\.[01]?$ ]] || :
resource=${BASH_REMATCH[1]}
# When resource is empty, substitute the value of $index_page
resource=${resource:-$index_page}
# Capture mime type
content_type=$(file -b --mime-type "$resource")
# Set http status code depending on if resource file exist
if [ -f "$resource" ]; then
http_status='200 OK'
else
resource="$error_page"
content_type='text/html'
http_status='404 NOT FOUND'
fi
# Check supported MIME types
case "${content_type#*/}" in
html | jpeg | png) ;;
*)
printf '%s\n' 'Unknown type' >&2
resource="$error_page"
content_type='text/html'
http_status='415 UNSUPPORTED MEDIA TYPE'
;;
esac
# Capture the content_length (default to 0)
read -r content_length _ < <(wc -c "$resource" 2>/dev/null)
content_length=${content_length:-0}
# Send reply
printf 'HTTP %s\r\n' "$http_status"
printf 'Content-Length: %d\r\n' "$content_length"
printf 'Content-Type: %s\r\n' "$content_type"
send_body "$resource"