X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=blobdiff_plain;f=lib%2FCatalyst.pm;h=9e7d156e3db9680f18c3bc2727c7341598efe226;hp=7009a53dce75da0bae1574596385a48b2d3299a7;hb=11d52bbdb4fccbe1678d869494acb9d43ae83c99;hpb=cfdd890d1f76bd9403c5b8a30f902394297ffb68 diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 7009a53..9e7d156 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -23,6 +23,7 @@ use Path::Class::File (); use URI (); use URI::http; use URI::https; +use HTML::Entities; use Tree::Simple qw/use_weak_refs/; use Tree::Simple::Visitor::FindByUID; use Class::C3::Adopt::NEXT; @@ -33,9 +34,11 @@ use Catalyst::EngineLoader; use utf8; use Carp qw/croak carp shortmess/; use Try::Tiny; +use Safe::Isa; use Plack::Middleware::Conditional; use Plack::Middleware::ReverseProxy; use Plack::Middleware::IIS6ScriptNameFix; +use Plack::Middleware::IIS7KeepAliveFix; use Plack::Middleware::LighttpdScriptNameFix; BEGIN { require 5.008003; } @@ -50,20 +53,30 @@ has request => ( is => 'rw', default => sub { my $self = shift; - my %p = ( _log => $self->log ); - $p{_uploadtmp} = $self->_uploadtmp if $self->_has_uploadtmp; - $self->request_class->new(\%p); + $self->request_class->new($self->_build_request_constructor_args); }, lazy => 1, ); +sub _build_request_constructor_args { + my $self = shift; + my %p = ( _log => $self->log ); + $p{_uploadtmp} = $self->_uploadtmp if $self->_has_uploadtmp; + \%p; +} + has response => ( is => 'rw', default => sub { my $self = shift; - $self->response_class->new({ _log => $self->log }); + $self->response_class->new($self->_build_response_constructor_args); }, lazy => 1, ); +sub _build_response_constructor_args { + my $self = shift; + { _log => $self->log }; +} + has namespace => (is => 'rw'); sub depth { scalar @{ shift->stack || [] }; } @@ -100,7 +113,7 @@ __PACKAGE__->stats_class('Catalyst::Stats'); # Remember to update this in Catalyst::Runtime as well! -our $VERSION = '5.90015'; +our $VERSION = '5.90042'; sub import { my ( $class, @arguments ) = @_; @@ -135,6 +148,8 @@ sub import { sub _application { $_[0] } +=encoding UTF-8 + =head1 NAME Catalyst - The Elegant MVC Web Application Framework @@ -252,9 +267,9 @@ MYAPP_WEB_HOME. If both variables are set, the MYAPP_HOME one will be used. If none of these are set, Catalyst will attempt to automatically detect the home directory. If you are working in a development environment, Catalyst -will try and find the directory containing either Makefile.PL, Build.PL or -dist.ini. If the application has been installed into the system (i.e. -you have done C), then Catalyst will use the path to your +will try and find the directory containing either Makefile.PL, Build.PL, +dist.ini, or cpanfile. If the application has been installed into the system +(i.e. you have done C), then Catalyst will use the path to your application module, without the .pm extension (e.g., /foo/MyApp if your application was installed at /foo/MyApp.pm) @@ -544,13 +559,13 @@ sub _comp_names_search_prefixes { # undef for a name will return all return keys %eligible if !defined $name; - my $query = ref $name ? $name : qr/^$name$/i; + my $query = $name->$_isa('Regexp') ? $name : qr/^$name$/i; my @result = grep { $eligible{$_} =~ m{$query} } keys %eligible; return @result if @result; # if we were given a regexp to search against, we're done. - return if ref $name; + return if $name->$_isa('Regexp'); # skip regexp fallback if configured return @@ -641,7 +656,7 @@ sub controller { my $appclass = ref($c) || $c; if( $name ) { - unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps + unless ( $name->$_isa('Regexp') ) { # Direct component hash lookup to avoid costly regexps my $comps = $c->components; my $check = $appclass."::Controller::".$name; return $c->_filter_component( $comps->{$check}, @args ) if exists $comps->{$check}; @@ -679,7 +694,7 @@ sub model { my ( $c, $name, @args ) = @_; my $appclass = ref($c) || $c; if( $name ) { - unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps + unless ( $name->$_isa('Regexp') ) { # Direct component hash lookup to avoid costly regexps my $comps = $c->components; my $check = $appclass."::Model::".$name; return $c->_filter_component( $comps->{$check}, @args ) if exists $comps->{$check}; @@ -738,7 +753,7 @@ sub view { my $appclass = ref($c) || $c; if( $name ) { - unless ( ref($name) ) { # Direct component hash lookup to avoid costly regexps + unless ( $name->$_isa('Regexp') ) { # Direct component hash lookup to avoid costly regexps my $comps = $c->components; my $check = $appclass."::View::".$name; if( exists $comps->{$check} ) { @@ -1266,7 +1281,7 @@ path, use C<< $c->uri_for_action >> instead. sub uri_for { my ( $c, $path, @args ) = @_; - if (blessed($path) && $path->isa('Catalyst::Controller')) { + if ( $path->$_isa('Catalyst::Controller') ) { $path = $path->path_prefix; $path =~ s{/+\z}{}; $path .= '/'; @@ -1283,7 +1298,7 @@ sub uri_for { $arg =~ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go; } - if ( blessed($path) ) { # action object + if ( $path->$_isa('Catalyst::Action') ) { # action object s|/|%2F|g for @args; my $captures = [ map { s|/|%2F|g; $_; } ( scalar @args && ref $args[0] eq 'ARRAY' @@ -1327,9 +1342,13 @@ sub uri_for { my $args = join('/', grep { defined($_) } @args); $args =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE $args =~ s!^/+!!; - my $base = $c->req->base; - my $class = ref($base); - $base =~ s{(?req->base; + $class = ref($base); + $base =~ s{(?log->error($error); } + # Support skipping finalize for psgix.io style 'jailbreak'. Used to support + # stuff like cometd and websockets + + if($c->request->has_io_fh) { + $c->log_response; + return; + } + # Allow engine to handle finalize flow (for POE) my $engine = $c->engine; if ( my $code = $engine->can('finalize') ) { @@ -1801,7 +1828,7 @@ sub finalize { $c->log_response; if ($c->use_stats) { - my $elapsed = sprintf '%f', $c->stats->elapsed; + my $elapsed = $c->stats->elapsed; my $av = $elapsed == 0 ? '??' : sprintf '%.3f', 1 / $elapsed; $c->log->info( "Request took ${elapsed}s ($av/s)\n" . $c->stats->report . "\n" ); @@ -1855,6 +1882,7 @@ sub finalize_headers { if ( !$response->has_body ) { # Add a default body if none is already present + my $encoded_location = encode_entities($location); $response->body(<<"EOF"); @@ -1862,7 +1890,7 @@ sub finalize_headers { Moved -

This item has moved here.

+

This item has moved here.

EOF @@ -2793,6 +2821,16 @@ sub apply_default_middlewares { # IIS versions $psgi_app = Plack::Middleware::IIS6ScriptNameFix->wrap($psgi_app); + # And another IIS issue, this time with IIS7. + $psgi_app = Plack::Middleware::Conditional->wrap( + $psgi_app, + builder => sub { Plack::Middleware::IIS7KeepAliveFix->wrap($_[0]) }, + condition => sub { + my ($env) = @_; + return $env->{SERVER_SOFTWARE} && $env->{SERVER_SOFTWARE} =~ m!IIS/7\.[0-9]!; + }, + ); + return $psgi_app; } @@ -2944,10 +2982,26 @@ the plugin name does not begin with C. return $class; } + sub _default_plugins { return qw(Unicode::Encoding) } + sub setup_plugins { my ( $class, $plugins ) = @_; $class->_plugins( {} ) unless $class->_plugins; + $plugins = [ grep { + m/Unicode::Encoding/ ? do { + $class->log->warn( + 'Unicode::Encoding plugin is auto-applied,' + . ' please remove this from your appclass' + . ' and make sure to define "encoding" config' + ); + unless (exists $class->config->{'encoding'}) { + $class->config->{'encoding'} = 'UTF-8'; + } + () } + : $_ + } @$plugins ]; + push @$plugins, $class->_default_plugins; $plugins = Data::OptList::mkopt($plugins || []); my @plugins = map { @@ -3139,12 +3193,33 @@ is having paths rewritten into it (e.g. as a .cgi/fcgi in a public_html director at other URIs than that which the app is 'normally' based at with C), the resolution of C<< $c->request->base >> will be incorrect. -=back +=back =item * C - See L. +=item * + +C - See L + +=item * + +C + +When there is an error in an action chain, the default behavior is to continue +processing the remaining actions and then catch the error upon chain end. This +can lead to running actions when the application is in an unexpected state. If +you have this issue, setting this config value to true will promptly exit a +chain when there is an error raised in any action (thus terminating the chain +early.) + +use like: + + __PACKAGE__->config(abort_chain_on_error_fix => 1); + +In the future this might become the default behavior. + =back =head1 INTERNAL ACTIONS @@ -3236,6 +3311,53 @@ If you plan to operate in a threaded environment, remember that all other modules you are using must also be thread-safe. Some modules, most notably L, are not thread-safe. +=head1 ENCODING + +On request, decodes all params from encoding into a sequence of +logical characters. On response, encodes body into encoding. + +=head2 Methods + +=over 4 + +=item encoding + +Returns an instance of an C encoding + + print $c->encoding->name + +=item handle_unicode_encoding_exception ($exception_context) + +Method called when decoding process for a request fails. + +An C<$exception_context> hashref is provided to allow you to override the +behaviour of your application when given data with incorrect encodings. + +The default method throws exceptions in the case of invalid request parameters +(resulting in a 500 error), but ignores errors in upload filenames. + +The keys passed in the C<$exception_context> hash are: + +=over + +=item param_value + +The value which was not able to be decoded. + +=item error_msg + +The exception received from L. + +=item encoding_step + +What type of data was being decoded. Valid values are (currently) +C - for request parameters / arguments / captures +and C - for request upload filenames. + +=back + +=back + =head1 SUPPORT IRC: @@ -3363,6 +3485,8 @@ marcus: Marcus Ramberg miyagawa: Tatsuhiko Miyagawa +mgrimes: Mark Grimes + mst: Matt S. Trout mugwump: Sam Vilain @@ -3407,7 +3531,7 @@ Will Hawes C willert: Sebastian Willert -wreis: Wallace Reis +wreis: Wallace Reis Yuval Kogman, C