我正在尝试使用 xinetd 和 bash 为 webhook 编写一个简单的处理程序。我有一个简单的案例,使用 xinetd 的这个配置:
service github-hooks
{
port = 61000
socket_type = stream
protocol = tcp
wait = no
user = ubuntu
server = /home/ubuntu/github-hooks.sh
}
还有这个 bash 脚本:
#!/bin/bash
echo -e "HTTP/1.1 200 OK"
现在,我想读取在 webhook 中发送的帖子数据,这样我就可以做一些比总是返回 200 更有趣的事情。
我如何从我的 bash 脚本读取帖子数据?
我试过了:
while read line; do
echo "$line" >> /home/ubuntu/test
done < /dev/stdin
但这对我来说不起作用。
编辑
感谢以下建议,我停下来xinetd
并用来nc
查看通过网络传输的原始数据:
$nc -l 61000
并得到这个:
POST / HTTP/1.1
Host: <snip>:61000
Accept: */*
User-Agent: GitHub-Hookshot/375c44e
X-GitHub-Event: pull_request
X-GitHub-Delivery: 2dc1fb00-1c8e-11e6-9955-64afafb6ce32
content-type: application/json
X-Hub-Signature: sha1=45afd85b7d4312fa8ac4c56638e8e9699e2ddb36
Content-Length: 20558
{"action":"opened","number":116,"pull_request": <snip>
因此,数据正在发送。现在,知道有 11 行被发送,我读了 11 行:
for i in {0..10}
do
read line
echo "$line" >> /home/ubuntu/test
done
并且,我得到了相同的输出(非常成功:)
POST / HTTP/1.1
Host: <snip>:61000
Accept: */*
User-Agent: GitHub-Hookshot/375c44e
X-GitHub-Event: pull_request
X-GitHub-Delivery: 2dc1fb00-1c8e-11e6-9955-64afafb6ce32
content-type: application/json
X-Hub-Signature: sha1=45afd85b7d4312fa8ac4c56638e8e9699e2ddb36
Content-Length: 20558
{"action":"opened","number":116,"pull_request": <snip>
也许我应该只读 9 行,然后使用Content-Length
参数读取其余部分?我仍然不太明白发生了什么,所以任何信息都会非常有帮助。
答案1
好吧,我从来没有弄清楚如何在有输入时读取,但我确实注意到标头中有一个长度。因此,我解析出长度,然后读取该数量的字符:
#!/bin/bash
for i in {1..9}
do
read line
done
array=(${line})
length=${array[1]}
read line
read -n ${length:0:-1} line
echo "$line" >> /home/ubuntu/test
echo -e "HTTP/1.1 200 OK"
现在我已经获得了 github 发送的帖子数据。
答案2
要读取 xinetd http 请求的标准 post 数据,程序只需读取标准输入。
我编写了一个 bash 脚本,用于读取和解析通过标准输入传入的 http 标头。从 xinetd 调用时很有用。我创建这个脚本是为了给想要创建可以识别 HTTP REST 类调用的 xinetd 服务的人提供一个起点。 https://github.com/rglaue/xinetd_bash_http_service
但本质上,读取 xinetd 服务中的 HTTP 输入(标头和 POST 数据)如下所示:
# Read HTTP Headers, line by line
# We're looking for the Content-Length HTTP header
: ${HTTP_CONTENT_LENGTH:=0}
while read -t 0.01 line; do
# If the line is empty, stop reading headers
if [ -z "$line" ]; then break; fi
# Read each HTTP Header
if echo "${line}" | grep -qi "^some-header:"; then
# do something here
elif echo "${line}" | grep -qi "^Content-Length:"; then
HTTP_CONTENT_LENGTH="$(echo "${line}"|cut -d" " -f 2-)"
fi
done
# Next read from standard input into the HTTP_POST_DATA variable
# (This assumes the request is a POST)
while IFS= read -N $HTTP_CONTENT_LENGTH -r -t 0.01 post_buffer; do
echo "Reading in the HTTP Post Data"
HTTP_POST_DATA="${HTTP_POST_DATA}${post_buffer}"
if [ ${#HTTP_POST_DATA} -ge ${HTTP_CONTENT_LENGTH} ]; then
# Make sure we stop reading, since we have read enough.
break;
fi
done
为什么要使用IFS=
- 该
-r
标志已读取数据,而不会在分隔符处停止 - IFS 是 bash 使用的内部字段分隔符,用于确定如何拆分单词以及如何拆分行。
- 我们将其清空
IFS
以确保 bash 不会改变我们对原始读取的预期结果read -r
。
对于read
参数:
- 该
-t 0.01
标志定义读取超时时间(以秒为单位)(0.01 秒) - 该
-r
标志读取原始数据,忽略分隔符\r\n
- 该
-N <num>
标志读取<num>个字符。
答案3
字面上cat
,或者xargs
,或者grep .
或者任何其他从标准输入读取的内容。