Catalyst-Runtime

 view release on metacpan or  search on metacpan

lib/Catalyst.pm  view on Meta::CPAN

package Catalyst;

use Moose;
use Moose::Meta::Class ();
extends 'Catalyst::Component';
use Moose::Util qw/find_meta/;
use namespace::clean -except => 'meta';
use Catalyst::Exception;
use Catalyst::Exception::Detach;
use Catalyst::Exception::Go;
use Catalyst::Log;
use Catalyst::Request;
use Catalyst::Request::Upload;
use Catalyst::Response;
use Catalyst::Utils;
use Catalyst::Controller;
use Data::OptList;
use Devel::InnerPackage ();
use Module::Pluggable::Object ();
use Text::SimpleTable ();
use Path::Class::Dir ();
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;
use List::Util qw/uniq/;
use attributes;
use String::RewritePrefix;
use Catalyst::EngineLoader;
use utf8;
use Carp qw/croak carp shortmess/;
use Try::Tiny;
use Safe::Isa;
use Moose::Util 'find_meta';
use Plack::Middleware::Conditional;
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::Middleware::HTTPExceptions;
use Plack::Middleware::FixMissingBodyInRedirect;
use Plack::Middleware::MethodOverride;
use Plack::Middleware::RemoveRedundantBody;
use Catalyst::Middleware::Stash;
use Plack::Util;
use Class::Load 'load_class';
use Encode 2.21 'decode_utf8', 'encode_utf8';
use Scalar::Util;

our $VERSION = '5.90132';
$VERSION =~ tr/_//d;

BEGIN { require 5.008003; }

has stack => (is => 'ro', default => sub { [] });
has state => (is => 'rw', default => 0);
has stats => (is => 'rw');
has action => (is => 'rw');
has counter => (is => 'rw', default => sub { {} });
has request => (
    is => 'rw',
    default => sub {
        my $self = shift;
        my $class = ref $self;
        my $composed_request_class = $class->composed_request_class;
        return $composed_request_class->new( $self->_build_request_constructor_args);
    },
    predicate => 'has_request',
    lazy => 1,
);
sub _build_request_constructor_args {
    my $self = shift;
    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;
}

sub composed_request_class {
  my $class = shift;
  return $class->_composed_request_class if $class->_composed_request_class;

  my @traits = (@{$class->request_class_traits||[]}, @{$class->config->{request_class_traits}||[]});

  # For each trait listed, figure out what the namespace is.  First we try the $trait
  # as it is in the config.  Then try $MyApp::TraitFor::Request:$trait. Last we try
  # Catalyst::TraitFor::Request::$trait.  If none load, throw error.

lib/Catalyst.pm  view on Meta::CPAN

=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' },
        'Model::Foo' => { from_component => 'Local::Model::Foo', roles => ['TestRole'] },
      },
      'Controller::Err' => { a => 100, b=>200, namespace=>'error' },
      'Model::Zoo' => { a => 2 },
      'Model::Foo' => { a => 100 },
    });

Generally L<Catalyst> looks for components in your Model/View or Controller directories.
However for cases when you which to use an existing component and you don't need any
customization (where for when you can apply a role to customize it) you may inject those
components into your application.  Please note any configuration should be done 'in the
normal way', with a key under configuration named after the component affix, as in the
above example.

Using this type of injection allows you to construct significant amounts of your application
with only configuration!.  This may or may not lead to increased code understanding.

Please not you may also call the ->inject_components application method as well, although
you must do so BEFORE setup.

=back

=head1 EXCEPTIONS

Generally when you throw an exception inside an Action (or somewhere in
your stack, such as in a model that an Action is calling) that exception
is caught by Catalyst and unless you either catch it yourself (via eval
or something like L<Try::Tiny> or by reviewing the L</error> stack, it
will eventually reach L</finalize_errors> and return either the debugging
error stack page, or the default error page.  However, if your exception
can be caught by L<Plack::Middleware::HTTPExceptions>, L<Catalyst> will
instead rethrow it so that it can be handled by that middleware (which
is part of the default middleware).  For example this would allow

    use HTTP::Throwable::Factory 'http_throw';

    sub throws_exception :Local {
      my ($self, $c) = @_;

      http_throw(SeeOther => { location =>
        $c->uri_for($self->action_for('redirect')) });

    }

=head1 INTERNAL ACTIONS

Catalyst uses internal actions like C<_DISPATCH>, C<_BEGIN>, C<_AUTO>,
C<_ACTION>, and C<_END>. These are by default not shown in the private
action table, but you can make them visible with a config parameter.

    MyApp->config(show_internal_actions => 1);

=head1 ON-DEMAND PARSER

The request body is usually parsed at the beginning of a request,
but if you want to handle input yourself, you can enable on-demand
parsing with a config parameter.

    MyApp->config(parse_on_demand => 1);

=head1 PROXY SUPPORT

Many production servers operate using the common double-server approach,
with a lightweight frontend web server passing requests to a larger
backend server. An application running on the backend server must deal
with two problems: the remote user always appears to be C<127.0.0.1> and
the server's hostname will appear to be C<localhost> regardless of the
virtual host that the user connected through.

Catalyst will automatically detect this situation when you are running
the frontend and backend servers on the same machine. The following
changes are made to the request.

    $c->req->address is set to the user's real IP address, as read from
    the HTTP X-Forwarded-For header.

    The host value for $c->req->base and $c->req->uri is set to the real
    host, as read from the HTTP X-Forwarded-Host header.

Additionally, you may be running your backend application on an insecure
connection (port 80) while your frontend proxy is running under SSL.  If there
is a discrepancy in the ports, use the HTTP header C<X-Forwarded-Port> to
tell Catalyst what port the frontend listens on.  This will allow all URIs to
be created properly.

In the case of passing in:

    X-Forwarded-Port: 443



( run in 1.215 second using v1.01-cache-2.11-cpan-39bf76dae61 )