X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=blobdiff_plain;f=lib%2FCatalyst.pm;h=0d8a817cc91d6053899a046da5c9e9e4a3a93f10;hp=582ebb3a453846270d96b737b64a7e67f94a0778;hb=772bd9deac85d462d77bfe2cbbe73f3de1688ebf;hpb=6dcc530761473f574ccde956e3a321b1dfb3d27e diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 582ebb3..0d8a817 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -120,7 +120,7 @@ __PACKAGE__->mk_classdata($_) for qw/components arguments dispatcher engine log dispatcher_class engine_loader context_class request_class response_class stats_class setup_finished _psgi_app loading_psgi_file run_options _psgi_middleware - _data_handlers _encoding _encode_check/; + _data_handlers _encoding _encode_check finalized_default_middleware/; __PACKAGE__->dispatcher_class('Catalyst::Dispatcher'); __PACKAGE__->request_class('Catalyst::Request'); @@ -129,7 +129,7 @@ __PACKAGE__->stats_class('Catalyst::Stats'); __PACKAGE__->_encode_check(Encode::FB_CROAK | Encode::LEAVE_SRC); # Remember to update this in Catalyst::Runtime as well! -our $VERSION = '5.90079_005'; +our $VERSION = '5.90089_001'; $VERSION = eval $VERSION if $VERSION =~ /_/; # numify for warning-free dev releases sub import { @@ -592,7 +592,7 @@ sub last_error { my ($err, @errs) = @{shift->error}; return $err } =head2 shift_errors shifts the most recently added error off the error stack and returns if. Returns -nothing if there are nomore errors. +nothing if there are no more errors. =cut @@ -1049,7 +1049,11 @@ Clears the encoding for the current context =head2 encoding -Sets or gets the application encoding. +Sets or gets the application encoding. Setting encoding takes either an +Encoding object or a string that we try to resolve via L. + +You would expect to get the encoding object back if you attempt to set it. If +there is a failure you will get undef returned and an error message in the log. =cut @@ -1060,7 +1064,7 @@ sub clear_encoding { if(blessed $c) { $c->encoding(undef); } else { - $c->debug->error("You can't clear encoding on the application"); + $c->log->error("You can't clear encoding on the application"); } } @@ -1069,6 +1073,13 @@ sub encoding { my $encoding; if ( scalar @_ ) { + + # Don't let one change this once we are too far into the response + if(blessed $c && $c->res->finalized_headers) { + Carp::croak("You may not change the encoding once the headers are finalized"); + return; + } + # Let it be set to undef if (my $wanted = shift) { $encoding = Encode::find_encoding($wanted) @@ -1184,6 +1195,17 @@ Catalyst> line. B You B wrap this method with method modifiers or bad things will happen - wrap the C method instead. +B You can create a custom setup stage that will execute when the +application is starting. Use this to customize setup. + + MyApp->setup(-Custom=value); + + sub setup_custom { + my ($class, $value) = @_; + } + +Can be handy if you want to hook into the setup phase. + =cut sub setup { @@ -2094,7 +2116,7 @@ sub finalize_headers { =head2 $c->finalize_encoding Make sure your body is encoded properly IF you set an encoding. By -default the encoding is UTF-8 but you can disable it by explictly setting the +default the encoding is UTF-8 but you can disable it by explicitly setting the encoding configuration value to undef. We can only encode when the body is a scalar. Methods for encoding via the @@ -3006,15 +3028,30 @@ EOW Adds the following L middlewares to your application, since they are useful and commonly needed: -L, (conditionally added based on the status -of your $ENV{REMOTE_ADDR}, and can be forced on with C -or forced off with C), L -(if you are using Lighttpd), L (always -applied since this middleware is smart enough to conditionally apply itself). +L (if you are using Lighttpd), +L (always applied since this middleware +is smart enough to conditionally apply itself). + +We will also automatically add L if we notice +that your HTTP $env variable C is '127.0.0.1'. This is usually +an indication that your server is running behind a proxy frontend. However in +2014 this is often not the case. We preserve this code for backwards compatibility +however I B recommend that if you are running the server behind a front +end proxy that you clearly indicate so with the C configuration +setting to true for your environment configurations that run behind a proxy. This +way if you change your front end proxy address someday your code would inexplicably +stop working as expected. Additionally if we detect we are using Nginx, we add a bit of custom middleware to solve some problems with the way that server handles $ENV{PATH_INFO} and -$ENV{SCRIPT_NAME} +$ENV{SCRIPT_NAME}. + +Please B that if you do use C the middleware is now +adding via C rather than this method. + +If you are using Lighttpd or IIS6 you may wish to apply these middlewares. In +general this is no longer a common case but we have this here for backward +compatibility. =cut @@ -3022,16 +3059,21 @@ $ENV{SCRIPT_NAME} sub apply_default_middlewares { my ($app, $psgi_app) = @_; - $psgi_app = Plack::Middleware::Conditional->wrap( - $psgi_app, - builder => sub { Plack::Middleware::ReverseProxy->wrap($_[0]) }, - condition => sub { - my ($env) = @_; - return if $app->config->{ignore_frontend_proxy}; - return $env->{REMOTE_ADDR} eq '127.0.0.1' - || $app->config->{using_frontend_proxy}; - }, - ); + # Don't add this conditional IF we are explicitly saying we want the + # frontend proxy support. We don't need it here since if that is the + # case it will be always loaded in the default_middleware. + + unless($app->config->{using_frontend_proxy}) { + $psgi_app = Plack::Middleware::Conditional->wrap( + $psgi_app, + builder => sub { Plack::Middleware::ReverseProxy->wrap($_[0]) }, + condition => sub { + my ($env) = @_; + return if $app->config->{ignore_frontend_proxy}; + return $env->{REMOTE_ADDR} eq '127.0.0.1'; + }, + ); + } # If we're running under Lighttpd, swap PATH_INFO and SCRIPT_NAME # http://lists.scsys.co.uk/pipermail/catalyst/2006-June/008361.html @@ -3069,11 +3111,24 @@ sub apply_default_middlewares { =head2 App->to_app Returns a PSGI application code reference for the catalyst application -C<$c>. This is the bare application without any middlewares -applied. C<${myapp}.psgi> is not taken into account. +C<$c>. This is the bare application created without the C +method called. We do however apply C since those are +integral to how L functions. Also, unlike starting your application +with a generated server script (via L and C) we do +not attempt to return a valid L application using any existing C<${myapp}.psgi> +scripts in your $HOME directory. + +B C was originally created when the first PSGI +port was done for v5.90000. These are middlewares that are added to achieve +backward compatibility with older applications. If you start your application +using one of the supplied server scripts (generated with L and +the project skeleton script C) we apply C +automatically. This was done so that pre and post PSGI port applications would +work the same way. This is what you want to be using to retrieve the PSGI application code -reference of your Catalyst application for use in F<.psgi> files. +reference of your Catalyst application for use in a custom F<.psgi> or in your +own created server modules. =cut @@ -3178,6 +3233,7 @@ sub _handle_unicode_decoding { sub _handle_param_unicode_decoding { my ( $self, $value ) = @_; return unless defined $value; # not in love with just ignoring undefs - jnap + return $value if blessed($value); #don't decode when the value is an object. my $enc = $self->encoding; return try { @@ -3353,6 +3409,68 @@ the plugin name does not begin with C. } } +=head2 default_middleware + +Returns a list of instantiated PSGI middleware objects which is the default +middleware that is active for this application (taking any configuration +options into account, excluding your custom added middleware via the C +configuration option). You can override this method if you wish to change +the default middleware (although do so at risk since some middleware is vital +to application function.) + +The current default middleware list is: + + Catalyst::Middleware::Stash + Plack::Middleware::HTTPExceptions + Plack::Middleware::RemoveRedundantBody + Plack::Middleware::FixMissingBodyInRedirect + Plack::Middleware::ContentLength + Plack::Middleware::MethodOverride + Plack::Middleware::Head + +If the configuration setting C is true we add: + + Plack::Middleware::ReverseProxy + +If the configuration setting C is true we add: + + Plack::Middleware::ReverseProxyPath + +But B that L is not a dependency of the +L distribution so if you want to use this option you should add it to +your project distribution file. + +These middlewares will be added at L during the +L phase of application startup. + +=cut + +sub default_middleware { + my $class = shift; + my @mw = ( + Catalyst::Middleware::Stash->new, + Plack::Middleware::HTTPExceptions->new, + Plack::Middleware::RemoveRedundantBody->new, + Plack::Middleware::FixMissingBodyInRedirect->new, + Plack::Middleware::ContentLength->new, + Plack::Middleware::MethodOverride->new, + Plack::Middleware::Head->new); + + if($class->config->{using_frontend_proxy}) { + push @mw, Plack::Middleware::ReverseProxy->new; + } + + if($class->config->{using_frontend_proxy_path}) { + if(Class::Load::try_load_class('Plack::Middleware::ReverseProxyPath')) { + push @mw, Plack::Middleware::ReverseProxyPath->new; + } else { + $class->log->error("Cannot use configuration 'using_frontend_proxy_path' because 'Plack::Middleware::ReverseProxyPath' is not installed"); + } + } + + return @mw; +} + =head2 registered_middlewares Read only accessor that returns an array of all the middleware in the order @@ -3394,15 +3512,13 @@ up. sub registered_middlewares { my $class = shift; if(my $middleware = $class->_psgi_middleware) { - return ( - Catalyst::Middleware::Stash->new, - Plack::Middleware::HTTPExceptions->new, - Plack::Middleware::RemoveRedundantBody->new, - Plack::Middleware::FixMissingBodyInRedirect->new, - Plack::Middleware::ContentLength->new, - Plack::Middleware::MethodOverride->new, - Plack::Middleware::Head->new, - @$middleware); + my @mw = ($class->default_middleware, @$middleware); + + if($class->config->{using_frontend_proxy}) { + push @mw, Plack::Middleware::ReverseProxy->new; + } + + return @mw; } else { die "You cannot call ->registered_middlewares until middleware has been setup"; } @@ -3410,8 +3526,17 @@ sub registered_middlewares { sub setup_middleware { my $class = shift; - my @middleware_definitions = @_ ? - reverse(@_) : reverse(@{$class->config->{'psgi_middleware'}||[]}); + my @middleware_definitions; + + # If someone calls this method you can add middleware with args. However if its + # called without an arg we need to setup the configuration middleware. + if(@_) { + @middleware_definitions = reverse(@_); + } else { + @middleware_definitions = reverse(@{$class->config->{'psgi_middleware'}||[]}) + unless $class->finalized_default_middleware; + $class->finalized_default_middleware(1); # Only do this once, just in case some people call setup over and over... + } my @middleware = (); while(my $next = shift(@middleware_definitions)) { @@ -3508,7 +3633,7 @@ sub default_data_handlers { return eval { local $/; $slurped = $fh->getline; - $parser->can("decode_json")->($slurped); + $parser->can("decode_json")->($slurped); # decode_json does utf8 decoding for us } || Catalyst::Exception->throw(sprintf "Error Parsing POST '%s', Error: %s", (defined($slurped) ? $slurped : 'undef') ,$@); }, }; @@ -3705,6 +3830,15 @@ C - See L. =item * +C - Enabled L on your application (if +installed, otherwise log an error). This is useful if your application is not running on the +'root' (or /) of your host server. B if you use this feature you should add the required +middleware to your project dependency list since its not automatically a dependency of L. +This has been done since not all people need this feature and we wish to restrict the growth of +L dependencies. + +=item * + C - See L This now defaults to 'UTF-8'. You my turn it off by setting this configuration @@ -3749,6 +3883,27 @@ backwardly compatible). =item * +C + +When creating body parameters from a POST, if we run into a multpart POST +that does not contain uploads, but instead contains inlined complex data +(very uncommon) we cannot reliably convert that into field => value pairs. So +instead we create an instance of L. If this causes +issue for you, you can disable this by setting C +to true (default is false). + +=item * + +C + +Generally we decode incoming POST params based on your declared encoding (the +default for this is to decode UTF-8). If this is causing you trouble and you +do not wish to turn all encoding support off (with the C configuration +parameter) you may disable this step atomically by setting this configuration +parameter to true. + +=item * + C - See L. =item * @@ -4052,26 +4207,32 @@ Please see L for more on middleware. =head1 ENCODING -On request, decodes all params from encoding into a sequence of -logical characters. On response, encodes body into encoding. +Starting in L version 5.90080 encoding is automatically enabled +and set to encode all body responses to UTF8 when possible and applicable. +Following is documentation on this process. If you are using an older +version of L you should review documentation for that version since +a lot has changed. By default encoding is now 'UTF-8'. You may turn it off by setting the encoding configuration to undef. + MyApp->config(encoding => undef); + +This is recommended for temporary backwards compatibility only. + Encoding is automatically applied when the content-type is set to a type that can be encoded. Currently we encode when the content type matches the following regular expression: $content_type =~ /^text|xml$|javascript$/ -Encoding is set on the application, but it is copied to the response object -so you can override encoding rules per request (See L -for more information). +Encoding is set on the application, but it is copied to the context object +so that you can override it on a request basis. Be default we don't automatically encode 'application/json' since the most -popular JSON encoders (such as L which is the library that -L can make use of) will do the UTF8 encoding and decoding automatically. -Having it on in Catalyst could result in double encoding. +common approaches to generating this type of response (Either via L +or L) will do so already and we want to avoid double +encoding issues. If you are producing JSON response in an unconventional manner (such as via a template or manual strings) you should perform the UTF8 encoding @@ -4079,11 +4240,12 @@ manually as well such as to conform to the JSON specification. NOTE: We also examine the value of $c->response->content_encoding. If you set this (like for example 'gzip', and manually gzipping the body) -we assume that you have done all the neccessary encoding yourself, since +we assume that you have done all the necessary encoding yourself, since we cannot encode the gzipped contents. If you use a plugin like -L we will be updating that plugin to work -with the new UTF8 encoding code, or you can use L -or (probably best) do your compression on a front end proxy. +L you need to update to a modern version in order +to have this function correctly with the new UTF8 encoding code, or you +can use L or (probably best) do your compression on +a front end proxy. =head2 Methods @@ -4176,6 +4338,8 @@ acme: Leon Brocard abraxxa: Alexander Hartmaier +andrewalker: André Walker + Andrew Bramble Andrew Ford EA.Ford@ford-mason.co.ukE @@ -4314,9 +4478,11 @@ dd070: Dhaval Dhanani Upasana +John Napiorkowski (jnap) + =head1 COPYRIGHT -Copyright (c) 2005-2014, the above named PROJECT FOUNDER and CONTRIBUTORS. +Copyright (c) 2005-2015, the above named PROJECT FOUNDER and CONTRIBUTORS. =head1 LICENSE