Web服务器外壳脚本可以使用标准输入/输出服务多个请求



我想扩展此示例网络服务器shell脚本以处理多个请求。这是来源:

#!/bin/sh
# based on https://debian-administration.org/article/371/A_web_server_in_a_shell_script
base=/srv/content
while /bin/true
do
read request
while /bin/true; do
  read header
  [ "$header" == $'r' ] && break;
done
url="${request#GET }"
url="${url% HTTP/*}"
filename="$base$url"
if [ -f "$filename" ]; then
  echo -e "HTTP/1.1 200 OKr"
  echo -e "Content-Type: `/usr/bin/file -bi "$filename"`r"
  echo -e "r"
  cat "$filename"
  echo -e "r"
else
  echo -e "HTTP/1.1 404 Not Foundr"
  echo -e "Content-Type: text/htmlr"
  echo -e "r"
  echo -e "404 Not Foundr"
  echo -e "Not Found
           The requested resource was not foundr"
  echo -e "r"
fi
done

将代码包装在循环中是不够的,因为浏览器不会渲染任何内容。我该如何做这项工作?

特定于应用程序的原因使启动脚本每次请求不合适的方法。


需要TCP侦听器接受浏览器连接并将其连接到脚本。我使用socat来做到这一点:

$ socat EXEC:./webserver TCP4-LISTEN:8080,reuseaddr,fork

通过将浏览器指向http://localhost:8080

浏览器需要知道要期望多少数据,并且不会渲染任何内容它获取该数据或连接由服务器关闭。

HTTP响应应包括Content-Length标头,否则应使用 *块*转移编码。

示例脚本不这样做。但是,它起作用是因为它处理了一个请求 并导致连接关闭的退出。

因此,解决问题的一种方法是设置Content-Length标头。这是一个有效的示例:

#!/bin/sh
# stdio webserver based on https://debian-administration.org/article/371/A_web_server_in_a_shell_script
respond_with() {
  echo -e "HTTP/1.1 200 OKr"
  echo -e "Content-Type: text/htmlr"
  echo -e "Content-Length: ${#1}r"
  echo -e "r"
  echo "<pre>${1}</pre>"
  echo -e "r"
}
respond_not_found() {
  content='<h1>Not Found</h1>
           <p>The requested resource was not found</p>'
  echo -e "HTTP/1.1 404 Not Foundr"
  echo -e "Content-Type: text/htmlr"
  echo -e "Content-Length: ${#content}r"
  echo -e "r"
  echo "${content}"
  echo -e "r"
}
base='/var/www'
while /bin/true; do
  read request
  while /bin/true; do
    read header
    [ "$header" == $'r' ] && break;
  done
  url="${request#GET }"
  url="${url% HTTP/*}"
  filename="$base/$url"
  if [ -f "$filename" ]; then
    respond_with "$(cat $filename)"
  elif [ -d "$filename" ]; then
    respond_with "$(ls -l $filename)"
  else
    respond_not_found
  fi
done

另一个解决方案是使脚本触发连接关闭。一种方法是发送socat可以解释为EOF的逃生代码。

例如,在响应末尾添加钟字符代码(ASCII 7,a):

echo -e 'a'

并告诉socat将其解释为EOF:

$ socat EXEC:./webserver,escape=7 TCP4-LISTEN:8080,reuseaddr,fork

任何通常未使用的角色都会做的,贝尔就是一个例子。

尽管上述功能将起作用,但HTTP应该真正包含内容类型或传输编码标头。如果使用类似技术从脚本提供任意(非HTTP)请求时,此替代方法可能很有用。

最新更新