diff -urN ../htmllint.orig/htmllint.cgi ./htmllint.cgi --- ../htmllint.orig/htmllint.cgi Fri Apr 25 03:16:29 2014 +++ ./htmllint.cgi Sun May 4 00:30:00 2014 @@ -6,8 +6,8 @@ =ignore 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 $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($RULEDIR $LOGSDIR $TMPDIR $IMGDIR $TAGSLIST $HTMLDIR $GATEWAYURL $EXPLAIN $CGIROOT $IMGROOT $HTMLLINTRC $HTMLEXT $INDEXHTML @REJECTREFERER @EXCEPTDOMAINS @PERMITDOMAINS $ACCEPTIRI $PERMITPRIVATEIP $NOUSELWP $NOUSEJCODE $MAXHTMLSIZE $TIMEOUT $HTTP_PROXY @HTTP_NOPROXY $GETLOCALFILE $KANJICODE $LYNX $W3M $SCOREFILE $SCORECOUNTER $STATFILE @EXCEPTSCORES $COUNTER $NOCOMMERCIAL $AUTOSCORE); +use vars qw($HTML $HTMLSIZE $LOCALFILE $URL $RURL $IRI @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 @@ -141,18 +141,29 @@ } if ($cgi->param('Method') =~ /^(?:Data|File)$/oi) { - $RURL = $URL = ''; + $RURL = $IRI = $URL = ''; } else { $URL = $cgi->param('URL'); # AbsoluteURLで前後の空白は除去されるが # 以下のコードではAbsoluteURLを通らない場合があるので $URL =~ s/^\s*//; $URL =~ s/\s*$//; + $IRI = $URL; # 日本語文字が含まれている$URLをエラーメッセージの中に表示する場合に備え、 # $URLの文字コードをスクリプトの文字コード($myCODE)に合わせておく。 # さもないとフォームの文字コードが$myCODEと異なる場合に文字化けが起こる。 &Jconvert(\$URL, $myCODE, $formCODE); + # HTTP::Requestへ渡すために、$URLをperl内部形式utf8テキストへ変換したものを + # $IRIとして別に用意する + if ($ACCEPTIRI && $Jcode && $] >= 5.008) { + &Jconvert(\$IRI, 'utf8', $formCODE); # Jcode.pm必要 + utf8::decode($IRI); # perl内部形式へ変換 (perl v5.8.0 〜) + } else { + $ACCEPTIRI = 0; + $IRI = $URL; + } + # フォームのURL入力欄へ誤ってHTMLそのものをコピペしてしまう人への対処。 # これが週に2人ぐらいの割合でいる。これを除外しないと、AbsoluteURLで # 絶対URLに変換されWebサーバへのアクセスが発生してしまう場合もあるので。 @@ -172,8 +183,10 @@ # 他にも、UNCパスを表すfile:指定はやや特殊な構文になっているので、 # URL中の連続する/を一つにまとめられると動作しなくなってしまう。 # 除外条件:フォームの初期値(http://)・http:以外の絶対URI・Windowsパス/UNCパス - $URL = &htmllint::AbsoluteURL($ENV{HTTP_REFERER}, $URL) - if $URL =~ m#^https?:(?!//$)#oi || $URL !~ m#^([\w.+-]*:|\\\\)#oi; + if ($URL =~ m#^https?:(?!//$)#oi || $URL !~ m#^([\w.+-]*:|\\\\)#oi) { + $URL = &htmllint::AbsoluteURL($ENV{HTTP_REFERER}, $URL); + $IRI = &htmllint::AbsoluteURL($ENV{HTTP_REFERER}, $IRI); + } $RURL = $URL; } @@ -259,12 +272,21 @@ unless ($scheme =~ /^http/i) { &ErrorExit($msgInURL.&HrefURL($URL).$msgCantGet); } - if (&Jgetcode(\$host) =~ /^(jis|euc|sjis|utf8)$/) { + # IRIへの対応は、LWPが内部で利用しているURIモジュールの働きによる(IRI対応はURI-1.50から) + # ASCII以外の文字が含まれる文字列をURLとして与えれば、自動的にIRIとして認識される + # 日本語文字を正しく認識させるには、utf8フラグがセットされたUTF-8文字列を与えればよい + my $USELWP = (!$NOUSELWP && + eval('require LWP::UserAgent') && eval('require HTTP::Request')); + if ($ACCEPTIRI && !($USELWP && $LWP::VERSION >= 5.40 && $URI::VERSION >= 1.50)) { + $ACCEPTIRI = 0; + $IRI = $URL; + } + if (!$ACCEPTIRI && &Jgetcode(\$host) =~ /^(jis|euc|sjis|utf8)$/) { # 対応UAが普及したことで国際化ドメイン名の使用も徐々に増加している。 # ASCII以外の文字を使用できるWebアドレスはIRI(RFC3987)という別規格であって、 # 厳密に言うとURLにASCII以外の文字を使用できないことに変わりはない。 # html5やxhtml1.1では文書中にIRIを使用できる。 - my $noIDN = 'Another HTML-lint では国際化ドメイン名に対応していません。'. + my $noIDN = 'このサーバでは国際化ドメイン名は扱えません。'. 'ドメイン名をPunycodeエンコードされた形式で指定してください。'; &ErrorExit($msgInURL.&HrefURL($URL).$msgCantGet.$noIDN); } @@ -319,8 +341,7 @@ } } # HTMLを読み込んで改行を変換してテンポラリに書く - if (!$NOUSELWP && - eval('require LWP::UserAgent') && eval('require HTTP::Request')) { + if ($USELWP) { $URLGETVer = "LWP $LWP::VERSION"; $LWPUA = new LWP::UserAgent; # $LWPUA->agent の既定値は libwww-perl/$LWP::VERSION だが、 @@ -334,10 +355,11 @@ $LWPUA->proxy('http', "http://$HTTP_PROXY/") if $HTTP_PROXY; $LWPUA->no_proxy(@HTTP_NOPROXY) if @HTTP_NOPROXY; $LWPUA->parse_head(0); - my $req = new HTTP::Request GET => $URL; + my $req = new HTTP::Request GET => $IRI; # $req->header('Accept' => 'text/html, application/xhtml+xml, */*;q=0.1'); $req->header('Accept' => 'text/html, application/xhtml+xml'); # 20090427 - if ($host =~ m#^//(.+)#o) { $req->header('Host' => $1); } + #'Host'は HTTP::Request の内部で自動的に設定される(そもそも必須ヘッダですから) + #if ($host =~ m#^//(.+)#o) { $req->header('Host' => $1); } my $res = $LWPUA->request($req, $HTML); $RESULT = $res->status_line()."\n".$res->headers_as_string(); ($STAT = "\n".$res->status_line()) =~ s/\s*\(\@INC contains:.+//o; @@ -461,8 +483,9 @@ 'ファイルが存在しないか、ディレクトリ(フォルダ)の読み取りが許可されていません。'; $STAT = ''; } else { - if (&Jgetcode(\$URL) =~ /^(jis|euc|sjis|utf8)$/) { - $msgErr = 'URLに日本語などのASCII以外の文字を使うことはできません。'; + if (!$ACCEPTIRI && &Jgetcode(\$URL) =~ /^(jis|euc|sjis|utf8)$/) { + $msgErr = 'このサーバでは国際化URL(IRI)は扱えません。'. + '通常のURLに日本語などのASCII以外の文字を使うことはできません。'; } elsif ($STAT =~ /^\s*2\d\d/) { if (!$existHTML || $RESULT =~ /^X-Died:/oim) { # LWP内部でコンテントのファイルへのセーブに失敗した場合は、 diff -urN ../htmllint.orig/htmllintenv ./htmllintenv --- ../htmllint.orig/htmllintenv Tue Oct 16 08:20:00 2012 +++ ./htmllintenv Sun May 4 00:30:00 2014 @@ -50,6 +50,10 @@ # プライヴェートIPを許す (禁止するときコメントアウト) #$PERMITPRIVATEIP = 1; +# URL入力欄でIRI (国際化URL) を認識させる +# LWP および Jcode.pm の使用必須、加えてURI-1.50以降・perl v5.8.0以降が必要です +$ACCEPTIRI = 1; + # LWP や Jcode.pm の使用を制限する (制限したいときコメントを外す) #$NOUSELWP = 1; #$NOUSEJCODE = 1;