has
[
qw/default_static_class root/
];
sub
dispatch {
my
(
$self
,
$c
) =
@_
;
return
1
if
$c
->res->code;
my
$stash
=
$c
->stash;
my
$path
=
$stash
->{path};
$path
=
$c
->req->url->path->clone->canonicalize->to_string
unless
defined
$path
;
my
@parts
= @{Mojo::Path->new->parse(
$path
)->parts};
return
unless
@parts
;
return
if
$parts
[0] eq
'..'
;
if
(
$self
->serve(
$c
,
join
(
'/'
,
@parts
))) {
$stash
->{
'mojo.static'
} = 1;
$c
->rendered;
return
1;
}
return
1;
}
sub
serve {
my
(
$self
,
$c
,
$rel
,
$root
) =
@_
;
$root
=
$self
->root
unless
defined
$root
;
my
$path
= File::Spec->catfile(
$root
,
split
(
'/'
,
$rel
));
$path
=~ /\.(\w+)$/;
my
$ext
= $1;
$self
->{bundled}
||= File::Spec->catdir(File::Spec->splitdir(dirname(__FILE__)),
'public'
);
my
$asset
;
my
$modified
=
$self
->{modified} ||=
time
;
my
$size
= 0;
my
$res
=
$c
->res;
if
(
my
$file
=
$self
->_get_file(
$path
)) {
if
(
@$file
) { (
$asset
,
$size
,
$modified
) =
@$file
}
else
{
$c
->app->
log
->debug(
qq/File "$rel" is forbidden./
);
$res
->code(403) and
return
;
}
}
elsif
(!
$asset
&&
defined
(
my
$data
=
$self
->_get_data_file(
$c
,
$rel
))) {
$size
=
length
$data
;
$asset
= Mojo::Asset::Memory->new->add_chunk(
$data
);
}
else
{
$path
= File::Spec->catfile(
$self
->{bundled},
split
(
'/'
,
$rel
));
if
(
my
$bundled
=
$self
->_get_file(
$path
)) {
(
$asset
,
$size
,
$modified
) =
@$bundled
if
@$bundled
;
}
}
if
(
$asset
) {
my
$rqh
=
$c
->req->headers;
my
$rsh
=
$res
->headers;
if
(
my
$date
=
$rqh
->if_modified_since) {
my
$since
= Mojo::Date->new(
$date
)->epoch;
if
(
defined
$since
&&
$since
==
$modified
) {
$res
->code(304);
$rsh
->remove(
'Content-Type'
);
$rsh
->remove(
'Content-Length'
);
$rsh
->remove(
'Content-Disposition'
);
return
1;
}
}
my
$start
= 0;
my
$end
=
$size
- 1 >= 0 ?
$size
- 1 : 0;
if
(
my
$range
=
$rqh
->range) {
if
(
$range
=~ m/^bytes=(\d+)\-(\d+)?/ && $1 <=
$end
) {
$start
= $1;
$end
= $2
if
defined
$2 && $2 <=
$end
;
$res
->code(206);
$rsh
->content_length(
$end
-
$start
+ 1);
$rsh
->content_range(
"bytes $start-$end/$size"
);
}
else
{
$res
->code(416);
return
1;
}
}
$asset
->start_range(
$start
);
$asset
->end_range(
$end
);
$res
->code(200)
unless
$res
->code;
$res
->content->asset(
$asset
);
$rsh
->content_type(
$c
->app->types->type(
$ext
) ||
'text/plain'
);
$rsh
->accept_ranges(
'bytes'
);
$rsh
->last_modified(Mojo::Date->new(
$modified
));
return
1;
}
return
;
}
sub
_get_data_file {
my
(
$self
,
$c
,
$rel
) =
@_
;
return
if
$rel
=~ /\.\w+\.\w+$/;
my
$class
=
$c
->stash->{static_class}
||
$ENV
{MOJO_STATIC_CLASS}
||
$self
->default_static_class
||
'main'
;
my
$data
=
$self
->{data_files}->{
$class
}
||= [
keys
%{Mojo::Command->new->get_all_data(
$class
) || {}}];
for
my
$path
(
@$data
) {
return
Mojo::Command->new->get_data(
$path
,
$class
)
if
$path
eq
$rel
;
}
return
;
}
sub
_get_file {
my
(
$self
,
$path
,
$rel
) =
@_
;
return
unless
-f
$path
;
return
[]
unless
-r
$path
;
return
[Mojo::Asset::File->new(
path
=>
$path
), (
stat
$path
)[7, 9]];
}
1;