Bivio::Biz::Action::LocalFilePlain
# Copyright (c) 1999-2011 bivio Software, Inc. All rights reserved. # $Id$ package Bivio::Biz::Action::LocalFilePlain; use strict; use Bivio::Base 'Biz.Action'; b_use('IO.ClassLoaderAUTOLOAD'); my($_MAX_AGE) = 3600; my($_TAGGED_MAX_AGE) = 60 * 60 * 24 * 365; our($_TRACE); b_use('IO.Trace'); my($_T) = b_use('MIME.Type'); my($_FCC) = b_use('FacadeComponent.Constant'); my($_IOC) = b_use('IO.Config'); my($_FCT) = b_use('FacadeComponent.Text'); my($_F) = b_use('UI.Facade'); my($_PLAIN) = b_use('UI.LocalFileType')->PLAIN; my($_DT) = b_use('Type.DateTime'); sub execute { my($proto, $req, $file_name, $content_type) = @_; $file_name = $req->get('uri') unless defined($file_name); my($tagged) = 0; if (Type_CacheTagFilePath()->is_tagged_path($file_name)) { $file_name = Type_CacheTagFilePath()->to_untagged_path($file_name); $tagged = 1; } else { _trace($file_name, ': missing cache tag') if $_TRACE; } my($mime_type); $proto->set_cacheable_output( _open($req, $file_name, \$mime_type), defined($content_type) ? $content_type : $mime_type, $req, $tagged, ); return 1; } sub execute_apple_touch_icon { my($proto, $req) = @_; my($file_name) = $_FCT->get_value('apple_touch_icon_prefix', $req); b_die('invalid apple touch uri: ', $req->get('uri')) unless $req->get('uri') =~ m,/apple-touch-icon(.*?\.png)$,; my($suffix) = $1; my($res); my($die) = Bivio::Die->catch_quietly( sub { $res = $proto->execute($req, $file_name . $suffix); }, ); if ($die) { # avoid warning in logs return 'DEFAULT_ERROR_REDIRECT_NOT_FOUND' if $die->unsafe_get('code') && $die->get('code')->eq_not_found; $die->throw; } return $res; } sub execute_favicon { my($proto, $req) = @_; return $proto->execute($req, $_FCT->get_value('favicon_uri', $req)); } sub execute_robots_txt { my($proto, $req) = @_; my($disallow) = $req->get('is_production') && $_FCC->get_value('robots_txt_allow_all', $req) ? '' : ' /'; $proto->set_cacheable_output(\(<<"EOF"), 'text/plain', $req); User-agent: * Disallow:$disallow EOF return 1; } sub execute_uri_as_view { my($proto, $req) = @_; return b_use('UI.View')->execute( $_FCC->get_value('view_execute_uri_prefix', $req) . '/' . $req->get('uri'), $req); } sub set_cacheable_output { my(undef, $output, $mime_type, $req, $never_expire) = @_; return $req->get('reply') ->set_output($output) ->set_output_type($mime_type) ->set_cache_max_age( $never_expire ? $_TAGGED_MAX_AGE : $_MAX_AGE, $req, $never_expire, ); } sub _open { # (Agent.Request, string, string_ref) : file_handle # Opens the file_name on the request as a document or throws NOT_FOUND my($req, $file_name, $mime_type) = @_; my($doc) = $_F->get_local_file_name($_PLAIN, $file_name, $req); # No files which begin with '.' or contain VC are allowed if ($file_name =~ /\/\./ || $file_name =~ b_use('Util.VC')->CONTROL_DIR_RE) { _trace($doc, ': invalid name') if $_TRACE; } else { $$mime_type = $_T->from_extension($doc); if (my $fh = IO::File->new('< ' . $doc)) { _trace($doc, ': opened') if $_TRACE; $$mime_type = 'text/plain' if $$mime_type eq 'application/octet-stream' && -T $doc; return $fh; } _trace('open(', $doc, "): $!") if $_TRACE; } $req->throw_die('NOT_FOUND', {entity => $doc}); # DOES NOT RETURN } 1;