Kossy
view release on metacpan or search on metacpan
lib/Kossy.pm view on Meta::CPAN
our $SECURITY_HEADER = 1;
our $JSON_SERIALIZER;
# cache underscore translation
HTTP::Headers::Fast::_standardize_field_name('X-Frame-Options');
sub new {
my $class = shift;
my %args;
if ( @_ < 2 ) {
my $root_dir = shift;
my @caller = caller;
$root_dir ||= File::Basename::dirname( Cwd::realpath($caller[1]) );
$args{root_dir} = $root_dir;
}
else {
%args = @_;
}
bless \%args, $class;
}
sub psgi {
my $self = shift;
if ( ! ref $self ) {
my %args;
if ( @_ < 2 ) {
my $root_dir = shift;
my @caller = caller;
$root_dir ||= File::Basename::dirname( Cwd::realpath($caller[1]) );
$args{root_dir} = $root_dir;
}
else {
%args = @_;
}
$self = $self->new(%args);
}
$self->build_app;
}
sub build_app {
my $self = shift;
my $security_header_local = $SECURITY_HEADER;
my %match_cache;
my $tx = __PACKAGE__->_build_text_xslate(
root_dir => $self->root_dir,
cache => $XSLATE_CACHE,
cache_dir => $XSLATE_CACHE_DIR,
);
my $json_serializer = __PACKAGE__->_build_json_serializer();
sub {
my $env = shift;
$Kossy::Response::SECURITY_HEADER = $security_header_local;
try {
my $header = bless {
'content-type' => 'text/html; charset=UTF-8',
$security_header_local ? ('x-frame-options' => 'DENY') : (),
}, 'HTTP::Headers::Fast';
my $c = Kossy::Connection->new({
tx => $tx,
req => Kossy::Request->new($env),
res => Kossy::Response->new(200, $header),
stash => {},
json_serializer => $json_serializer,
});
my $method = uc($env->{REQUEST_METHOD});
my $cache_key = $method . '-' . $env->{PATH_INFO};
my ($match,$args) = try {
if ( exists $match_cache{$cache_key} ) {
return @{$match_cache{$cache_key}};
}
my $path_info = Encode::decode_utf8( $env->{PATH_INFO}, Encode::FB_CROAK | Encode::LEAVE_SRC );
my ($dest, $captured, $method_not_allowed) = $self->_router->match($method, $path_info);
if ($method_not_allowed) {
$c->halt(405);
}
if (!$dest) {
$c->halt(404);
}
$match_cache{$cache_key} = [$dest, $captured];
return ($dest, $captured);
} catch {
if ( ref $_ && ref $_ eq 'Kossy::Exception' ) {
die $_; #rethrow
}
$c->halt(400,'unexpected character in request');
};
my $code = $match->{__action__};
my $filters = $match->{__filter__} || [];
if ( $] == 5.020000 || $] == 5.020100 ) {
# workaround for 5.20.0 or 5.20.1 https://github.com/kazeburo/Kossy/pull/10
my %args = map { $_ => Encode::decode_utf8($args->{$_}) } keys %$args;
$c->args(\%args);
} else {
$c->args({%$args});
}
my $app = sub {
my ($self, $c) = @_;
my $response;
my $res = $code->($self, $c);
Carp::croak "Undefined Response" if ! defined $res;
my $res_t = ref($res) || '';
if ( $res_t eq 'Kossy::Response' ) {
$response = $res;
}
elsif ( $res_t eq 'Plack::Response' ) {
$response = bless $res, 'Kossy::Response';
}
elsif ( $res_t eq 'ARRAY' ) {
$response = Kossy::Response->new(@$res);
}
elsif ( !$res_t ) {
$c->res->body($res);
( run in 0.330 second using v1.01-cache-2.11-cpan-d7f47b0818f )