我想扩展this example webserver 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 OK\r"
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 Found\r"
echo -e "Content-Type: text/html\r"
echo -e "\r"
echo -e "404 Not Found\r"
echo -e "Not Found
The requested resource was not found\r"
echo -e "\r"
fi
done
将代码包装在循环中是不够的,因为浏览器不会渲染任何内容。我怎样才能做到这一点?
特定于应用程序的原因使得启动脚本 per-request 成为一种不合适的方法。
TCP侦听器需要接受浏览器连接并将它们连接到脚本。我使用socat
来执行此操作:
$ socat EXEC:./webserver TCP4-LISTEN:8080,reuseaddr,fork
通过将浏览器指向http://localhost:8080
。
答案 0 :(得分:0)
浏览器需要知道预期的数据量,并且它不会渲染任何内容 它获取该数据或连接由服务器关闭。
HTTP响应应该包含Content-Length
标头,或者它应该使用* chunked
* Transfer-Encoding。
example script不会这样做。但是,它可以工作,因为它处理单个请求 和退出导致连接关闭。
因此,解决问题的一种方法是设置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 OK\r"
echo -e "Content-Type: text/html\r"
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 Found\r"
echo -e "Content-Type: text/html\r"
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
答案 1 :(得分:0)
另一个解决方案是让脚本触发连接关闭。一种方法是发送socat
可以解释为EOF的转义码。
例如,在回复的末尾添加BELL character code(ASCII 7,\a
):
echo -e '\a'
并告诉socat
将其解释为EOF:
$ socat EXEC:./webserver,escape=7 TCP4-LISTEN:8080,reuseaddr,fork
任何通常未使用的角色都可以,BELL就是一个例子。
虽然上述方法可行,但HTTP实际上应该包含内容类型或传输编码标头。如果使用类似的技术从脚本提供任意(非HTTP)请求,则此替代方法可能很有用。