| Jifty documentation | Contained in the Jifty distribution. |
Jifty::View::Static::Handler - Jifty view handler for static files
This is deprecated and is being port to a stack of plack middleware and plack::app::file
This class takes care of serving out static files for a Jifty application.
When fully operational, it will use an algorithm along the lines of the following:
* Static files are served out of a separate root * If static files go through apache: * How do we merge together the N static roots? * If static files go through Jifty::Handler * We need a flag to allow them to go through the dispatcher, too * return "True" (304) for if-modified-since * if the browser accepts gzipped data, see if we have a cached gzipped copy if so, send it see if we have a marker indicating that gzip is a lose if so, send uncompressed
gzip the content
send the gzipped content
* if the browser doesn't accept gzipped content
send the content uncompressed
Create a new static file handler. Likely, only the Jifty::Handler needs to do this.
Returns all the static roots the handler will search
Handle a request for $path. If we can't find a static file of that name, return undef.
An alias for show
Returns the system path for $path, searching inside the
application's static root, loaded plugins' static roots, and finally
Jifty's static root. Returns undef if it can't find the file in any
path.
An alias for file_path.
Returns the mime type of the file whose path on disk is $path. Tries to use
MIME::Types to guess first. If that fails, it falls back to File::MMagic.
Print $path to STDOUT (the client), identified with a mimetype of $mimetype.
Sends appropriate cache control and expiration headers such that the client will cache the content. COMPRESSION is deprecated
Sends a "304 Not modified" response to the browser, telling it to use a cached copy.
| Jifty documentation | Contained in the Jifty distribution. |
use warnings; use strict; use File::MMagic (); use MIME::Types (); use HTTP::Date (); package Jifty::View::Static::Handler; use base qw/Jifty::View/; our ($MIME,$MAGIC);
sub new { my $class = shift; my @roots = (Jifty->config->framework('Web')->{StaticRoot}); my %seen; $seen{$_} = 1 for map Jifty->config->framework('Web')->{$_}, qw/StaticRoot DefaultStaticRoot/; for my $plugin ( Jifty->plugins ) { for my $root ($plugin->static_root) { next unless ( defined $root and -d $root and -r $root and not $seen{$root}++); push @roots, $root; $plugin->log->debug( "Plugin @{[ref($plugin)]} static root added: (@{[$root ||'']})"); } } push @roots, (Jifty->config->framework('Web')->{DefaultStaticRoot}); return bless { roots => \@roots }, $class; }
sub roots { my $self = shift; return wantarray ? @{$self->{roots}} : $self->{roots}; }
sub show { shift->handle_request(@_); } sub handle_request { my $self = shift; my $path = shift; my $local_path = $self->file_path($path) or return undef; if ( my $since = Jifty->web->request->header('If-Modified-Since') ) { my @file_info = stat($local_path); # IE appends "; length=N" to If-Modified-Since headers and we need # to get rid of it so str2time doesn't choke below $since =~ s/;.+$//; return $self->send_not_modified unless $file_info[9] > HTTP::Date::str2time($since); } return $self->send_file($local_path, $self->mime_type($local_path)); }
sub template_exists { my $class = shift; my $template = shift; return $template if $class->file_path($template); return undef; } sub file_path { my $self = shift; my $file = shift; # Chomp a leading "/static" - should this be configurable? $file =~ s/^\/*?static//; foreach my $path ( $self->roots ) { my $abspath = Jifty::Util->absolute_path( File::Spec->catdir($path,$file )); # If the user is trying to request something outside our static root, # decline the request my $abs_base_path = Jifty::Util->absolute_path( $path ); unless ($abspath =~ /^\Q$abs_base_path\E/) { return undef; } return $abspath if ( -f $abspath && -r $abspath ); } return undef; }
sub mime_type { my $self = shift; my $local_path = shift; # The key is the file extension, the value is the MIME type to send. my %type_override = ( 'json' => 'application/json; charset=UTF-8', 'htc' => 'text/x-component', ); return ($type_override{$1}) if $local_path =~ /^.*\.(.+?)$/ and defined $type_override{$1}; # Defer initialization to first use. (It's not actually cheap) $MIME ||= MIME::Types->new(); $MAGIC ||= File::MMagic->new(); my $mimeobj = $MIME->mimeTypeOf($local_path); my $mime_type = ( $mimeobj ? $mimeobj->type : $MAGIC->checktype_filename($local_path)); return ($mime_type); }
sub send_file { my $self = shift; my $local_path = shift; my $mime_type = shift; my $fh = IO::File->new( $local_path, 'r' ); if ( defined $fh ) { binmode $fh; # This is designed to work under CGI or FastCGI; will need an # abstraction for mod_perl # Clear out the mason output, if any Jifty->web->mason->clear_buffer if Jifty->web->mason; my @file_info = stat($local_path); Jifty->web->response->content_type($mime_type); $self->send_http_header( '', $file_info[7], $file_info[9] ); Jifty->web->response->content($fh); return 1; } else { return undef; } }
sub send_http_header { my $self = shift; my (undef, $length, $modified) = @_; my $now = time(); my $response = Jifty->web->response; # Expire in a year $response->header( 'Cache-Control' => 'max-age=31536000, public' ); $response->header( 'Expires' => HTTP::Date::time2str( $now + 31536000 ) ); $response->header( 'Content-Length' => $length ) if $length; $response->header( 'Last-Modified' => HTTP::Date::time2str( $modified ) ) if $modified; }
sub send_not_modified { my $self = shift; my $response = Jifty->web->response; $response->status( 304 ); return 1; } 1;