社内検証サーバがぶっ壊れたので新しくサーバ構築しつつ動作確認中。そんな中、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 プログラムの方を直すべき。