Klonk
view release on metacpan or search on metacpan
lib/Klonk/Routes.pm view on Meta::CPAN
my @chunks = @{$_->[2]};
my $rest = defined $chunks[-1] ? 0 : (pop @chunks, 1);
my $re = join '([^/]*+)', map quotemeta, @chunks;
$re .= '(.*+)' if $rest;
$re .= "(*:$gen)";
$mapping{$gen++} = $_->[0];
$re
}
sort { $b->[1] cmp $a->[1] || $a->[0] cmp $b->[0] }
map [$_, @{$routes{$_}}{'weight', 'chunks'}],
keys %routes;
$regex = '(?!)' if $regex eq '';
#say STDERR ">>> $regex";
#use re 'debugcolor';
[
qr/\A(?|$regex)\z/s,
\%mapping,
]
}
my %text_types = (
'css' => 'text/css',
'csv' => 'text/csv',
'html' => 'text/html',
'js' => 'text/javascript',
'json' => 'application/json',
'jsonld' => 'application/ld+json',
'text' => 'text/plain',
);
my %bin_types = (
'bin' => 'application/octet-stream',
'jpeg' => 'image/jpeg',
'png' => 'image/png',
'webp' => 'image/webp',
);
fun _postprocess($ret) {
my $status = 200;
if ($ret->[0] =~ /\A\d{3}\z/a) {
$status = shift @$ret;
}
my ($itype, $body, $headers) = @$ret;
for my $spec (
[\%text_types, 1],
[\%bin_types, 0],
) {
my ($type_map, $encode_p) = @$spec;
if (my $type = $type_map->{$itype}) {
if ($encode_p) {
utf8::encode $body unless ref $body;
$type .= '; charset=utf-8';
}
my $length = ref $body
? -s $body || undef
: length $body;
return [
$status,
[
'content-type' => $type,
defined $length
? ('content-length' => $length)
: (),
map {
my $k = $_;
my $v = $headers->{$k};
map +($k => $_), ref($v) eq 'ARRAY' ? @$v : $v
}
keys %{$headers // {}}
],
ref $body ? $body : [ $body ]
];
}
}
die "Unknown content type: $itype";
}
my $booted;
my @init;
fun on_init($fun) {
croak "Can't call on_init() after boot()" if $booted;
push @init, $fun;
}
fun dispatch($env) {
my $kenv = Klonk::Env->new($env);
my $req_path = $env->{PATH_INFO};
my $req_method = $env->{REQUEST_METHOD};
$dispatch_info //= _routes_prepare;
local our $REGMARK;
if (my @captures = $req_path =~ /$dispatch_info->[0]/) {
my $pattern = $dispatch_info->[1]{$REGMARK};
my $meta = $routes{$pattern};
splice @captures, $#{$meta->{chunks}};
my $resource = $meta->{resource};
if (my $info = $resource->{$req_method}) {
my $handler = $info->{handler};
return _postprocess $handler->($kenv, @captures);
}
if ($req_method eq 'HEAD' && (my $info = $resource->{GET})) {
my $ret = _postprocess $info->{handler}($kenv, @captures);
return [ 204, $ret->[1], [] ];
}
my $allowed_methods = join ', ', sort keys %$resource;
if ($req_method eq 'OPTIONS') {
return [ 204, [ 'allow' => $allowed_methods ], [] ];
}
return _postprocess [
405,
'html',
"<!doctype html><title>405 Method Not Allowed</title><h1>405 Method Not Allowed</h1>",
{ allow => $allowed_methods }
];
}
( run in 0.498 second using v1.01-cache-2.11-cpan-d7f47b0818f )