Catalyst-Runtime
view release on metacpan or search on metacpan
lib/Catalyst.pm view on Meta::CPAN
$c->prepare_headers; # Just hooks, no longer needed - they just
$c->prepare_cookies; # cause the lazy attribute on req to build
$c->prepare_path;
# Prepare the body for reading, either by prepare_body
# or the user, if they are using $c->read
$c->prepare_read;
# Parse the body unless the user wants it on-demand
unless ( ref($c)->config->{parse_on_demand} ) {
$c->prepare_body;
}
}
$c->prepare_action;
}
# VERY ugly and probably shouldn't rely on ->finalize actually working
catch {
# failed prepare is always due to an invalid request, right?
# Note we call finalize and then die here, which escapes
# finalize being called in the enclosing block..
# It in fact couldn't be called, as we don't return $c..
# This is a mess - but I'm unsure you can fix this without
# breaking compat for people doing crazy things (we should set
# the 400 and just return the ctx here IMO, letting finalize get called
# above...
if ( $c->_handle_http_exception($_) ) {
foreach my $err (@{$c->error}) {
$c->log->error($err);
}
$c->clear_errors;
$c->log->_flush if $c->log->can('_flush');
$_->can('rethrow') ? $_->rethrow : croak $_;
} else {
$c->response->status(400);
$c->response->content_type('text/plain');
$c->response->body('Bad Request');
$c->finalize;
die $_;
}
};
$c->log_request;
$c->{stash} = $c->stash;
Scalar::Util::weaken($c->{stash});
return $c;
}
=head2 $c->prepare_action
Prepares action. See L<Catalyst::Dispatcher>.
=cut
sub prepare_action {
my $c = shift;
my $ret = $c->dispatcher->prepare_action( $c, @_);
if($c->encoding) {
foreach (@{$c->req->arguments}, @{$c->req->captures}) {
$_ = $c->_handle_param_unicode_decoding($_);
}
}
return $ret;
}
=head2 $c->prepare_body
Prepares message body.
=cut
sub prepare_body {
my $c = shift;
return if $c->request->_has_body;
# Initialize on-demand data
$c->engine->prepare_body( $c, @_ );
$c->prepare_parameters;
$c->prepare_uploads;
}
=head2 $c->prepare_body_chunk( $chunk )
Prepares a chunk of data before sending it to L<HTTP::Body>.
See L<Catalyst::Engine>.
=cut
sub prepare_body_chunk {
my $c = shift;
$c->engine->prepare_body_chunk( $c, @_ );
}
=head2 $c->prepare_body_parameters
Prepares body parameters.
=cut
sub prepare_body_parameters {
my $c = shift;
$c->request->prepare_body_parameters( $c, @_ );
}
=head2 $c->prepare_connection
Prepares connection.
=cut
sub prepare_connection {
my $c = shift;
$c->request->prepare_connection($c);
}
=head2 $c->prepare_cookies
lib/Catalyst.pm view on Meta::CPAN
backward compatibility with older applications. If you start your application
using one of the supplied server scripts (generated with L<Catalyst::Devel> and
the project skeleton script C<catalyst.pl>) we apply C<apply_default_middlewares>
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 a custom F<.psgi> or in your
own created server modules.
=cut
*to_app = \&psgi_app;
sub psgi_app {
my ($app) = @_;
my $psgi = $app->engine->build_psgi_app($app);
return $app->Catalyst::Utils::apply_registered_middleware($psgi);
}
=head2 $c->setup_home
Sets up the home directory.
=cut
sub setup_home {
my ( $class, $home ) = @_;
if ( my $env = Catalyst::Utils::env_value( $class, 'HOME' ) ) {
$home = $env;
}
$home ||= Catalyst::Utils::home($class);
if ($home) {
#I remember recently being scolded for assigning config values like this
$class->config->{home} ||= $home;
$class->config->{root} ||= Path::Class::Dir->new($home)->subdir('root');
}
}
=head2 $c->setup_encoding
Sets up the input/output encoding. See L<ENCODING>
=cut
sub setup_encoding {
my $c = shift;
if( exists($c->config->{encoding}) && !defined($c->config->{encoding}) ) {
# Ok, so the user has explicitly said "I don't want encoding..."
return;
} else {
my $enc = defined($c->config->{encoding}) ?
delete $c->config->{encoding} : 'UTF-8'; # not sure why we delete it... (JNAP)
$c->encoding($enc);
}
}
=head2 handle_unicode_encoding_exception
Hook to let you customize how encoding errors are handled. By default
we just throw an exception and the default error page will pick it up.
Receives a hashref of debug information. Example of call (from the
Catalyst internals):
my $decoded_after_fail = $c->handle_unicode_encoding_exception({
param_value => $value,
error_msg => $_,
encoding_step => 'params',
});
The calling code expects to receive a decoded string or an exception.
You can override this for custom handling of unicode errors. By
default we just die. If you want a custom response here, one approach
is to throw an HTTP style exception, instead of returning a decoded
string or throwing a generic exception.
sub handle_unicode_encoding_exception {
my ($c, $params) = @_;
HTTP::Exception::BAD_REQUEST->throw(status_message=>$params->{error_msg});
}
Alternatively you can 'catch' the error, stash it and write handling code later
in your application:
sub handle_unicode_encoding_exception {
my ($c, $params) = @_;
$c->stash(BAD_UNICODE_DATA=>$params);
# return a dummy string.
return 1;
}
<B>NOTE:</b> Please keep in mind that once an error like this occurs,
the request setup is still ongoing, which means the state of C<$c> and
related context parts like the request and response may not be setup
up correctly (since we haven't finished the setup yet). If you throw
an exception the setup is aborted.
=cut
sub handle_unicode_encoding_exception {
my ( $self, $exception_ctx ) = @_;
die $exception_ctx->{error_msg};
}
# Some unicode helpers cargo culted from the old plugin. These could likely
# be neater.
sub _handle_unicode_decoding {
my ( $self, $value ) = @_;
return unless defined $value;
## I think this mess is to support the old nested
if ( ref $value eq 'ARRAY' ) {
foreach ( @$value ) {
$_ = $self->_handle_unicode_decoding($_);
}
return $value;
}
elsif ( ref $value eq 'HASH' ) {
foreach (keys %$value) {
my $encoded_key = $self->_handle_param_unicode_decoding($_);
$value->{$encoded_key} = $self->_handle_unicode_decoding($value->{$_});
# If the key was encoded we now have two (the original and current so
# delete the original.
delete $value->{$_} if $_ ne $encoded_key;
}
return $value;
}
else {
return $self->_handle_param_unicode_decoding($value);
}
}
sub _handle_param_unicode_decoding {
my ( $self, $value, $check ) = @_;
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 $value unless $enc; # don't decode if no encoding is specified
$check ||= $self->_encode_check;
return try {
$enc->decode( $value, $check);
}
catch {
return $self->handle_unicode_encoding_exception({
param_value => $value,
error_msg => $_,
encoding_step => 'params',
});
};
}
=head2 $c->setup_log
Sets up log by instantiating a L<Catalyst::Log|Catalyst::Log> object and
passing it to C<log()>. Pass in a comma-delimited list of levels to set the
log to.
This method also installs a C<debug> method that returns a true value into the
catalyst subclass if the "debug" level is passed in the comma-delimited list,
or if the C<$CATALYST_DEBUG> environment variable is set to a true value.
Note that if the log has already been setup, by either a previous call to
C<setup_log> or by a call such as C<< __PACKAGE__->log( MyLogger->new ) >>,
that this method won't actually set up the log object.
=cut
sub setup_log {
my ( $class, $levels ) = @_;
$levels ||= '';
$levels =~ s/^\s+//;
$levels =~ s/\s+$//;
my %levels = map { $_ => 1 } split /\s*,\s*/, $levels;
my $env_debug = Catalyst::Utils::env_value( $class, 'DEBUG' );
if ( defined $env_debug ) {
$levels{debug} = 1 if $env_debug; # Ugly!
delete($levels{debug}) unless $env_debug;
}
unless ( $class->log ) {
$class->log( Catalyst::Log->new(keys %levels) );
}
if ( $levels{debug} ) {
Class::MOP::get_metaclass_by_name($class)->add_method('debug' => sub { 1 });
$class->log->debug('Debug messages enabled');
}
}
=head2 $c->setup_plugins
Sets up plugins.
=cut
=head2 $c->setup_stats
Sets up timing statistics class.
=cut
sub setup_stats {
lib/Catalyst.pm view on Meta::CPAN
=item *
C<encoding> - See L</ENCODING>
This now defaults to 'UTF-8'. You my turn it off by setting this configuration
value to undef.
=item *
C<abort_chain_on_error_fix>
Defaults to true.
When there is an error in an action chain, the default behavior is to
abort the processing of the remaining actions to avoid running them
when the application is in an unexpected state.
Before version 5.90070, the default used to be false. To keep the old
behaviour, you can explicitly set the value to false. E.g.
__PACKAGE__->config(abort_chain_on_error_fix => 0);
If this setting is set to false, then the remaining actions are
performed and the error is caught at the end of the chain.
=item *
C<use_hash_multivalue_in_request>
In L<Catalyst::Request> the methods C<query_parameters>, C<body_parametes>
and C<parameters> 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<Catalyst> populate the
attributes underlying these methods with an instance of L<Hash::MultiValue>
which is used by L<Plack::Request> 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<skip_complex_post_part_handling>
When creating body parameters from a POST, if we run into a multipart 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<Catalyst::Request::PartData>. If this causes
issue for you, you can disable this by setting C<skip_complex_post_part_handling>
to true (default is false).
=item *
C<skip_body_param_unicode_decoding>
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<encoding> configuration
parameter) you may disable this step atomically by setting this configuration
parameter to true.
=item *
C<do_not_decode_query>
If true, then do not try to character decode any wide characters in your
request URL query or keywords. Most readings of the relevant specifications
suggest these should be UTF-* encoded, which is the default that L<Catalyst>
will use, however if you are creating a lot of URLs manually or have external
evil clients, this might cause you trouble. If you find the changes introduced
in Catalyst version 5.90080+ break some of your query code, you may disable
the UTF-8 decoding globally using this configuration.
This setting takes precedence over C<default_query_encoding>
=item *
C<do_not_check_query_encoding>
Catalyst versions 5.90080 - 5.90106 would decode query parts of an incoming
request but would not raise an exception when the decoding failed due to
incorrect unicode. It now does, but if this change is giving you trouble
you may disable it by setting this configuration to true.
=item *
C<default_query_encoding>
By default we decode query and keywords in your request URL using UTF-8, which
is our reading of the relevant specifications. This setting allows one to
specify a fixed value for how to decode your query. You might need this if
you are doing a lot of custom encoding of your URLs and not using UTF-8.
=item *
C<use_chained_args_0_special_case>
In older versions of Catalyst, when more than one action matched the same path
AND all those matching actions declared Args(0), we'd break the tie by choosing
the first action defined. We now normalized how Args(0) works so that it
follows the same rule as Args(N), which is to say when we need to break a tie
we choose the LAST action defined. If this breaks your code and you don't
have time to update to follow the new normalized approach, you may set this
value to true and it will globally revert to the original chaining behavior.
=item *
C<psgi_middleware> - See L<PSGI MIDDLEWARE>.
=item *
C<data_handlers> - See L<DATA HANDLERS>.
=item *
C<stats_class_traits>
An arrayref of L<Moose::Role>s that get composed into your stats class.
=item *
C<request_class_traits>
An arrayref of L<Moose::Role>s that get composed into your request class.
=item *
C<response_class_traits>
An arrayref of L<Moose::Role>s that get composed into your response class.
=item *
C<inject_components>
A Hashref of L<Catalyst::Component> subclasses that are 'injected' into configuration.
For example:
MyApp->config({
inject_components => {
'Controller::Err' => { from_component => 'Local::Controller::Errors' },
'Model::Zoo' => { from_component => 'Local::Model::Foo' },
lib/Catalyst.pm view on Meta::CPAN
Please see L<PSGI> for more on middleware.
=head1 ENCODING
Starting in L<Catalyst> 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<Catalyst> 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.
To turn it off for a single request use the L<clear_encoding>
method to turn off encoding for this request. This can be useful
when you are setting the body to be an arbitrary block of bytes,
especially if that block happens to be a block of UTF8 text.
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 context object
so that you can override it on a request basis.
Be default we don't automatically encode 'application/json' since the most
common approaches to generating this type of response (Either via L<Catalyst::View::JSON>
or L<Catalyst::Action::REST>) 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
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 necessary encoding yourself, since
we cannot encode the gzipped contents. If you use a plugin like
L<Catalyst::Plugin::Compress> 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<Plack::Middleware::Deflater> or (probably best) do your compression on
a front end proxy.
=head2 Methods
=over 4
=item encoding
Returns an instance of an C<Encode> 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<Encode>.
=item encoding_step
What type of data was being decoded. Valid values are (currently)
C<params> - for request parameters / arguments / captures
and C<uploads> - for request upload filenames.
=back
=back
=head1 SUPPORT
IRC:
Join #catalyst on irc.perl.org.
Mailing Lists:
http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst
http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst-dev
Web:
http://catalyst.perl.org
Wiki:
http://dev.catalyst.perl.org
=head1 SEE ALSO
=head2 L<Task::Catalyst> - All you need to start with Catalyst
=head2 L<Catalyst::Manual> - The Catalyst Manual
=head2 L<Catalyst::Component>, L<Catalyst::Controller> - Base classes for components
=head2 L<Catalyst::Engine> - Core engine
( run in 1.491 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )