| Tripletail documentation | Contained in the Tripletail distribution. |
Tripletail::InputFilter::HTML - 通常 HTML 向け CGI クエリ読み取り
$TL->setInputFilter('Tripletail::InputFilter::HTML');
$TL->startCgi(
-main => \&main,
);
sub main {
if ($CGI->get('mode') eq 'Foo') {
...
}
}
以下の場所からクエリを読み取る。
$ENV{QUERY_STRING}application/x-www-form-urlencoded を読み取る。
STDINapplication/x-www-form-urlencoded または multipart/form-data を読み取る。 multipartでファイルがアップロードされた場合は、そのファイル名と IO ハンドルが Form に格納される。 詳しくは Tripletail の Ini パラメータを参照。
また、 Tripletail::Session が有効になっている場合は、セッションデータを クッキー から読み出す。
クエリの文字コードはINIのcharsetが指定されていればそれが使用される。 指定されていない場合は自動判別され、文字コード変換には Encode が優先される。 Encode が利用可能でない場合はUnicode::Japaneseが用いられる。
文字コードの自動判別は、フォームの中の CCC キーに含まれる「愛」という文字列によって行われる。 通常、 TL から出力された HTML には、自動的にこの情報が追加されるが、 外部の静的な HTML や FLASH コンテンツ等からフォームデータを渡す場合は、 追加する必要がある。
例えば、 UTF-8 コードで、name キーに「名前」の文字列を渡す場合は、 CCC=%e6%84%9b&name=%E5%90%8D%E5%89%8D をフォームデータとして渡す。
内部メソッド
内部メソッド
Copyright 2006 YMIRLINK Inc.
This framework is free software; you can redistribute it and/or modify it under the same terms as Perl itself
このフレームワークはフリーソフトウェアです。あなたは Perl と同じライセンスの 元で再配布及び変更を行うことが出来ます。
Address bug reports and comments to: tl@tripletail.jp
HP : http://tripletail.jp/
| Tripletail documentation | Contained in the Tripletail distribution. |
# ----------------------------------------------------------------------------- # Tripletail::InputFilter::HTML - é常HTMLåãCGIã¯ã¨ãªèªã¿åã # ----------------------------------------------------------------------------- package Tripletail::InputFilter::HTML; use strict; use warnings; use Tripletail; require Tripletail::InputFilter; our @ISA = qw(Tripletail::InputFilter); my $TEMPFILE_COUNTER = 0; 1; sub _new { my $class = shift; my $this = $class->SUPER::_new(@_); $this; } sub decodeCgi { my $this = shift; my $form = shift; binmode(STDIN); my $newform = $this->_formFromPairs( $this->__pairsFromCgiInput); $form->addForm($newform); if(defined(&Tripletail::Session::_getInstance)) { # å°ãå¤åçã ããããã§å¿ è¦ã«å¿ãã¦ã»ãã·ã§ã³ãã¯ããã¼ããèªã¿åºãã foreach my $group (Tripletail::Session->_getInstanceGroups) { Tripletail::Session->_getInstance($group)->_getSessionDataFromCookies; } } $this; } sub decodeURL { my $this = shift; my $form = shift; my $url = shift; # ãã©ã°ã¡ã³ãã¯é¤å»æ¸ my $fragment = shift; if($url =~ m/\?(.+)$/) { my $newform = $this->_formFromPairs( $this->__pairsFromUrlEncoded($1)); $form->addForm($newform); } $this; } sub __pairsFromCgiInput { # æ»ãå¤: ([[key => value], ...], {key => filename, ...}) # ä½ãkey, valueå ±ã«URLãã³ã¼ãããã¦ããäºãæåã³ã¼ãã¯çã®ã¾ã¾ã # valueã¯ãã¡ã¤ã«ãã³ãã«ã§ããå ´åãæãã my $this = shift; if(!defined($ENV{REQUEST_METHOD})) { return ([], undef); } if(defined($ENV{CONTENT_TYPE}) && $ENV{CONTENT_TYPE} =~ m|multipart/form-data|) { $this->__pairsFromMultipart; } else { ($this->__pairsFromUrlEncoded, {}); } } sub __pairsFromUrlEncoded { my $this = shift; my $input = shift; # optional if(!defined($input)) { if($ENV{REQUEST_METHOD} eq 'POST') { if(!defined($ENV{CONTENT_LENGTH})) { die __PACKAGE__.": Post Error: no Content-Length given by the user agent. (POSTã¡ã½ããã«ããããããContent-Lengthããããããã¾ããã§ãã)"; } my $limit = $TL->parseQuantity( $TL->INI->get(TL => 'maxrequestsize', '8Mi')); if ($ENV{CONTENT_LENGTH} > $limit) { # ãã¡ã¤ã«ã¯ç¡ã $TL->log("Post Error: request size [$ENV{CONTENT_LENGTH}] was too big to accept [limit:$limit]."); die __PACKAGE__.": Post Error: request size was too big to accept. (ãªã¯ã¨ã¹ããµã¤ãºã大ãããã¾ã)"; } my $remaining = $ENV{CONTENT_LENGTH}; my $chunksize = 16 * 1024; $input = ''; while($remaining) { my $size = ($remaining > $chunksize) ? $chunksize : $remaining; my $chunk; my $read = read STDIN, $chunk, $size; if(!defined($read)) { die $TL->newError('error', __PACKAGE__.": we got IO error while reading from stdin. [$!] (stdinããã®èªã¿è¾¼ã¿ä¸ã«IOã¨ã©ã¼ãçºçãã¾ãã)\n"); } elsif($read == 0) { die $TL->newError('error', __PACKAGE__.": we got EOF while reading from stdin.". " We read ".length($input)." bytes actually but $remaining bytes remain. ". " (stdinããã®èªã¿åãéä¸ã§EOFãåä¿¡ãã¾ããã".length($input)."ãã¤ãèªã¿åãã¾ããã${remaining}ãã¤ããæ®ã£ã¦ãã¾ã)\n"); } $input .= $chunk; $remaining -= $read; } } else { if(!defined($ENV{QUERY_STRING})) { return []; } $input = $ENV{QUERY_STRING}; } } if($input eq '') { return []; } my $pairs = []; foreach(split /[&;]/, $input) { my ($key, $value) = split /=/, $_, 2; $key = defined $key ? $this->_urlDecodeString($key) : ''; $value = defined $value ? $this->_urlDecodeString($value) : ''; push @$pairs, [$key => $value]; } $pairs; } sub __pairsFromMultipart { my $this = shift; local($_); if($ENV{REQUEST_METHOD} ne 'POST') { return ([], {}); } if(!defined($ENV{CONTENT_LENGTH})) { return ([], {}); } my $boundary = do { if ($ENV{CONTENT_TYPE} =~ m/boundary="([^"]+)"/i or $ENV{CONTENT_TYPE} =~ m/boundary=(\S+)/i) { '--' . $1; } else { die __PACKAGE__."#__pairsFromMultipart, we found no boundaries ". "in the Content-Type. [$ENV{CONTENT_TYPE}]\n"; } }; if(($ENV{'HTTP_USER_AGENT'} || '') =~ m/MSIE\s+3\.0[12];\s*Mac|DreamPassport/) { # IE3 on Mac ã®ãã°å¯¾å¿ $boundary =~ s/^--//; } my $req_limit = $TL->parseQuantity( $TL->INI->get(TL => 'maxrequestsize', '8Mi')); my $file_limit = $TL->parseQuantity( $TL->INI->get(TL => 'maxfilesize', '8Mi')); my $chunksize = 16 * 1024; if( $req_limit < $chunksize ) { $chunksize = $req_limit; my $boundary = ( length($boundary)+2 )*2; # +2="\r\n"; if( $req_limit < $boundary ) { $chunksize = $boundary; } } my $buffer = ''; my $eof = undef; my $non_file_count = 0; my $file_count = 0; my $pairs = []; my $filename_h = {}; my $current_key = undef; my $current_value = undef; my $find = sub { my $substr = shift; index $buffer, $substr, 0; }; my $rest_len = $ENV{CONTENT_LENGTH}; my $fill = sub { # ä¸åº¦EOFãæ¤åºããå¾ã«åã³fillãããã¨ãããdie if ($eof) { die __PACKAGE__.": we got EOF while reading from stdin. (stdinããã®èªã¿åãéä¸ã§EOFãåä¿¡ãã¾ãã)\n"; } # ãããã¡ã®ãµã¤ãºã maxrequestsize ãè¶ããªãããã«ããã my $size = $chunksize - length($buffer); if ($size == 0) { die __PACKAGE__.": read buffer has been full. (èªã¿è¾¼ã¿ãããã¡ãããµãã¾ãããmaxrequestsizeãå°ãããããããªã¯ã¨ã¹ãã大ãããã¾ã)\n"; } if( $size > $rest_len ) { $size = $rest_len; if ($size <= 0) { die __PACKAGE__.": already read CONTENT_LENGTH bytes ($ENV{CONTENT_LENGTH}). (Content-Lengthãã¤ããèªã¿åãã¾ããããã¼ã¿ãæ®ã£ã¦ãã¾ã)\n"; } } my $chunk; my $read = read STDIN, $chunk, $size; if (not defined $read) { die __PACKAGE__.": we got IO error while reading from stdin. [$!] (stdinããã®èªã¿è¾¼ã¿ä¸ã«IOã¨ã©ã¼ãçºçãã¾ãã)\n"; } elsif ($read == 0) { $eof = 1; } else { $buffer .= $chunk; $rest_len -= length($chunk); } }; my $fill_until = sub { my $str = shift; # ãããã¡ä¸ã«$strãç¾ããã¾ã§fillãç¶ããã while (index($buffer, $str) == -1) { $fill->(); } }; my $remove_until = sub { my $substr = shift; my $pos = index $buffer, $substr, 0; if ($pos == -1) { undef; } else { substr $buffer, 0, $pos, ''; } }; my $remove = sub { my $len = shift; substr $buffer, 0, $len, ''; }; my $next_header_line = sub { # ããããä¸è¡èªãã§è¿ãããããã¯æ¹è¡ããã¦ããå¯è½æ§ããããã # æ¹è¡ã¯ç©ºç½1ã¤ã«ç½®ãæããã while (1) { $fill_until->("\x0d\x0a"); my $pos = index $buffer, "\x0d\x0a"; if ( $pos>0 && $buffer =~ s/^(.{$pos})\x0d\x0a[ \t]+/$1 /s) { next; # ããä¸åº¦ã } last; } $buffer =~ s/^(.*?)\x0d\x0a// or die __PACKAGE__."#__pairsFromMultipart: Internal Error (å é¨ã¨ã©ã¼)\n"; $1; }; my $tempdir = $TL->INI->get(TL => 'tempdir'); if( defined($tempdir) ) { # trust TL.tempdir parameter. $tempdir = $tempdir=~/^(.*)\z/ && $1 or die "untaint"; } my $new_ih = sub { if (defined $tempdir) { if (!-d $tempdir) { require File::Path; File::Path::mkpath($tempdir); } my $filename = "$tempdir/TL-INPUTFILTER-HTML-$$-$TEMPFILE_COUNTER.tmp"; $TEMPFILE_COUNTER++; open my $fh, '+>', $filename or die __PACKAGE__.": failed to open $filename for writing. [$!] (${filename}ã«æ¸ãè¾¼ãã¾ãã)\n"; unlink $filename or die __PACKAGE__.": failed to unlink $filename. [$!] (${filename}ãåé¤ã§ãã¾ãã)\n"; $fh; } else { require IO::Scalar; IO::Scalar->new; } }; my $prepare = sub { my $key = shift; my $filename = shift; if (defined $current_key) { die __PACKAGE__."#__pairsFromMultipart: Internal Error. (å é¨ã¨ã©ã¼)\n"; } $current_key = $key; if (defined $filename) { # ããã¯ãã¡ã¤ã« $filename_h->{$key} = $filename; $current_value = $new_ih->(); } else { # ããã¯ãã¡ã¤ã«ã§ãªã $current_value = ''; } }; my $commit = sub { if (not defined $current_key) { die __PACKAGE__."#__pairsFromMultipart: Internal Error. (å é¨ã¨ã©ã¼)\n"; } if (ref $current_value) { # ãã¡ã¤ã«ã®å é ã«seekãã seek $current_value, 0, 0; } push @$pairs, [$current_key, $current_value]; undef $current_key; undef $current_value; }; my $push = sub { my $data = shift; if (not defined $current_key) { die __PACKAGE__."#__pairsFromMultipart: Internal Error. (å é¨ã¨ã©ã¼)\n"; } if (ref $current_value) { # ãã¡ã¤ã« if (length($data) + $file_count > $file_limit) { die __PACKAGE__.": we are getting too large file which exceeds the limit. (ãã¡ã¤ã«ãµã¤ãºãå¶éãè¶ ãã¾ãããmaxfilesizeã確èªãã¦ãã ãã)\n"; } print $current_value $data; $file_count += length($data); } else { # ãã¡ã¤ã«ä»¥å¤ if (length($data) + $non_file_count > $req_limit) { die __PACKAGE__.": we are getting too large request which exceeds the limit. (ãªã¯ã¨ã¹ããµã¤ãºã大ãããã¾ããmaxrequestsizeã確èªãã¦ãã ãã)\n"; } $current_value .= $data; $non_file_count += length($data); } }; # å°ãªãã¨ã(ãã¦ã³ããªã®é·ã+2)ã®2å-1ãã¤ããèªãã§ããããã¡ãµã¤ # ãº-(ãã¦ã³ããªã®é·ã+2)+1ãã¤ãã ããããã¡ãæ¶è²»ãã¦è¡ããä¾ãã° # ãã¦ã³ããªã --% ã ã£ãå ´åãä¸åº¦ã«èªã¿è¾¼ããã¤ãæ°ã¯å°ãªãã¨ã9 # ãã¤ãã # # |ç¾å¨buf | 次read | # |.........|...**--%.| **ã¯CRLFã5ãã¤ãã ãæ¶è²»ãã # # |.....**--|%........| 5ãã¤ãã ãæ¶è²»ããã®ã§ããããã¡ã«ã¯CRLF以éãæ®ã # # |....**--%|.........| ãã¦ã³ããªãå ¨é¨è¦ãã¦ãã # # |.**--%...|.........| ãã¦ã³ããªãå ¨é¨è¦ãã¦ãã # # ä½ãã®å ´åããã¦ã³ããªã®éä¸ã¾ã§ãåãåã£ã¦ãã¾ãäºãç¡ãã while (1) { if ($find->($boundary) == -1) { $fill->(); } if (defined $remove_until->($boundary)) { # ãã¦ã³ããªæ¤åºã # ç´å¾ã«'--'ããã£ããçµäºãããã§ãªããã°ä¸è¡ãã¤ããããèªãã $remove->(length $boundary); $fill_until->("\x0d\x0a"); if ($find->("--") == 0) { last; } $remove_until->("\x0d\x0a"); # ãã¦ã³ããªã«ä»ããããæ¹è¡ãåé¤ $remove->(2); while (1) { my $line = $next_header_line->(); if (not length $line) { # ããã§ãããçµãã last; } elsif ($line =~ m/^Content-Disposition:/i) { my $key; if ($line =~ m/(?!file)name="(.+?)"/i or $line =~ m/(?!file)name=(\S+)/i) { $key = $1; } else { die __PACKAGE__.": we got a part with no name. (ååããªããã¼ããããã¾ãã)\n"; } if ($line =~ m/filename="(.*?)"/i or $line =~ m/filename=(\S+)/i) { if (not defined $key) { die __PACKAGE__.": we got an isolated filename without name. [$_] (ååããªãã®ã«ãã¡ã¤ã«åãããã¾ãã)\n"; } $prepare->($key, $1); } else { $prepare->($key); } } # ãã以å¤ã®ãããã¯ç¡è¦ã } # ãã¦ã³ããªãè¦ä»ããã¾ã§ push ãç¶ããã while (1) { if ($find->("\x0d\x0a$boundary") == -1) { $fill->(); } if (defined($_ = $remove_until->("\x0d\x0a$boundary"))) { # è¦ä»ãã£ã $push->($_); $commit->(); $remove->(2); # ãã¦ã³ããªç´åã®CRLFã¯ããã§åé¤ # ãã¦ã³ããªèªä½ã¯ããã§ã¯åé¤ããªãã last; } else { my $consume = length($buffer) - (length($boundary) + 2) + 1; if ($consume > 0) { $push->($remove->($consume)); } } } } else { # æããpreambleãããã®ã§ãããä¸åº¦ã«ã¼ãåãã } } ($pairs, $filename_h); } __END__