302重定向从CGI脚本停止在Apache 2.4中工作

时间:2016-04-19 17:54:11

标签: cgi http-redirect apache2.4

我继承了自编写的CGI应用程序的维护 文档,从未见过原作者。应用程序 停止在Debian 8工作,但在Debian 7和CentOS 5工作 主要的变化是从Apache 2.2升级(Debian 7& CentOS 5)到Apache 2.4(由Debian 8使用)和从perl升级 5.8(在CentOS 5中)分别为perl 5.14(在Debian 7中)到perl 5.20。 有问题的部分归结为以下脚本(a 302重定向):

#!/usr/bin/perl
$|=1; # activate auto-flushing of stdout
use strict;
use warnings;
my $CRLF = "\015\012";
print STDOUT "Status: 302 Moved Temporarily$CRLF" .
             "Location: /does_not_matter$CRLF" .
             "URI: /does_not_matter$CRLF" .
             "Connection: close$CRLF" .
             "Content-type: text/html; charset=UTF-8$CRLF$CRLF";
close STDOUT;
while(1) {
        sleep 1;
}

观察到的行为是重定向永远不会到达客户端 只要脚本仍在运行与Apache 2.4一起使用,但是 Apache的error.log中没有错误消息。我改变了客户端 (Firefox,Chromium,wget),Apache模块(mod_cgid& mod_cgi), 发送了其他标头,删除了close STDOUT,删除了 $|=1,将$CRLF替换为\n并制作了脚本 fork并退出父进程(以便Apache不再是 父进程),一切都无济于事。唯一有效的方法:使用 Apache 2.2,将脚本转换为NPH-CGI脚本(必须发送 完整的HTTP标头,Apache不会以任何方式修改,即使 它们包含错误),使脚本退出而不是输入 无尽的循环。我通过tcpdump确认了包的 在脚本被杀死之前,重定向确实永远不会离开服务器。 并从响应中的日期行和最终的时间 到达我收集Apache立即收到我的输出(& 立即将日期行添加到标题中,但不发送 回应客户。

不要回答,我已经自己解决了解决方案 并会写一个答案。我只想提供解决方案 对可能遇到同样问题的其他人。

1 个答案:

答案 0 :(得分:1)

问题是缺少邮件正文。 302重定向可能包含 消息体(参见RFC 2616,第4.3节(消息体):"所有其他 响应确实包含一个消息体,尽管它可能为零 长度"),但Content-Length-line是可选的(RFC的第4.4节) 2616表示消息体长度可以通过关闭来确定 连接如果缺少Content-Length-line)。既然Apache可以 不知道我是否要发送邮件正文,它必须等待 直到我关闭连接或实际发送邮件正文 (Apache 2.2显然在这里错误地表现为不等待 邮件正文 - 或者close STDOUT;在perl中没有 5.20它在旧的perl版本中做了什么)。正确的脚本应该 因此看起来像这样(经过验证可以在Apache 2.2和 Apache 2.4) - 唯一的区别是额外的$CRLF 终止零长度的消息体:

#!/usr/bin/perl
$|=1; # activate auto-flushing of stdout
use strict;
use warnings;
my $CRLF = "\015\012";
print STDOUT "Status: 302 Moved Temporarily$CRLF" .
             "Location: /doesNotMatter$CRLF" .
             "URI: /doesNotMatter$CRLF" .
             "Connection: close$CRLF" .
             "Content-type: text/html; charset=UTF-8$CRLF$CRLF$CRLF";
close STDOUT;
while(1) {
        sleep 1;
}

https://stackoverflow.com/a/8062277/2845840指出了我正确的方向。