Apache2-SSI
view release on metacpan or search on metacpan
lib/Apache2/SSI.pm view on Meta::CPAN
our $ATTRIBUTES_RE = qr/
(
(?<tag_attr>
(?:
[[:blank:]\h]*
(?<attr_name>[\w\-]+)
[[:blank:]\h]*
=
[[:blank:]\h]*
# (?<!\\)(?<attr_val>[^\"\'[:blank:]\h]+)
# (?:(?<!\")|(?<!\'))(?<attr_val>[^[:blank:]\h]+)
(?!["'])(?<attr_val>[^[:blank:]\h]+)
[[:blank:]\h]*
)
|
(?:
[[:blank:]\h]*
(?<attr_name>[\w\-]+)
[[:blank:]\h]*
=
[[:blank:]\h]*
(?<quote>(?<quote_double>\")|(?<quote_single>\'))
(?(<quote_double>)
(?<attr_val>(?>\\"|[^"])*+)
|
(?<attr_val>(?>\\'|[^'])*+)
)
# (?>\\["']|[^"'])*+
\g{quote}
[[:blank:]\h]*
)
)
)
/xsm;
our $EXPR_RE = qr/
(?<tag_attr>
\b(?<attr_name>expr)
[[:blank:]\h]*\=
(?:
(?:
(?!["'])(?<attr_val>[^[:blank:]\h]+)
[[:blank:]\h]*
)
|
(?:
[[:blank:]\h]*
(?<quote>(?<quote_double>\")|(?<quote_single>\'))
(?(<quote_double>)
(?<attr_val>(?>\\"|[^"])*+)
|
(?<attr_val>(?>\\'|[^'])*+)
)
\g{quote}
[[:blank:]\h]*
)
)
)
/xsmi;
our $SUPPORTED_FUNCTIONS = qr/(base64|env|escape|http|ldap|md5|note|osenv|replace|req|reqenv|req_novary|resp|sha1|tolower|toupper|unbase64|unescape)/i;
our $FUNCTION_PARAMETERS_RE = qr/
[[:blank:]\h]* # Some possible leading blanks
(?:
(?:
(?<func_quote>(?<func_quote_2>\")|(?<func_quote_1>\')) # quotes used to enclose function parameters
(?(<func_quote_2>)
(?<func_params>(?>\\"|[^"])*+)
|
(?<func_params>(?>\\'|[^'])*+)
)
\g{func_quote}
)
|
(?<func_params>(?>\\\)|[^\)\}])*+) # parameters not surounded by quotes
)
[[:blank:]\h]* # Some possible trailing blanks
/xsm;
our $IS_UTF8 = qr/
^(
([\0-\x7F])
|
([\xC2-\xDF][\x80-\xBF])
|
(
(
([\xE0][\xA0-\xBF])
|
([\xE1-\xEC\xEE-\xEF][\x80-\xBF])
|
([\xED][\x80-\x9F])
)
[\x80-\xBF]
)
|
(
(
([\xF0][\x90-\xBF])
|
([\xF1-\xF3][\x80-\xBF])
|
([\xF4][\x80-\x8F])
)
[\x80-\xBF][\x80-\xBF]
)
)*$
/x;
}
# PerlResponseHandler
sub handler : method
{
if( Scalar::Util::blessed( $_[1] ) && $_[1]->isa( 'Apache2::Filter' ) )
{
return( &apache_filter_handler( @_ ) );
}
else
{
return( &apache_response_handler( @_ ) );
}
lib/Apache2/SSI.pm view on Meta::CPAN
@$params{ @copy } = @$self{ @copy };
$params->{apache_filter} = $self->apache_filter if( $self->apache_filter );
$params->{apache_request} = $self->apache_request if( $self->apache_request );
$params->{document_uri} = $self->uri->document_uri;
$params->{document_root} = $self->document_root;
my $new = $class->new( %$params ) || return( $self->error( "Unable to create a clone of our object: ", $class->error ) );
return( $new );
}
sub decode_base64
{
my $self = shift( @_ );
local $@;
# try-catch
my $rv = eval
{
my $v = join( '', @_ );
if( $self->mod_perl )
{
$v = APR::Base64::decode( $v );
}
else
{
require MIME::Base64;
$v = MIME::Base64::decode( $v );
}
$v = Encode::decode( 'utf8', $v ) if( $self->_has_utf8( $v ) );
return( $v );
};
if( $@ )
{
return( $self->error( "Error while decoding base64 data: $@" ) );
}
return( $rv );
}
sub decode_entities
{
my $self = shift( @_ );
local $@;
# try-catch
my $rv = eval
{
return( HTML::Entities::decode_entities( @_ ) );
};
if( $@ )
{
return( $self->error( "Error while decoding html entities data: $@" ) );
}
return( $rv );
}
sub decode_uri
{
my $self = shift( @_ );
local $@;
# try-catch
my $rv = eval
{
require URI::Escape::XS;
return( URI::Escape::XS::uri_unescape( @_ ) );
};
if( $@ )
{
return( $self->error( "Error while decoding uri: $@" ) );
}
return( $rv );
}
sub decode_url
{
my $self = shift( @_ );
local $@;
# try-catch
my $rv = eval
{
if( $self->mod_perl )
{
return( Encode::decode( 'utf8', APR::Request::decode( @_ ), Encode::FB_CROAK ) );
}
else
{
# Will use XS version automatically
require URL::Encode;
return( URL::Encode::url_decode_utf8( @_ ) );
}
};
if( $@ )
{
return( $self->error( "Error while url decoding data: $@" ) );
}
return( $rv );
}
sub document_filename { return( shift->uri->filename( @_ ) ); }
sub document_path { return( shift->uri->document_path( @_ ) ); }
sub document_root
{
my $self = shift( @_ );
my $r = $self->apache_request;
if( $r )
{
$r->document_root( @_ ) if( @_ );
return( $r->document_root );
}
else
{
if( @_ )
{
$self->{document_root} = shift( @_ );
$self->_set_env( DOCUMENT_ROOT => $self->{document_root} );
}
return( $self->{document_root} || $self->env( 'DOCUMENT_ROOT' ) );
}
}
# A document uri is an absolute uri possibly with some path info and query string.
sub document_uri { return( shift->uri->document_uri( @_ ) ); }
lib/Apache2/SSI.pm view on Meta::CPAN
if( $self->mod_perl )
{
return( APR::Base64::encode( $v ) );
}
else
{
require MIME::Base64;
return( MIME::Base64::encode( $v, '' ) );
}
};
if( $@ )
{
return( $self->error( "Error while encoding data into base64: $@" ) );
}
return( $rv );
}
sub encode_entities
{
my $self = shift( @_ );
local $@;
# try-catch
my $rv = eval
{
return( HTML::Entities::encode_entities( join( '', @_ ) ) );
};
if( $@ )
{
return( $self->error( "Error while encoding data into html entities: $@" ) );
}
return( $rv );
}
sub encode_md5
{
my $self = shift( @_ );
local $@;
# try-catch
my $rv = eval
{
require Digest::MD5;
my $v = join( '', @_ );
$v = Encode::encode( 'utf8', $v, Encode::FB_CROAK ) if( Encode::is_utf8( $v ) );
return( Digest::MD5::md5_hex( $v ) );
};
if( $@ )
{
return( $self->error( "Error while encoding data into md5 hex: $@" ) );
}
return( $rv );
}
sub encode_uri
{
my $self = shift( @_ );
local $@;
# try-catch
my $rv = eval
{
require URI::Escape::XS;
# return( URI::Escape::uri_escape_utf8( join( '', @_ ) ) );
return( URI::Escape::XS::uri_escape( join( '', @_ ) ) );
};
if( $@ )
{
return( $self->error( "Error while encoding uri: $@" ) );
}
return( $rv );
}
sub encode_url
{
my $self = shift( @_ );
local $@;
# try-catch
my $rv = eval
{
if( $self->mod_perl )
{
my $v = Encode::encode( 'utf8', join( '', @_ ), Encode::FB_CROAK );
return( APR::Request::encode( $v ) );
}
else
{
# Will use XS version automatically
require URL::Encode;
return( URL::Encode::url_encode_utf8( join( '', @_ ) ) );
}
};
if( $@ )
{
return( $self->error( "Error while url encoding data: $@" ) );
}
return( $rv );
}
sub env
{
my $self = shift( @_ );
# The user wants the entire hash reference
unless( @_ )
{
my $r = $self->apache_request;
if( $r )
{
$r = $r->is_initial_req ? $r : $r->main ? $r->main : $r;
return( $r->subprocess_env )
}
else
{
unless( ref( $self->{_env} ) )
{
$self->{_env} = {%ENV};
}
return( $self->{_env} );
}
}
my $name = shift( @_ );
return( $self->error( "No environment variable name was provided." ) ) if( !length( $name ) );
my $opts = {};
if( scalar( @_ ) )
{
lib/Apache2/SSI.pm view on Meta::CPAN
my $r = $self->apache_request;
my $env = $self->env;
foreach my $this ( @$args )
{
my $res = $self->ap2perl_expr( $this, [] );
push( @$buff, @$res ) if( $res );
}
return( join( ', ', @$buff ) );
}
sub parse_flastmod
{
my( $self, $args ) = @_;
my $p = $self->find_file( $args );
unless( $p->code == 200 )
{
return( $self->errmsg );
}
return( $self->_lastmod( $p, $args->{timefmt} || $self->{timefmt} ) );
}
sub parse_fsize
{
my( $self, $args ) = @_;
my $f = $self->find_file( $args );
unless( $f->code == 200 )
{
return( $self->errmsg );
}
my $finfo = $f->finfo;
my $size = $finfo->size;
my $n = Module::Generic::Number->new( $size );
if( $self->{sizefmt} eq 'bytes' )
{
# Not everyone is using a comma as thousand separator
# 1 while( $size =~ s/^(\d+)(\d{3})/$1,$2/g );
# return( $size );
my $str = $n->format( 0 )->scalar;
undef( $n );
return( '' ) if( !defined( $str ) );
return( $str );
}
elsif( $self->{sizefmt} eq 'abbrev' )
{
return( $size ) if( $size < 1024 );
my $n = Module::Generic::Number->new( $size );
my $str = $n->format_bytes->scalar;
undef( $n );
return( '' ) if( !defined( $str ) );
return( $str );
}
else
{
$self->error( "Unrecognized size format '$self->{sizefmt}'" );
return( $self->errmsg );
}
}
# Functions
# See https://httpd.apache.org/docs/trunk/en/expr.html#page-header
# base64|env|escape|http|ldap|md5|note|osenv|replace|req|reqenv|req_novary|resp|sha1|tolower|toupper|unbase64|unescape
sub parse_func_base64 { return( shift->encode_base64( join( '', @_ ) ) ); }
# Return first match of note, reqenv, osenv
sub parse_func_env
{
my $self = shift( @_ );
my $var = shift( @_ );
my $r = $self->apache_request;
my $env = $self->env;
if( $r )
{
local $@;
# try-catch
my $rv = eval
{
return( $r->subprocess_env( $var ) || $env->{ $var } || $self->notes( $var ) );
};
if( $@ )
{
return( $self->error( "An error occurred trying to get the environment value for variable \"${var}\": $@" ) );
}
return( $rv );
}
else
{
return( $env->{ $var } || $self->notes( $var ) );
}
}
sub parse_func_escape { return( shift->encode_uri( join( '', @_ ) ) ); }
sub parse_func_http
{
my $self = shift( @_ );
my $header_name = shift( @_ );
my $r = $self->apache_request;
if( $r )
{
my $headers = $r->headers_in;
return( $headers->{ $header_name } );
}
# No http header outside of Apache
else
{
my $env = $self->env;
return( $env->{ $header_name } ) if( length( $env->{ $header_name } ) );
my $name = $header_name =~ tr/-/_/;
return( $env->{"HTTP_\U${name}\E"} ) if( length( $env->{"HTTP_\U${name}\E"} ) );
return( $env->{ uc( $name ) } ) if( length( $env->{ uc( $name ) } ) );
return( '' );
}
}
# Apache documentation: "Escape characters as required by LDAP distinguished name escaping (RFC4514) and LDAP filter escaping (RFC4515)"
# Taken from Net::LDAP::Util
sub parse_func_ldap
{
my $self = shift( @_ );
my $val = join( '', @_ );
$val =~ s/([\x00-\x1F\*\(\)\\])/'\\' . unpack( 'H2', $1 )/oge;
return( $val );
}
sub parse_func_md5 { return( shift->encode_md5( @_ ) ); }
# Notes are stored in the ENV global hash so they can be shared across processes
sub parse_func_note
{
my $self = shift( @_ );
my $var = shift( @_ );
return( $self->notes( $var ) );
}
# Essentially same as parse_func_note
sub parse_func_osenv
{
my $self = shift( @_ );
my $var = shift( @_ );
return( $ENV{ $var } );
}
sub parse_func_replace
{
my $self = shift( @_ );
my( $str, $what, $with ) = @_;
$str =~ s/$what/$with/g;
return( $str );
}
sub parse_func_req { return( shift->parse_func_http( @_ ) ); }
sub parse_func_reqenv
{
my $self = shift( @_ );
my $var = shift( @_ );
my $r = $self->apache_request;
if( $r )
{
return( $r->subprocess_env( $var ) );
}
else
{
my $env = $self->env;
return( $env->{ $var } );
}
}
sub parse_func_req_novary { return( shift->parse_func_http( @_ ) ); }
sub parse_func_resp
{
my $self = shift( @_ );
my $header_name = shift( @_ );
my $r = $self->apache_request;
if( $r )
{
my $headers = $r->headers_out;
return( $headers->{ $header_name } );
}
# No http header outside of Apache
else
{
return( '' );
}
}
sub parse_func_sha1
{
my $self = shift( @_ );
my $val = join( '', @_ );
require Digest::SHA;
return( Digest::SHA::sha1_hex( $val ) );
}
sub parse_func_tolower
{
my $self = shift( @_ );
return( lc( join( '', @_ ) ) );
}
sub parse_func_toupper
{
my $self = shift( @_ );
return( uc( join( '', @_ ) ) );
}
sub parse_func_unbase64 { return( shift->decode_base64( join( '', @_ ) ) ); }
sub parse_func_unescape { return( shift->decode_uri( join( '', @_ ) ) ); }
sub parse_if
{
my( $self, $args ) = @_;
unshift( @{$self->{if_state}}, 0 );
unshift( @{$self->{suspend}}, $self->{suspend}->[0] );
return( '' ) if( $self->{suspend}->[0] );
return( $self->_handle_ifs( $self->parse_eval_expr( $args->{expr} ) ) );
}
sub parse_include
{
my( $self, $args ) = @_;
unless( exists( $args->{file} ) or exists( $args->{virtual} ) )
{
return( $self->error( "No 'file' or 'virtual' attribute found in SSI 'include' tag" ) );
}
my $f = $self->find_file( $args );
unless( $f->code == 200 )
{
return( $self->errmsg );
}
my $filename = $f->filename;
if( !-e( "$filename" ) )
{
return( $self->errmsg );
}
# TODO This needs to be improved, as we should not assume the file encoding is utf8
# It could be binary or some other text encoding like iso-2022-jp
# So we should slurp it, parse the meta tags if this is an html and decode if the charset attribute is set or default to utf8
# But this complicates things quite a bit, so for now, it is just utf8 simply
my $html = $f->slurp_utf8;
if( !defined( $html ) )
{
$self->error( "Unable to get html data of included file \"", $f->filename, "\": ", $f->error );
return( $self->errmsg );
}
my $clone = $self->clone || do
{
warn( $self->error );
return( $self->errmsg );
};
# share our environment variables with our clone so we pass it to included files.
# If we are running under mod_perl, we'll use subprocess_env
my $env = $self->env;
$clone->{_env} = $env;
return( $clone->parse( $html ) );
}
# NOTE: Legacy
# http://perl.apache.org/docs/1.0/guide/snippets.html#Passing_Arguments_to_a_SSI_script
sub parse_perl
{
my( $self, $args, $margs ) = @_;
my $r = $self->apache_request;
my( $pass_r, @arg1, @arg2, $sub ) = (1);
{
my @a;
lib/Apache2/SSI.pm view on Meta::CPAN
This method is used to convert Apache2 expressions into perl equivalents to be then eval'ed.
It takes an hash reference provided by L<Apache2::Expression/parse>, an array reference to store the output recursively and an optional hash reference of parameters.
It parse recursively the structure provided in the hash reference to provide the perl equivalent for each Apache2 expression component.
It returns the array reference provided as the content buffer. This array is used by L</parse_expr> and then joined using a single space to form a string of perl expression to be eval'ed.
=head2 apache_filter
Set or get the L<Apache2::Filter> object.
When running under Apache mod_perl this is set automatically from the special L</handler> method.
=head2 apache_filter_handler
This method is called from L</handler> to handle the Apache response when this module L<Apache2::SSI> is used as a filter handler.
See also L</apache_response_handler>
=head2 apache_request
Sets or gets the L<Apache2::RequestRec> object. As explained in the L</new> method, you can get this Apache object by requiring the package L<Apache2::RequestUtil> and calling L<Apache2::RequestUtil/request> such as C<Apache2::RequestUtil->request> a...
When running under Apache mod_perl this is set automatically from the special L</handler> method, such as:
my $r = $f->r; # $f is the Apache2::Filter object provided by Apache
=head2 apache_response_handler
This method is called from L</handler> to handle the Apache response when this module L<Apache2::SSI> is used as a response handler.
See also L</apache_filter_handler>
=head2 clone
Create a clone of the object and return it.
=head2 decode_base64
Decode base64 data provided. When running under Apache mod_perl, this uses L<APR::Base64/decode> module, otherwise it uses L<MIME::Base64/decode>
If the decoded data contain utf8 data, this will decode the utf8 data using L<Encode/decode>
If an error occurred during decoding, it will return undef and set an L</error> object accordingly.
=head2 decode_entities
Decode html data containing entities. This uses L<HTML::Entities/decode_entities>
If an error occurred during decoding, it will return undef and set an L</error> object accordingly.
Example:
$ssi->decode_entities( 'Tous les êtres humains naissent libres et égaux en dignité et en droits.' );
# Tous les êtres humains naissent libres et égaux en dignité et en droits.
=head2 decode_uri
Decode uri encoded data. This uses L<URI::Escape/uri_unescape>.
Not to be confused with x-www-form-urlencoded data. For that see L</decode_url>
If an error occurred during decoding, it will return undef and set an L</error> object accordingly.
Example:
$ssi->decode_uri( 'https%3A%2F%2Fwww.example.com%2F' );
# https://www.example.com/
=head2 decode_url
Decode x-www-form-urlencoded encoded data. When using Apache mod_perl, this uses L<APR::Request/decode> and L<Encode/decode>, otherwise it uses L<URL::Encode/url_decode_utf8> (its XS version) to achieve the same result.
If an error occurred during decoding, it will return undef and set an L</error> object accordingly.
Example:
$ssi->decode_url( 'Tous+les+%C3%83%C2%AAtres+humains+naissent+libres+et+%C3%83%C2%A9gaux+en+dignit%C3%83%C2%A9+et+en+droits.' );
# Tous les êtres humains naissent libres et égaux en dignité et en droits.
=head2 document_filename
This is an alias for L<Apache2::SSI::URI/filename>
=head2 document_directory
Returns an L<Apache2::SSI::URI> object of the current directory of the L</document_uri> provided.
=head2 document_path
Sets or gets the uri path to the document. This is the same as L</document_uri>, except it is striped from L</query_string> and L</path_info>.
=head2 document_root
Sets or gets the document root.
Wen running under Apache mod_perl, this value will be available automatically, using L<Apache2::RequestRec/document_root> method.
If it runs outside of Apache, this will use the value provided upon instantiating the object and passing the C<document_root> parameter. If this is not set, it will return the value of the environment variable C<DOCUMENT_ROOT>.
=head2 document_uri
Sets or gets the document uri, which is the uri of the document being processed.
For example:
/index.html
Under Apache, this will get the environment variable C<DOCUMENT_URI> or calls the L<Apache2::RequestRec/uri> method.
Outside of Apache, this will rely on a value being provided upon instantiating an object, or the environment variable C<DOCUMENT_URI> be present.
The value should be an absolute uri.
=head2 echomsg
The default message to be returned for the C<echo> command when the variable called is not defined.
Example:
$ssi->echomsg( '[Value Undefined]' );
# or in the document itself
<!--#config echomsg="[Value Undefined]" -->
<!--#echo var="NON_EXISTING" encoding="none" -->
would produce:
[Value Undefined]
=head2 encode_base64
Encode data provided into base64. When running under Apache mod_perl, this uses L<APR::Base64/encode> module, otherwise it uses L<MIME::Base64/encode>
If the data have the perl internal utf8 flag on as checked with L<Encode/is_utf8>, this will encode the data into utf8 using L<Encode/encode> before encoding it into base64.
Please note that the base64 encoded resulting data is all on one line, similar to what Apache would do. The data is B<NOT> broken into lines of 76 characters.
If an error occurred during encoding, it will return undef and set an L</error> object accordingly.
=head2 encode_entities
Encode data into html entities. This uses L<HTML::Entities/encode_entities>
If an error occurred during encoding, it will return undef and set an L</error> object accordingly.
Example:
$ssi->encode_entities( 'Tous les êtres humains naissent libres et égaux en dignité et en droits.' );
# Tous les êtres humains naissent libres et égaux en dignité et en droits.
=head2 encode_md5
Encode data provided into md5. This uses L<Digest::MD5> which it will attempt to load.
=head2 encode_uri
Encode uri data. This uses L<URI::Escape::XS/uri_escape>.
Not to be confused with x-www-form-urlencoded data. For that see L</encode_url>
If an error occurred during encoding, it will return undef and set an L</error> object accordingly.
Example:
$ssi->encode_uri( 'https://www.example.com/' );
# https%3A%2F%2Fwww.example.com%2F
=head2 encode_url
Encode data provided into an x-www-form-urlencoded string. When using Apache mod_perl, this uses L<APR::Request/encode>, otherwise it uses L<URL::Encode/url_encode_utf8> (its XS version)
If an error occurred during decoding, it will return undef and set an L</error> object accordingly.
Example:
$ssi->encode_url( 'Tous les êtres humains naissent libres et égaux en dignité et en droits.' );
# Tous+les+%C3%83%C2%AAtres+humains+naissent+libres+et+%C3%83%C2%A9gaux+en+dignit%C3%83%C2%A9+et+en+droits.
=head2 env
Sets or gets the value for an environment variable. Or, if no environment variable name is provided, it returns the entire hash reference. This method is intended to be used by users of this module, not by developers wanting to inherit from it.
Note that the environment variable hash is unique for each new object, so it works like L<Apache2::RequestRec/subprocess_env>, meaning each process has its set of environment variable.
When a value is set for an environment variable that has an equivalent name, it will call the method as well with the new value provided. This is done to ensure data consistency and also additional processing if necessary.
For example, let's assume you set the environment variable C<REQUEST_URI> or C<DOCUMENT_URI> like this:
$ssi->env( REQUEST_URI => '/some/path/to/file.html?q=something&l=ja_JP' );
This will, in turn, call L</request_uri>, which is an alias for L<document_uri> and this method will get the uri, path info and query string from the value provided and set those values accordingly, so they can be available when parsing.
=head2 errmsg
Sets or gets the error message to be displayed in lieu of a faulty ssi directive. This is the same behaviour as in Apache.
=head2 error
Retrieve the error object set. This is a L<Module::Generic::Error> object.
This module does not die nor "croak", but instead returns undef when an error occurs and set the error object.
It is up to you to check the return value of the method calls. If you do not, you will miss important information. If you really want your script to die, it is up to you to interrupt it:
if( !defined( $ssi->parse( $some_html_data ) ) )
{
die( $ssi->error );
}
or maybe more simply, when you are sure you will not get a false, but defined value:
$ssi->parse( $some_html_data ) || die( $ssi->error );
This example is dangerous, because L</parse> might return an empty string which will be construed as a false value and will trigger the die statement, even though no error had occurred.
=head2 filename
lib/Apache2/SSI.pm view on Meta::CPAN
=head2 parse_flastmod
Process the ssi directive C<flastmod>
Provided with an hash reference of parameters and this will return the formatted date time of the file last modification time.
=head2 parse_fsize
Provided with an hash reference of parameters and this will return the formatted file size.
The output is affected by the value of L</sizefmt>. If its value is C<bytes>, it will return the raw size in bytes, and if its value is C<abbrev>, it will return its value formated in kilo, mega or giga units.
Example
<!--#config sizefmt="abbrev" -->
This file size is <!--#fsize file="/some/filesystem/path/to/archive.tar.gz" -->
would return:
This file size is 12.7M
Or:
<!--#config sizefmt="bytes" -->
This file size is <!--#fsize virtual="/some/filesystem/path/to/archive.tar.gz" -->
would return:
This file size is 13,316,917 bytes
The size value before formatting is a L<Module::Generic::Number> and the output is formatted using L<Number::Format> by calling L<Module::Generic::Number/format>
=head2 parse_func_base64
Returns the arguments provided into a base64 string.
If the arguments are utf8 data with perl internal flag on, as checked with L<Encode/is_utf8>, this will encode the data into utf8 with L<Encode/encode> before encoding it into base64.
Example:
<!--#set var="payload" value='{"sub":"1234567890","name":"John Doe","iat":1609047546}' encoding="base64" -->
<!--#if expr="$payload == 'eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNjA5MDQ3NTQ2fQo='" -->
Payload matches
<!--#else -->
Sorry, this failed
<!--#endif -->
=head2 parse_func_env
Return first match of L<note>, L<reqenv>, and L<osenv>
Example:
<!--#if expr="env( $QUERY_STRING ) == /\bl=ja_JP/" -->
Showing Japanese data
<!--#else -->
Defaulting to English
<!--#endif -->
=head2 parse_func_escape
Escape special characters in %hex encoding.
Example:
<!--#set var="website" value="https://www.example.com/" -->
Please go to <a href="<!--#echo var='website' encoding='escape' -->"><!--#echo var="website" --></a>
=head2 parse_func_http
Get HTTP request header; header names may be added to the Vary header.
Example:
<!--#if expr="http('X-API-ID') == 1234567" -->
You're good to go.
<!--#endif -->
However, outside of an Apache environment this will return the value of the environment variable in the following order:
=over 4
=item X-API-ID (i.e. the name as-is)
=item HTTP_X_API_ID (i.e. adding C<HTTP_> and replace C<-> for C<_>)
=item X_API_ID (i.e. same as above, but without the C<HTTP_> prefix)
=back
If none is found, it returns an empty string.
For an equivalent function for response headers, see L</parse_func_resp>
=head2 parse_func_ldap
Escape characters as required by LDAP distinguished name escaping (RFC4514) and LDAP filter escaping (RFC4515).
See L<Apache documentation|https://httpd.apache.org/docs/trunk/en/expr.html#page-header> for more information
Example:
<!--#set var="phrase" value="%{ldap:'Tous les êtres humains naissent libres (et égaux) en dignité et\ en\ droits.\n'}" -->
# Tous les êtres humains naissent libres \28et égaux\29 en dignité et\5c en\5c droits.\5cn
=head2 parse_func_md5
Hash the string using MD5, then encode the hash with hexadecimal encoding.
If the arguments are utf8 data with perl internal flag on, as checked with L<Encode/is_utf8>, this will encode the data into utf8 with L<Encode/encode> before encoding it with md5.
Example:
<!--#if expr="md5( $hash_data ) == '2f50e645b6ef04b5cfb76aed6de343eb'" -->
You're good to go.
<!--#endif -->
=head2 parse_func_note
Lookup request note
<!--#set var="CUSTOMER_ID" value="1234567" -->
<!--#if expr="note('CUSTOMER_ID') == 1234567" -->
Showing special message
<!--#endif -->
This uses L<Apache2::SSI::Notes> to enable notes to be shared on and off Apache2/mod_perl2 environment. Thus, you could set a note from a command-line perl script, and then access it under Apache2/mod_perl2 or just your regular script running under a...
lib/Apache2/SSI.pm view on Meta::CPAN
<!--#else -->
Nope, it failed.
<!--#endif -->
An important note here:
First, there is obviously no response header available for perl scripts running outside of Apache2/mod_perl2 framework.
If the script runs under mod_perl, not all response header will be available depending on whether you are using L<Apache2::SSI> in your Apache configuration as an output filter handler (C<PerlOutputFilterHandler>) or a response handler (C<PerlRespons...
If it is running as an output filter handler, then some headers, such as C<Content-Type> will not be available, unless they have been set by a script in a previous phase. Only basic headers will be available. For more information, check the Apache/mo...
=head2 parse_func_sha1
Hash the string using SHA1, then encode the hash with hexadecimal encoding.
Example:
<!--#if expr="sha1('Tous les êtres humains naissent libres et égaux en dignité et en droits.') == '8c244078c64a51e8924ecf646df968094a818d59'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->
=head2 parse_func_tolower
Convert string to lower case.
Example:
<!--#if expr="tolower('Tous les êtres humains naissent libres et égaux en dignité et en droits.') == 'tous les êtres humains naissent libres et égaux en dignité et en droits.'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->
=head2 parse_func_toupper
Convert string to upper case.
Example:
<!--#if expr="toupper('Tous les êtres humains naissent libres et égaux en dignité et en droits.') == 'TOUS LES ÃTRES HUMAINS NAISSENT LIBRES ET ÃGAUX EN DIGNITà ET EN DROITS.'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->
=head2 parse_func_unbase64
Decode base64 encoded string, return truncated string if 0x00 is found.
Example:
<!--#if expr="unbase64('VG91cyBsZXMgw6p0cmVzIGh1bWFpbnMgbmFpc3NlbnQgbGlicmVzIGV0IMOpZ2F1eCBlbiBkaWduaXTDqSBldCBlbiBkcm9pdHMu') == 'Tous les êtres humains naissent libres et égaux en dignité et en droits.'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->
=head2 parse_func_unescape
Unescape %hex encoded string, leaving encoded slashes alone; return empty string if %00 is found.
Example:
<!--#if expr="unescape('https%3A%2F%2Fwww.example.com%2F') == 'https://www.example.com/'" -->
This worked!
<!--#else -->
Nope, it failed.
<!--#endif -->
=head2 parse_if
Parse the C<if> condition.
See L</parse_elif> above for example.
=head2 parse_include
Provided with an hash reference of parameters and this process the ssi directive C<include>, which is arguably the most used.
It will try to resolve the file to include by calling L</find_file> with the same arguments this is called with.
Under Apache, if the previous look up succeeded, it calls L<Apache2::SubRequest/run>
Outside of Apache, it reads the entire file, utf8 decode it and return it.
=head2 parse_perl
Provided with an hash reference of parameters and this parse some perl command and returns the output as a string.
Example:
<!--#perl sub="sub{ print 'Hello!' }" -->
or
<!--#perl sub="package::subroutine" -->
=head2 parse_printenv
This returns a list of environment variables sorted and their values.
=head2 parse_set
Provided with an hash reference of parameters and this process the ssi directive C<set>.
Possible parameters are:
=over 4
=item C<decoding>
The decoding of the variable before it is set. This can be C<none>, C<url>, C<urlencoded>, C<base64> or C<entity>
=item C<encoding>
This instruct to encode the variable value before display. It can the same possible value as for decoding.
=item C<value>
The string value for the variable to be set.
=item C<var>
The variable name
lib/Apache2/SSI.pm view on Meta::CPAN
=head2 exec
# pwd is "print working directory" in shell
<!--#exec cmd="pwd" -->
<!--#exec cgi="/uri/path/to/prog.cgi" -->
=head2 include
# Filesystem file path
<!--#include file="/home/john/var/quote_of_the_day.txt" -->
# Relative to the document root
<!--#include virtual="/footer.html" -->
=head2 flastmod
<!--#flastmod file="/home/john/var/quote_of_the_day.txt" -->
<!--#flastmod virtual="/copyright.html" -->
=head2 fsize
<!--#fsize file="/download/software-v1.2.tgz" -->
<!--#fsize virtual="/images/logo.jpg" -->
=head2 printenv
<!--#printenv -->
=head2 set
<!--#set var="debug" value="2" -->
=head2 if, elif, endif and else
<!--#if expr="$debug > 1" -->
I will print a lot of debugging
<!--#else -->
Debugging output will be reasonable
<!--#endif -->
or with new version of Apache SSI:
No such file or directory.
<!--#if expr="v('HTTP_REFERER') != ''" -->
Please let the admin of the <a href="<!--#echo encoding="url" var="HTTP_REFERER" -->"referring site</a> know about their dead link.
<!--#endif -->
=head2 functions
Apache SSI supports the following functions, as of Apache version 2.4.
See L<Apache documentation|https://httpd.apache.org/docs/current/en/expr.html#page-header> for detailed description of what they do.
You can also refer to the methods C<parse_func_*> documented above, which implement those Apache functions.
=over 4
=item C<base64>
=item C<env>
=item C<escape>
=item C<http>
=item C<ldap>
=item C<md5>
=item C<note>
=item C<osenv>
=item C<replace>
=item C<req>
=item C<reqenv>
=item C<req_novary>
=item C<resp>
=item C<sha1>
=item C<tolower>
=item C<toupper>
=item C<unbase64>
=item C<unescape>
=back
=head2 variables
On top of all environment variables available, Apache makes the following ones also accessible:
=over 4
=item DATE_GMT
=item DATE_LOCAL
=item DOCUMENT_ARGS
=item DOCUMENT_NAME
=item DOCUMENT_PATH_INFO
=item DOCUMENT_URI
=item LAST_MODIFIED
=item QUERY_STRING_UNESCAPED
=item USER_NAME
=back
See L<Apache documentation|https://httpd.apache.org/docs/current/en/mod/mod_include.html#page-header> and L<this page too|https://httpd.apache.org/docs/current/en/expr.html#page-header> for more information.
=head2 expressions
There is reasonable, but limited support for Apache expressions. For example, the followings are supported
In the examples below, we use the variable C<QUERY_STRING>, but you can use any other variable of course.
The regular expression are the ones L<PCRE|http://www.pcre.org/> compliant, so your perl regular expressions should work.
<!--#if expr="$QUERY_STRING = 'something'" -->
<!--#if expr="v('QUERY_STRING') = 'something'" -->
<!--#if expr="%{QUERY_STRING} = 'something'" -->
<!--#if expr="$QUERY_STRING = /^something/" -->
<!--#if expr="$QUERY_STRING == /^something/" -->
# works also with eq, ne, lt, le, gt and ge
<!--#if expr="9 gt 3" -->
<!--#if expr="9 -gt 3" -->
# Other operators work too, namely == != < <= > >= =~ !~
<!--#if expr="9 > 3" -->
<!--#if expr="9 !> 3" -->
<!--#if expr="9 !gt 3" -->
# Checks the remote ip is part of this subnet
<!--#if expr="-R 192.168.2.0/24" -->
<!--#if expr="192.168.2.10 -R 192.168.2.0/24" -->
<!--#if expr="192.168.2.10 -ipmatch 192.168.2.0/24" -->
# Checks if variable is non-empty
<!--#if expr="-n $some_variable" -->
# Checks if variable is empty
<!--#if expr="-z $some_variable" -->
# Checks if the visitor can access the uri /restricted/uri
( run in 2.181 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )