xinetd 读取帖子数据

xinetd 读取帖子数据

我正在尝试使用 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 .或者任何其他从标准输入读取的内容。

相关内容