X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=blobdiff_plain;f=lib%2FCatalyst.pm;h=d84ddbf3aee19ae3bcf0561488afa2e055d8b512;hp=04309c1b76aaf0bed47f7983eefa6f451b25241d;hb=7af15a33a6d54bdd91fe1635612c54fe026694bc;hpb=db79dedc53a699c00411bb9d3b989c6cd04a8988 diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 04309c1..d84ddbf 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -41,6 +41,8 @@ use Plack::Middleware::ReverseProxy; use Plack::Middleware::IIS6ScriptNameFix; use Plack::Middleware::IIS7KeepAliveFix; use Plack::Middleware::LighttpdScriptNameFix; +use Plack::Middleware::ContentLength; +use Plack::Middleware::Head; use Plack::Util; use Class::Load 'load_class'; @@ -65,6 +67,8 @@ sub _build_request_constructor_args { my %p = ( _log => $self->log ); $p{_uploadtmp} = $self->_uploadtmp if $self->_has_uploadtmp; $p{data_handlers} = {$self->registered_data_handlers}; + $p{_use_hash_multivalue} = $self->config->{use_hash_multivalue_in_request} + if $self->config->{use_hash_multivalue_in_request}; \%p; } @@ -118,7 +122,7 @@ __PACKAGE__->stats_class('Catalyst::Stats'); # Remember to update this in Catalyst::Runtime as well! -our $VERSION = '5.90049_003'; +our $VERSION = '5.90059_003'; sub import { my ( $class, @arguments ) = @_; @@ -1124,6 +1128,15 @@ sub setup { $class->setup_log( delete $flags->{log} ); $class->setup_plugins( delete $flags->{plugins} ); + + # Call plugins setup, this is stupid and evil. + # Also screws C3 badly on 5.10, hack to avoid. + { + no warnings qw/redefine/; + local *setup = sub { }; + $class->setup unless $Catalyst::__AM_RESTARTING; + } + $class->setup_middleware(); $class->setup_data_handlers(); $class->setup_dispatcher( delete $flags->{dispatcher} ); @@ -1157,6 +1170,11 @@ You are running an old script! EOF } + # Initialize our data structure + $class->components( {} ); + + $class->setup_components; + if ( $class->debug ) { my @plugins = map { "$_ " . ( $_->VERSION || '' ) } $class->registered_plugins; @@ -1200,22 +1218,7 @@ EOF ? $class->log->debug(qq/Found home "$home"/) : $class->log->debug(qq/Home "$home" doesn't exist/) : $class->log->debug(q/Couldn't find home/); - } - # Call plugins setup, this is stupid and evil. - # Also screws C3 badly on 5.10, hack to avoid. - { - no warnings qw/redefine/; - local *setup = sub { }; - $class->setup unless $Catalyst::__AM_RESTARTING; - } - - # Initialize our data structure - $class->components( {} ); - - $class->setup_components; - - if ( $class->debug ) { my $column_width = Catalyst::Utils::term_width() - 8 - 9; my $t = Text::SimpleTable->new( [ $column_width, 'Class' ], [ 8, 'Type' ] ); for my $comp ( sort keys %{ $class->components } ) { @@ -1835,7 +1838,7 @@ sub finalize { # Support skipping finalize for psgix.io style 'jailbreak'. Used to support # stuff like cometd and websockets - if($c->request->has_io_fh) { + if($c->request->_has_io_fh) { $c->log_response; return; } @@ -1856,11 +1859,6 @@ sub finalize { $c->finalize_headers unless $c->response->finalized_headers; - # HEAD request - if ( $c->request->method eq 'HEAD' ) { - $c->response->body(''); - } - $c->finalize_body; } @@ -1937,30 +1935,15 @@ EOF } } - # Content-Length - if ( defined $response->body && length $response->body && !$response->content_length ) { + # Remove incorrectly added body and content related meta data when returning + # an information response, or a response the is required to not include a body - # get the length from a filehandle - if ( blessed( $response->body ) && $response->body->can('read') || ref( $response->body ) eq 'GLOB' ) - { - my $size = -s $response->body; - if ( $size ) { - $response->content_length( $size ); - } - else { - $c->log->warn('Serving filehandle without a content-length'); - } - } - else { - # everything should be bytes at this point, but just in case - $response->content_length( length( $response->body ) ); - } - } - - # Errors if ( $response->status =~ /^(1\d\d|[23]04)$/ ) { - $response->headers->remove_header("Content-Length"); - $response->body(''); + if($response->has_body) { + $c->log->debug('Removing body for informational or no content http responses'); + $response->body(''); + $response->headers->remove_header("Content-Length"); + } } $c->finalize_cookies; @@ -3101,7 +3084,15 @@ See under L information regarding C and how to use it to enable L This method is automatically called during 'setup' of your application, so -you really don't need to invoke it. +you really don't need to invoke it. However you may do so if you find the idea +of loading middleware via configuration weird :). For example: + + package MyApp; + + use Catalyst; + + __PACKAGE__->setup_middleware('Head'); + __PACKAGE__->setup; When we read middleware definitions from configuration, we reverse the list which sounds odd but is likely how you expect it to work if you have prior @@ -3113,16 +3104,19 @@ L (which is now considered deprecated) sub registered_middlewares { my $class = shift; if(my $middleware = $class->_psgi_middleware) { - return @$middleware; + return ( + Plack::Middleware::ContentLength->new, + Plack::Middleware::Head->new, + @$middleware); } else { die "You cannot call ->registered_middlewares until middleware has been setup"; } } sub setup_middleware { - my ($class, @middleware_definitions) = @_; - push @middleware_definitions, reverse( - @{$class->config->{'psgi_middleware'}||[]}); + my $class = shift; + my @middleware_definitions = @_ ? + @_ : reverse(@{$class->config->{'psgi_middleware'}||[]}); my @middleware = (); while(my $next = shift(@middleware_definitions)) { @@ -3144,7 +3138,8 @@ sub setup_middleware { } } - $class->_psgi_middleware(\@middleware); + my @existing = @{$class->_psgi_middleware || []}; + $class->_psgi_middleware([@middleware,@existing,]); } =head2 registered_data_handlers @@ -3165,15 +3160,20 @@ you really don't need to invoke it. =head2 default_data_handlers -Default Data Handler that come bundled with L. Currently there is -only one default data handler, for 'application/json'. This uses L -which uses the dependency free L OR L if you have -installed it. If you don't mind the XS dependency, you should add the faster -L to you dependency list (in your Makefile.PL or dist.ini, or -cpanfile, etc.) +Default Data Handlers that come bundled with L. Currently there are +only two default data handlers, for 'application/json' and an alternative to +'application/x-www-form-urlencoded' which supposed nested form parameters via +L or via L IF you've installed it. -L is loaded the first time you ask for it (so if you never ask -for it, its never used). +The 'application/json' data handler is used to parse incoming JSON into a Perl +data structure. It used either L or L, depending on which +is installed. This allows you to fail back to L, which is a Pure Perl +JSON decoder, and has the smallest dependency impact. + +Because we don't wish to add more dependencies to L, if you wish to +use this new feature we recommend installing L or L in +order to get the best performance. You should add either to your dependency +list (Makefile.PL, dist.ini, cpanfile, etc.) =cut @@ -3199,10 +3199,16 @@ sub setup_data_handlers { sub default_data_handlers { my ($class) = @_; return +{ + 'application/x-www-form-urlencoded' => sub { + my ($fh, $req) = @_; + my $params = $req->_use_hash_multivalue ? $req->body_parameters->mixed : $req->body_parameters; + Class::Load::load_first_existing_class('CGI::Struct::XS', 'CGI::Struct') + ->can('build_cgi_struct')->($params); + }, 'application/json' => sub { - local $/; - Class::Load::load_class("JSON::MaybeXS"); - JSON::MaybeXS::decode_json $_->getline }, + Class::Load::load_first_existing_class('JSON::MaybeXS', 'JSON') + ->can('decode_json')->(do { local $/; $_->getline }); + }, }; } @@ -3395,6 +3401,26 @@ In the future this might become the default behavior. =item * +C + +In L the methods C, C +and C return a hashref where values might be scalar or an arrayref +depending on the incoming data. In many cases this can be undesirable as it +leads one to writing defensive code like the following: + + my ($val) = ref($c->req->parameters->{a}) ? + @{$c->req->parameters->{a}} : + $c->req->parameters->{a}; + +Setting this configuration item to true will make L populate the +attributes underlying these methods with an instance of L +which is used by L and others to solve this very issue. You +may prefer this behavior to the default, if so enable this option (be warned +if you enable it in a legacy application we are not sure if it is completely +backwardly compatible). + +=item * + C - See L. =item * @@ -3571,6 +3597,23 @@ So the general form is: Where C<@middleware> is one or more of the following, applied in the REVERSE of the order listed (to make it function similarly to L: + +Alternatively, you may also define middleware by calling the L +package method: + + package MyApp::Web; + + use Catalyst; + + __PACKAGE__->setup_middleware( \@middleware_definitions); + __PACKAGE__->setup; + +In the case where you do both (use 'setup_middleware' and configuration) the +package call to setup_middleware will be applied earlier (in other words its +middleware will wrap closer to the application). Keep this in mind since in +some cases the order of middleware is important. + +The two approaches are not exclusive. =over 4