diff -urN ../htmllint.orig/htmllint.cgi ./htmllint.cgi
--- ../htmllint.orig/htmllint.cgi Tue Dec 24 03:00:00 2013
+++ ./htmllint.cgi Fri Apr 25 01:30:01 2014
@@ -7,7 +7,7 @@
use strict;
use vars qw($VERSION $PROGNAME);
use vars qw($RULEDIR $LOGSDIR $TMPDIR $IMGDIR $TAGSLIST $HTMLDIR $GATEWAYURL $EXPLAIN $CGIROOT $IMGROOT $HTMLLINTRC $HTMLEXT $INDEXHTML @REJECTREFERER @EXCEPTDOMAINS @PERMITDOMAINS $PERMITPRIVATEIP $NOUSELWP $NOUSEJCODE $MAXHTMLSIZE $TIMEOUT $HTTP_PROXY @HTTP_NOPROXY $GETLOCALFILE $KANJICODE $LYNX $W3M $SCOREFILE $SCORECOUNTER $STATFILE @EXCEPTSCORES $COUNTER $NOCOMMERCIAL $AUTOSCORE);
-use vars qw($HTML $LOCALFILE $URL $RURL @OPT $RESULT $TXTCODE $STYLE $SCRIPT $RULE $FILE $PIPE $WARNS $SCORE $KIND $TAGS $STAT $LANG $outCODE $CHARSET $CTYPE $MIME $TextView $LWPUA $URLGETVer);
+use vars qw($HTML $HTMLSIZE $LOCALFILE $URL $RURL @OPT $RESULT $TXTCODE $STYLE $SCRIPT $RULE $FILE $PIPE $WARNS $SCORE $KIND $TAGS $STAT $LANG $outCODE $CHARSET $CTYPE $MIME $TextView $LWPUA $URLGETVer);
use vars qw(%in $stdio %doctypes $defaultrule %whines $icode $counter $err %warn %whinesStat %seenTagsStat %seenTagsKind %seenMultiBody %statistics %statSeenTags %statKindTags %statMultiBody $statstart $statsample $seensample);
=cut
@@ -47,7 +47,7 @@
# フォームデータのみでも26KB程度あるのでその分の余裕が必要
$CGI::POST_MAX = ($MAXHTMLSIZE+30)*1024 if $MAXHTMLSIZE > 0;
my $CGIVer = "CGI $CGI::VERSION";
-my $cgi = new CGI;
+my $cgi = new CGI(($CGI::VERSION >= 3.03)? sub { $HTMLSIZE = $_[2]; }: undef);
my ($Jcode, $JcodeVer);
if ($Jcode = (!$NOUSEJCODE && eval('require Jcode'))) {
$JcodeVer = "Jcode $Jcode::VERSION";
@@ -153,13 +153,27 @@
# さもないとフォームの文字コードが$myCODEと異なる場合に文字化けが起こる。
&Jconvert(\$URL, $myCODE, $formCODE);
+ # フォームのURL入力欄へ誤ってHTMLそのものをコピペしてしまう人への対処。
+ # これが週に2人ぐらいの割合でいる。これを除外しないと、AbsoluteURLで
+ # 絶対URLに変換されWebサーバへのアクセスが発生してしまう場合もあるので。
+ # <>はURLに使用できない文字なので、URL中に<〜>がある場合にエラーとした。
+ if ($URL =~ /<.*?>/o) {
+ # HTMLソースが全部そのままエラーページで表示されないよう適度に短くする
+ # マルチバイト文字の途中で切ってしまわないよう、ASCII文字の直後で切る
+ # そもそも正しいURLではないのでハイパーリンクにはしない
+ $URL =~ s/^(.{255}.*?[\x20-\x7e]).*$/$1/o; # 256バイト+α
+ &EscapeRef(\$URL);
+ &ErrorExit($msgInURL.$URL.$msgCantGet); # 詳しい説明は不要でしょう
+ }
+
# http:もしくは相対パスの場合のみAbsoluteURLを通す
# AbsoluteURLではホスト名が空になっているURLはうまく扱えないようで、
# file:/// が file:/ に直されてしまってfile:指定が動作しなくなってしまう。
# 他にも、UNCパスを表すfile:指定はやや特殊な構文になっているので、
# URL中の連続する/を一つにまとめられると動作しなくなってしまう。
+ # 除外条件:フォームの初期値(http://)・http:以外の絶対URI・Windowsパス/UNCパス
$URL = &htmllint::AbsoluteURL($ENV{HTTP_REFERER}, $URL)
- if $URL =~ m#^https?:(?!//$)#oi || $URL !~ m#^([\w.+-]*:|\\\\)#oi; # http://のみ、UNCパスも除外
+ if $URL =~ m#^https?:(?!//$)#oi || $URL !~ m#^([\w.+-]*:|\\\\)#oi;
$RURL = $URL;
}
@@ -424,6 +438,7 @@
push @OPT, '-usec';
} else {
# TEXTEREAの内容をテンポラリに書く
+ $HTMLSIZE = length($cgi->param('Data'));
open(HTML, ">$HTML");
print HTML $cgi->param('Data');
close(HTML);
@@ -432,21 +447,28 @@
}
push @OPT, '-stat', $STATFILE if $STATFILE && $cgi->param('Stat');
-if (!(-e $HTML) || (-z $HTML)) {
+if (!(my $existHTML = -e $HTML) || (-z $HTML)) {
# テンポラリファイルがうまくできていない
&Unlink;
+ my $msgErr = '';
if ($URL ne '') {
- my $msgErr = '';
if (defined($LOCALFILE)) {
- $msgErr = '指定されたファイルは'. ((!(-e $HTML))? '存在しません。': '空のファイルです。');
+ $msgErr = $existHTML? '空のファイルです。':
+ 'ファイルが存在しないか、ディレクトリ(フォルダ)の読み取りが許可されていません。';
$STAT = '';
} else {
if (&Jgetcode(\$URL) =~ /^(jis|euc|sjis|utf8)$/) {
$msgErr = 'URLに日本語などのASCII以外の文字を使うことはできません。';
} elsif ($STAT =~ /^\s*2\d\d/) {
- # 非対応UAに対して空のHTMLを返してくるWebサーバもある(www.rakuten.ne.jpなど)
- $msgErr = 'Webサーバから空のファイルが返されました。';
- } elsif ($STAT =~ /^\s*3\d\d/) {
+ if (!$existHTML || $RESULT =~ /^X-Died:/oim) {
+ # LWP内部でコンテントのファイルへのセーブに失敗した場合は、
+ # エラーメッセージが入った X-Died: という疑似ヘッダが付加される。
+ $msgErr = '内部エラーです。一時ファイルを作成できませんでした。';
+ } else {
+ # 非対応UAに対して空のHTMLを返してくるWebサーバもある(www.rakuten.ne.jpなど)
+ $msgErr = 'Webサーバから空のファイルが返されました。';
+ }
+ } elsif ($STAT =~ /^\s*3\d\d/ && $RESULT =~ /^Location:/oim) {
# リダイレクトループが発生した場合など
$msgErr = 'このURLは別のURLへリダイレクトされていますが、リダイレクト先のHTMLを取得できませんでした。';
} elsif ($STAT =~ /^\s*401/) {
@@ -463,8 +485,16 @@
&EscapeRef(\$STAT);
&ErrorExit($msgInHTML.&HrefURL($URL).$msgCantGet.$msgErr.$STAT);
} else {
+ # 実際には内部エラーのケースを分ける必要は無いだろうが、調査のため。
+ if (!$existHTML || $HTMLSIZE > 0) {
+ $msgErr = '内部エラーです。一時ファイルを作成できませんでした。';
+ } elsif ($FILE ne '') {
+ $msgErr = '空のファイルであるか、ファイルが存在しないか、読み取りが許可されていないファイルです。';
+ } else {
+ $msgErr = $msgNoData; # '入力されたデータはありませんでした。'
+ }
&EscapeRef(\$FILE);
- &ErrorExit(($FILE ne '')? $msgInFile.$FILE.$msgCantGet: $msgNoData);
+ &ErrorExit(($FILE ne '')? $msgInFile.$FILE.$msgCantGet.$msgErr: $msgErr);
}
}
@@ -572,6 +602,9 @@
}
&Jprint($RULE.' としてチェックしました。'."
\n", ($TAGS ne '0')?
"$footer
\n": 'タグのひとつもないHTMLは採点できません。'."
\n");
+ if ($RESULT =~ /^Client-Aborted:\s*max_size/oim) { # サイズオーバー時にLWPが付加する疑似ヘッダ
+ &Jprint("
\n".'このHTMLは受け付け可能上限('.$MAXHTMLSIZE.'KB)を超えています。上限を超えた部分はチェックされていません。');
+ }
if (!$Jcode && $cgi->param('CharCode') =~ /^UTF8$/oi) {
&Jprint("
\n".'このサーバではUTF-8は扱えません。');
}