302 从 CGI 脚本重定向在 Apache 2.4 中停止工作
302 Redirect from CGI script stopped working in Apache 2.4
我继承了 self-written 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 = "52";
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),
发送了额外的 headers,移除了 close STDOUT
,移除了
$|=1
,将 $CRLF
替换为 \n
并制作了脚本
fork 并退出 parent 进程(这样 Apache 就不再是
parent 过程),都无济于事。唯一有用的东西:使用
Apache 2.2,将脚本变成 NPH-CGI-script(必须发送
完整的 HTTP headers,Apache 不会以任何方式修改,即使
它们包含错误),使脚本退出而不是输入
无限循环。我通过 tcpdump 确认了带有
重定向确实在脚本被杀死之前永远不会离开服务器。
并从响应中的 Date-line 和最终的时间
到达 我收集到 Apache 立即收到我的输出(&
立即将 Date-line 添加到 headers),但不发送
回复客户。
不用回答了,我已经自己想好了
并会写一个答案。我只想提供解决方案
给可能遇到同样问题的其他人。
问题是缺少邮件正文。 302 重定向可能包含
消息正文(参见 RFC 2616,第 4.3 节(消息正文):“所有其他
响应确实包含消息正文,尽管它可能为零
length”),但是 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 = "52";
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;
}
给我指明了正确的方向。
我继承了 self-written 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 = "52";
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),
发送了额外的 headers,移除了 close STDOUT
,移除了
$|=1
,将 $CRLF
替换为 \n
并制作了脚本
fork 并退出 parent 进程(这样 Apache 就不再是
parent 过程),都无济于事。唯一有用的东西:使用
Apache 2.2,将脚本变成 NPH-CGI-script(必须发送
完整的 HTTP headers,Apache 不会以任何方式修改,即使
它们包含错误),使脚本退出而不是输入
无限循环。我通过 tcpdump 确认了带有
重定向确实在脚本被杀死之前永远不会离开服务器。
并从响应中的 Date-line 和最终的时间
到达 我收集到 Apache 立即收到我的输出(&
立即将 Date-line 添加到 headers),但不发送
回复客户。
不用回答了,我已经自己想好了 并会写一个答案。我只想提供解决方案 给可能遇到同样问题的其他人。
问题是缺少邮件正文。 302 重定向可能包含
消息正文(参见 RFC 2616,第 4.3 节(消息正文):“所有其他
响应确实包含消息正文,尽管它可能为零
length”),但是 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 = "52";
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;
}
给我指明了正确的方向。