社内検証サーバがぶっ壊れたので新しくサーバ構築しつつ動作確認中。そんな中、IO::Socket::INET を使って HTTP アクセスを行う perl スクリプトを動かしたところ、リクエスト先から「400 Bad Request」が返ってきてしまい接続不可。perlスクリプトはこんな具合。
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket;
my $sock = IO::Socket::INET->new(
PeerAddr => '192.168.0.20',
PeerPort => '80',
Proto => 'tcp'
);
my $out = "";
my $lf = "\n";
my $request_header =
"GET /test.php HTTP/1.0$lf"
. "UserAgent: testagent$lf$lf";
print $sock $request_header;
$sock->flush();
my $ret_code = <$sock>;
while (<$sock>){ m/^\r\n$/ && last; }
while (<$sock>){ $out .= $_; }
$sock->close() if($sock);
print $ret_code . "\n";
print $out . "\n";
今まで普通に動いていたのになんでだ…。全然原因がわからないので、リクエスト先(192.168.0.20)の Apache の httpd.conf を以下のように修正して apache 再起動しデバッグモードに変更。
LoadModule dumpio_module modules/mod_dumpio.so LogLevel debug DumpIOInput On
これで perl スクリプトを実行したところ、/var/log/error_log に以下が出力された。
[Thu Jan 31 15:28:26 2019] [debug] mod_dumpio.c(113): mod_dumpio: dumpio_in [getline-blocking] 0 readbytes [Thu Jan 31 15:28:26 2019] [debug] mod_dumpio.c(55): mod_dumpio: dumpio_in (data-HEAP): 23 bytes [Thu Jan 31 15:28:26 2019] [debug] mod_dumpio.c(74): mod_dumpio: dumpio_in (data-HEAP): GET /test.php HTTP/1.0\n [Thu Jan 31 15:28:26 2019] [debug] protocol.c(1260): [client 192.168.0.19] request failed: malformed request line
malformed request line でピンときた。多分改行コードのエラーだ。HTTPリクエストの改行コードは \n ではなく \r\n にしないといけない。先ほどの perl スクリプトの改行コードを修正。
# my $lf = "\n"; my $lf = "\r\n";
これで再度perlスクリプトを実行したところ正常に実行された。でもなんで今まで動いていた…? Apache に自動で改行コードを置換する設定ってあったっけか…。で調べていたら以下の記事がヒット。困ったときのスタックオーバーフローだわマジで。
mod rewrite - Have Apache Accept LF vs CRLF in Request Headers - Stack Overflow
最近の apache のバージョンではよりセキュアになり制限が増えたらしい。制限を緩めるためには過去のバージョンにダウングレードするか、以下設定を httpd.conf に記述して apache を再起動すればよい。
HttpProtocolOptions unsafe
手元の環境では perlスクリプトに手を入れることなく apache の設定変更のみで無事に動いた。ただし unsafe な設定なので、本来であれば perl プログラムの方を直すべき。
≪ 2019-02-01
人力音楽レコメンドエンジン
2019-01-30 ≫
餅、ボヘミアンラプソディ、カニ