存储在 bash 变量中时损坏的 png 或 jpeg 图像文件

Corrupt png or jpeg image files when stored in bash variable

我正在尝试使用 netcat 编写一个 httpserver。它不起作用我不知道为什么?当我删除“read -s GET”时,它适用于纯文本但不适用于图像,浏览器仅显示损坏图像的图标。

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"

它不适用于图像文件的原因是因为这些是二进制数据,Shell 无法将二进制存储到变量中,如下所示:

output=$(cat "$resource")

也如 there are code pitfalls that would be shown to you with a code check from https://shellcheck.net/

所述

以下是处理二进制文件的方法:

#!/usr/bin/env bash

# Function to stream a binary file as HTTP body
send_body () {
  printf '\r\n'
  cat "" 2>/dev/null || : # Can stream binary data
  printf '\r\n'
}

input=

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"