📄 compat.pm
字号:
sub register_cleanup { shift->pool->cleanup_register(@_);}*post_connection = \®ister_cleanup;sub get_remote_host { my ($r, $type) = @_; $type = Apache2::Const::REMOTE_NAME unless defined $type; $r->connection->get_remote_host($type, $r->per_dir_config);}sub parse_args { my ($r, $string) = @_; return () unless defined $string and $string; return map { tr/+/ /; s/%([0-9a-fA-F]{2})/pack("C",hex($1))/ge; $_; } split /[=&;]/, $string, -1;}use Apache2::Const -compile => qw(MODE_READBYTES);use APR::Const -compile => qw(SUCCESS BLOCK_READ);use constant IOBUFSIZE => 8192;sub content { my $r = shift; my $bb = APR::Brigade->new($r->pool, $r->connection->bucket_alloc); my $data = ''; my $seen_eos = 0; do { $r->input_filters->get_brigade($bb, Apache2::Const::MODE_READBYTES, APR::Const::BLOCK_READ, IOBUFSIZE); while (!$bb->is_empty) { my $b = $bb->first; if ($b->is_eos) { $seen_eos++; last; } if ($b->read(my $buf)) { $data .= $buf; } $b->delete; } } while (!$seen_eos); $bb->destroy; return $data unless wantarray; return $r->parse_args($data);}sub server_root_relative { my $r = shift; File::Spec->catfile(Apache2::ServerUtil::server_root, @_);}sub clear_rgy_endav { my ($r, $script_name) = @_; require ModPerl::Global; my $package = 'Apache2::ROOT' . $script_name; ModPerl::Global::special_list_clear(END => $package);}sub stash_rgy_endav { #see run_rgy_endav}#if somebody really wants to have END subroutine support#with the 1.x Apache2::Registry they will need to configure:# PerlHandler Apache2::Registry Apache2::compat::run_rgy_endavsub Apache2::compat::run_rgy_endav { my $r = shift; require ModPerl::Global; require Apache2::PerlRun; #1.x's my $package = Apache2::PerlRun->new($r)->namespace; ModPerl::Global::special_list_call(END => $package);}sub seqno { 1;}sub chdir_file { #XXX resolve '.' in @INC to basename $r->filename}#XXX: would like to have a proper implementation#that reads line-by-line as defined by $/#the best way will probably be to use perlio in 5.8.0#anything else would be more effort than it is worthsub READLINE { my $r = shift; my $line; $r->read($line, $r->headers_in->get('Content-length')); $line ? $line : undef;}#XXX: howto convert PerlIO to apr_file_t#so we can use the real ap_send_fd function#2.0 ap_send_fd() also has an additional offset parametersub send_fd_length { my ($r, $fh, $length) = @_; my $buff; my $total_bytes_sent = 0; my $len; return 0 if $length == 0; if (($length > 0) && ($total_bytes_sent + IOBUFSIZE) > $length) { $len = $length - $total_bytes_sent; } else { $len = IOBUFSIZE; } binmode $fh; while (CORE::read($fh, $buff, $len)) { $total_bytes_sent += $r->puts($buff); } $total_bytes_sent;}sub send_fd { my ($r, $fh) = @_; $r->send_fd_length($fh, -1);}sub is_main { !shift->main }# really old back-compat methods, they shouldn't be used in mp1*cgi_var = *cgi_env = \&Apache2::RequestRec::subprocess_env;package Apache::File;use Fcntl ();use Symbol ();use Carp ();sub new { my ($class) = shift; my $fh = Symbol::gensym; my $self = bless $fh, ref($class)||$class; if (@_) { return $self->open(@_) ? $self : undef; } else { return $self; }}sub open { my ($self) = shift; Carp::croak("no Apache2::File object passed") unless $self && ref($self); # cannot forward @_ to open() because of its prototype if (@_ > 1) { my ($mode, $file) = @_; CORE::open $self, $mode, $file; } else { my $file = shift; CORE::open $self, $file; }}sub close { my ($self) = shift; CORE::close $self;}my $TMPNAM = 'aaaaaa';my $TMPDIR = $ENV{'TMPDIR'} || $ENV{'TEMP'} || '/tmp';($TMPDIR) = $TMPDIR =~ /^([^<>|;*]+)$/; #untaintmy $Mode = Fcntl::O_RDWR()|Fcntl::O_EXCL()|Fcntl::O_CREAT();my $Perms = 0600;sub tmpfile { my $class = shift; my $limit = 100; my $r = Apache2::compat::request('Apache::File->tmpfile'); while ($limit--) { my $tmpfile = "$TMPDIR/${$}" . $TMPNAM++; my $fh = $class->new; sysopen $fh, $tmpfile, $Mode, $Perms or die "failed to open $tmpfile: $!"; $r->pool->cleanup_register(sub { unlink $tmpfile }); if ($fh) { return wantarray ? ($tmpfile, $fh) : $fh; } }}# the following functions now live in Apache2::RequestIO# * discard_request_body# the following functions now live in Apache2::Response# * meets_conditions# * set_content_length# * set_etag# * set_last_modified# * update_mtime# the following functions now live in Apache2::RequestRec# * mtimepackage Apache::Util;sub size_string { my ($size) = @_; if (!$size) { $size = " 0k"; } elsif ($size == -1) { $size = " -"; } elsif ($size < 1024) { $size = " 1k"; } elsif ($size < 1048576) { $size = sprintf "%4dk", ($size + 512) / 1024; } elsif ($size < 103809024) { $size = sprintf "%4.1fM", $size / 1048576.0; } else { $size = sprintf "%4dM", ($size + 524288) / 1048576; } return $size;}*unescape_uri = \&Apache2::URI::unescape_url;*escape_path = \&Apache2::Util::escape_path;sub escape_uri { my $path = shift; my $r = Apache2::compat::request('Apache2::Util::escape_uri'); Apache2::Util::escape_path($path, $r->pool);}#tmp compat until ap_escape_html is reworked to not require a poolmy %html_escapes = ( '<' => 'lt', '>' => 'gt', '&' => 'amp', '"' => 'quot',);%html_escapes = map { $_, "&$html_escapes{$_};" } keys %html_escapes;my $html_escape = join '|', keys %html_escapes;sub escape_html { my $html = shift; $html =~ s/($html_escape)/$html_escapes{$1}/go; $html;}*parsedate = \&APR::Date::parse_http;*validate_password = \&APR::Util::password_validate;sub Apache2::URI::parse { my ($class, $r, $uri) = @_; $uri ||= $r->construct_url; APR::URI->parse($r->pool, $uri);}package Apache::Table;sub new { my ($class, $r, $nelts) = @_; $nelts ||= 10; APR::Table::make($r->pool, $nelts);}package Apache::SIG;use Apache2::Const -compile => 'DECLINED';sub handler { # don't set the SIGPIPE return Apache2::Const::DECLINED;}package Apache2::Connection;# auth_type and user records don't exist in 2.0 conn_rec struct# 'PerlOptions +GlobalRequest' is requiredsub auth_type { shift; Apache2::RequestUtil->request->ap_auth_type(@_) }sub user { shift; Apache2::RequestUtil->request->user(@_) }1;__END__=head1 NAMEApache2::compat -- 1.0 backward compatibility functions deprecated in 2.0=head1 Synopsis # either add at the very beginning of startup.pl use Apache2::compat; # or httpd.conf PerlModule Apache2::compat # override and restore compat functions colliding with mp2 API Apache2::compat::override_mp2_api('Apache2::Connection::local_addr'); my ($local_port, $local_addr) = sockaddr_in($c->local_addr); Apache2::compat::restore_mp2_api('Apache2::Connection::local_addr');=head1 DescriptionC<Apache2::compat> provides mod_perl 1.0 compatibility layer and can beused to smooth the transition process to mod_perl 2.0.It includes functions that have changed their API or were removed inmod_perl 2.0. If your code uses any of those functions, you shouldload this module at the server startup, and everything should work asit did in 1.0. If it doesn't please L<report thebug|docs::2.0::user::help::help/Reporting_Problems>, but before youdo that please make sure that your code does work properly undermod_perl 1.0.However, remember, that it's implemented in pure Perl and not C,therefore its functionality is not optimized and it's the best to tryto L<port yourcode|docs::2.0::user::porting::porting> not to use deprecatedfunctions and stop using the compatibility layer.=head1 Compatibility Functions Colliding with mod_perl 2.0 APIMost of the functions provided by Apache2::compat don't interfere withmod_perl 2.0 API. However there are several functions which have thesame name in the mod_perl 1.0 and mod_perl 2.0 API, accept the samenumber of arguments, but either the arguments themselves aren't thesame or the return values are different. For example the mod_perl 1.0code: require Socket; my $sockaddr_in = $c->local_addr; my ($local_port, $local_addr) = Socket::sockaddr_in($sockaddr_in);should be adjusted to be: require Apache2::Connection; require APR::SockAddr; my $sockaddr = $c->local_addr; my ($local_port, $local_addr) = ($sockaddr->port, $sockaddr->ip_get);to work under mod_perl 2.0.As you can see in mod_perl 1.0 API local_addr() was returning aSOCKADDR_IN object (see the Socket perl manpage), in mod_perl 2.0 APIit returns an C<L<APR::SockAddr|docs::2.0::api::APR::SockAddr>>object, which is a totally different beast. If Apache2::compatoverrides the function C<local_addr()> to be back-compatible withmod_perl 1.0 API. Any code that relies on this function to work as itshould under mod_perl 2.0 will be broken. Therefore the solution isnot to override C<local_addr()> by default. Instead a special API isprovided which overrides colliding functions only when needed andwhich can be restored when no longer needed. So for example if youhave code from mod_perl 1.0: my ($local_port, $local_addr) = Socket::sockaddr_in($c->local_addr);and you aren't ready to port it to to use the mp2 API: my ($local_port, $local_addr) = ($c->local_addr->port, $c->local_addr->ip_get);you could do the following: Apache2::compat::override_mp2_api('Apache2::Connection::local_addr'); my ($local_port, $local_addr) = Socket::sockaddr_in($c->local_addr); Apache2::compat::restore_mp2_api('Apache2::Connection::local_addr');Notice that you need to restore the API as soon as possible.Both C<override_mp2_api()> and C<restore_mp2_api()> accept a list offunctions to operate on.=head2 Available Overridable FunctionsAt the moment the following colliding functions are available foroverriding:=over=item * C<Apache2::RequestRec::notes>=item * C<Apache2::RequestRec::filename>=item * C<Apache2::RequestRec::finfo>=item * C<Apache2::Connection::local_addr>=item * C<Apache2::Connection::remote_addr>=item * C<Apache2::Util::ht_time>=item * C<APR::URI::unparse>=back=head1 Use in CPAN ModulesThe short answer: B<Do not use> C<Apache2::compat> in CPAN modules.The long answer:C<Apache2::compat> is useful during the mod_perl 1.0 codeporting. Though remember that it's implemented in pure Perl. Incertain cases it overrides mod_perl 2.0 methods, because their API isvery different and doesn't map 1:1 to mod_perl 1.0. So if anything,not under user's control, loads C<Apache2::compat> user's code isforced to use the potentially slower method. Which is quite bad.Some users may choose to keep using C<Apache2::compat> in productionand it may perform just fine. Other users will choose not to use thatmodule, by porting their code to use mod_perl 2.0 API. However itshould be users' choice whether to load this module or not and not tobe enforced by CPAN modules.If you port your CPAN modules to work with mod_perl 2.0, you shouldfollow the porting L<Perl|docs::2.0::user::porting::porting> andL<XS|docs::2.0::devel::porting::porting> module guidelines.Users that are stuck with CPAN modules preloading C<Apache2::compat>,can prevent this from happening by adding $INC{'Apache2/compat.pm'} = __FILE__;at the very beginning of their I<startup.pl>. But this will mostcertainly break the module that needed this module.=head1 APIYou should be reading the mod_perl 1.0 L<APIdocs|docs::1.0::api::index> for usage of the methods and functionsin this package, since what this module is doing is providing abackwards compatibility and it makes no sense to duplicatedocumentation.Another important document to read is: L<Migrating from mod_perl 1.0to mod_perl 2.0|docs::2.0::user::porting::compat> which covers allmod_perl 1.0 constants, functions and methods that have changed inmod_perl 2.0.=head1 See AlsoL<mod_perl 2.0 documentation|docs::2.0::index>.=head1 Copyrightmod_perl 2.0 and its core modules are copyrighted underThe Apache Software License, Version 2.0.=head1 AuthorsL<The mod_perl development team and numerouscontributors|about::contributors::people>.=cut
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -