我已经为 Github 设置了一个 post-recieve 挂钩。它将向 Apache cgi 脚本发出 POST 请求,然后该脚本会将存储库的更改下载到本地克隆的裸存储库中。当我添加 a 时,脚本运行良好VARIABLE=$(cat -)
,但当我尝试发出发布请求并删除具有以下内容的行时,出现卷曲错误VARIABLE=
curl: (18) transfer closed with outstanding read data remaining
我的 POST 请求是由curl 生成的(后数据仅用于测试,不会在实际脚本中使用):
curl -D - -H "Connection: close" -H "Content-Type: application/json" -d '{ "repository": { "name": "webhook-test", "git_url": "git://github.com/bng44270/webhook-test.git", "ssh_url": "[email protected]:bng44270/webhook-test.git", "clone_url": "https://github.com/bng44270/webhook-test.git" }}' http://10.0.0.2/cgi-bin/clone.cgi --verbose
我的虚拟主机配置文件:
ScriptAlias "/cgi-bin" "/opt/hooks/cgi-bin"
DocumentRoot /opt/hooks/html
<Directory /opt/hooks>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
我的脚本运行:
#!/bin/bash
/sbin/runuser -l gogsjail -c '/usr/bin/git --git-dir /home/gogsjail/gogs-repositories/admin/upstream.git fetch --prune >/dev/null 2>&1' >/dev/null 2>&1
# VARIABLE=$(cat -)
echo "Content-type: text/json"
echo ""
echo '{"result":"success"}'
最后,curl 的输出:
* Expire in 0 ms for 6 (transfer 0x563f98984f90)
* Trying 10.0.0.2...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x563f98984f90)
* Connected to 10.0.0.2 (10.0.0.2) port 80 (#0)
> POST /cgi-bin/clone.cgi HTTP/1.1
> Host: 10.0.0.2
> User-Agent: curl/7.64.0
> Accept: */*
> Connection: close
> Content-Type: application/json
> Content-Length: 230
>
* upload completely sent off: 230 out of 230 bytes
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Date: Mon, 08 Feb 2021 12:55:42 GMT
Date: Mon, 08 Feb 2021 12:55:42 GMT
< Server: Apache/2.4.38 (Debian)
Server: Apache/2.4.38 (Debian)
< Connection: close
Connection: close
< Transfer-Encoding: chunked
Transfer-Encoding: chunked
< Content-Type: text/json
Content-Type: text/json
<
{"result":"success"}
* transfer closed with outstanding read data remaining
* Closing connection 0
curl: (18) transfer closed with outstanding read data remaining
VARIABLE=$(cat -)
如果我在echo-calls 之前运行,我会得到
* Expire in 0 ms for 6 (transfer 0x55ea56355f90)
* Trying 10.0.0.2...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x55ea56355f90)
* Connected to 10.0.0.2 (10.0.0.2) port 80 (#0)
> POST /cgi-bin/clone.cgi HTTP/1.1
> Host: 10.0.0.2
> User-Agent: curl/7.64.0
> Accept: */*
> Connection: close
> Content-Type: application/json
> Content-Length: 244
>
* upload completely sent off: 244 out of 244 bytes
< HTTP/1.1 200 OK
< Date: Mon, 08 Feb 2021 13:35:28 GMT
< Server: Apache/2.4.38 (Debian)
< Connection: close
< Transfer-Encoding: chunked
< Content-Type: text/json
<
{"result":"success"}
* Closing connection 0
有人可以把我推向正确的方向吗?
答案1
我想象 apache 正在做的事情相当于:读取来自客户端的所有请求,包括 POST 数据,并通过管道(比如说)将其写入 cgi 进程。它还读取来自 cgi 的回复并将其发送到客户端。它执行一个循环,select()
同时继续这些读取和写入。
当cgi退出并关闭管道时,apache的select()会因eof而在读取时出现异常,在写入时出现异常。如果 cgi 没有从 apache 读取 POST 数据,apache 会看到挂起的写入出现 ioerror,因此可能会认为 cgi 行为不当,然后直接关闭客户端连接而不进行进一步清理。
由于cgi不输出内容长度标头,apache无法确定回复的长度,因此输出标Transfer-Encoding: chunked
头。该协议通过由后续写入的长度组成的迷你标题包围回复中的每个写入。该协议需要通过发送写入长度 0 ( 0\r\n
) 来彻底终止。据推测,协议的最后一部分是缺失的,也是curl抱怨的原因。
分块协议不会通过curl公开,但您可能会通过--raw
或使用看到它strace()
。