diff -urN ../htmllint.orig/htmllint.cgi ./htmllint.cgi
--- ../htmllint.orig/htmllint.cgi Fri Sep 28 13:20:00 2012
+++ ./htmllint.cgi Fri Sep 28 15:00:00 2012
@@ -44,7 +44,8 @@
require 'common.rul';
use CGI;
-$CGI::POST_MAX = $MAXHTMLSIZE*1024 if $MAXHTMLSIZE > 0;
+# フォームデータのみでも26KB程度あるのでその分の余裕が必要
+$CGI::POST_MAX = ($MAXHTMLSIZE+30)*1024 if $MAXHTMLSIZE > 0;
my $CGIVer = "CGI $CGI::VERSION";
my $cgi = new CGI;
my ($Jcode, $JcodeVer);
@@ -103,6 +104,42 @@
&EndProc if defined(&EndProc);
}
+# POSTのサイズオーバーなど場合、2.46以前ではCGI.pm内部でdieしていたが、
+# 2.47以降ではdieしなくなったので自前でのエラー処理が必要になった。
+# その代わりに自由なエラーメッセージを返すことが可能になっている。
+# サイズオーバー(413)の場合CGIパラメータ$cgi->paramは何も返さないので、
+# ここの時点でエラー処理する必要があるでしょう。
+my $cgierror = $cgi->cgi_error if $CGI::VERSION >= 2.47;
+if (defined($cgierror)) {
+ if ($cgierror =~ /^413/o) {
+ # 413 Request entity too large
+ # このケースは (Content-Length > $CGI::POST_MAX) の場合に起こり、
+ # ここの時点で標準入力は全く読まれないままになっている。
+ # このままだと、Microsoft-IIS/5.1などでは、サーバがクライアントとの
+ # 接続を切ってしまったり、標準出力を読んでくれずにデッドロックが
+ # 起こったりするので、ここで標準入力をすべて読み捨てる。
+ # 巨大なファイルがPOSTされたときを考えて、一度に全部は読まない。
+ my $contentLength = defined($ENV{'CONTENT_LENGTH'}) ? $ENV{'CONTENT_LENGTH'} : 0;
+ my $bytesToRead = 4*1024;
+ my ($bytesRead, $buffer);
+ while ($contentLength > 0) {
+ $bytesToRead = $contentLength if $contentLength < $bytesToRead;
+ $bytesRead = $cgi->read_from_client(\$buffer, $bytesToRead, 0) or last;
+ $contentLength -= $bytesRead;
+ }
+ # HTTPステータスコードは返さず通常のエラーメッセージを表示する
+ my $msgTooLarge = 'HTML のサイズが受け付け可能上限('.$MAXHTMLSIZE.'KB)を超えています。';
+ &ErrorExit($msgTooLarge);
+ } else {
+ # 400 Bad request (malformed multipart POST)
+ # レアケースなのでHTTPステータスコードを返すだけで済ませる
+ # Content-Typeヘッダは出力する必要がある(rfc3875 6.2.1)
+ print(qq|Status: $cgierror\x0D\x0A|,
+ qq|Content-Type: text/html\x0D\x0A\x0D\x0A|);
+ &Exit;
+ }
+}
+
$URL = $RURL = ($cgi->param('Method') =~ /^(?:Data|File)$/oi)? '': &htmllint::AbsoluteURL($ENV{HTTP_REFERER}, $cgi->param('URL'));
# 日本語文字が含まれている$URLをエラーメッセージの中に表示する場合に備え、
@@ -291,6 +328,7 @@
$FILE = $cgi->param('File');
if ($FILE eq '') { &ErrorExit($msgNoFile); }
$HTML = $cgi->tmpFileName($FILE);
+ my $ctype = $cgi->uploadInfo($FILE)->{'Content-Type'};
close($FILE);
## 送信フォームに「日本語を含むファイル名はチェックできないことがあります」
@@ -309,6 +347,22 @@
# $FILEはファイルハンドル兼用のオブジェクトなのでclose後に変換する
# オブジェクト$FILEを通常の文字列へ変換するために""が必要(演算子多重定義)
&Jconvert(\($FILE="$FILE"), $myCODE, $formCODE);
+
+ # Content-Type チェック。
+ # 本来ならtext/htmlとapplication/xhtml+xmlに限定すべきだろうが、
+ # とりあえず、画像や音声など明らかに無意味なタイプを拒否するのみにした。
+ # text/の全タイプやapplication/octet-streamを許可している理由は、
+ # .xhtmlなどの拡張子に対するMIMEタイプ設定がされていない場合もあること、
+ # 過去のスコアログを見ると.phpや.jspのソースファイルのチェックなどにも
+ # 利用している人がいるようであること、などから。
+ # XHTMLをapplication/xmlやtext/xmlと指定することは禁止されていない。
+ if (defined($ctype) && $ctype ne '' &&
+ ($ctype !~ m#^text/|^application/(xhtml|xml|octet-stream)#oi || # 許可
+ $ctype =~ m#^text/css#oi)) { # 例外
+ &Unlink;
+ &EscapeRef(\$FILE);
+ &ErrorExit($msgInFile.$FILE."$msgNoHTML($ctype
)");
+ }
push @OPT, '-usec';
} else {
# TEXTEREAの内容をテンポラリに書く