| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | ##---------------------------------------------------------------------------- | 
| 2 |  |  |  |  |  |  | ## Apache2 Server Side Include Parser - ~/lib/Apache2/SSI/Common.pm | 
| 3 |  |  |  |  |  |  | ## Version v0.1.0 | 
| 4 |  |  |  |  |  |  | ## Copyright(c) 2021 DEGUEST Pte. Ltd. | 
| 5 |  |  |  |  |  |  | ## Author: Jacques Deguest <jack@deguest.jp> | 
| 6 |  |  |  |  |  |  | ## Created 2021/01/13 | 
| 7 |  |  |  |  |  |  | ## Modified 2021/01/13 | 
| 8 |  |  |  |  |  |  | ## All rights reserved | 
| 9 |  |  |  |  |  |  | ## | 
| 10 |  |  |  |  |  |  | ## This program is free software; you can redistribute  it  and/or  modify  it | 
| 11 |  |  |  |  |  |  | ## under the same terms as Perl itself. | 
| 12 |  |  |  |  |  |  | ##---------------------------------------------------------------------------- | 
| 13 |  |  |  |  |  |  | package Apache2::SSI::Common; | 
| 14 |  |  |  |  |  |  | BEGIN | 
| 15 |  |  |  |  |  |  | { | 
| 16 | 17 |  |  | 17 |  | 112506 | use strict; | 
|  | 17 |  |  |  |  | 45 |  | 
|  | 17 |  |  |  |  | 493 |  | 
| 17 | 17 |  |  | 17 |  | 77 | use warnings; | 
|  | 17 |  |  |  |  | 32 |  | 
|  | 17 |  |  |  |  | 459 |  | 
| 18 | 17 |  |  | 17 |  | 591 | use parent qw( Module::Generic ); | 
|  | 17 |  |  |  |  | 456 |  | 
|  | 17 |  |  |  |  | 91 |  | 
| 19 | 17 |  |  | 17 |  | 31148903 | use File::Spec (); | 
|  | 17 |  |  |  |  | 34 |  | 
|  | 17 |  |  |  |  | 279 |  | 
| 20 | 17 |  |  | 17 |  | 79 | use IO::File; | 
|  | 17 |  |  |  |  | 28 |  | 
|  | 17 |  |  |  |  | 2517 |  | 
| 21 | 17 |  |  | 17 |  | 105 | use Nice::Try; | 
|  | 17 |  |  |  |  | 33 |  | 
|  | 17 |  |  |  |  | 287 |  | 
| 22 | 17 |  |  | 17 |  | 5467873 | use Scalar::Util (); | 
|  | 17 |  |  |  |  | 40 |  | 
|  | 17 |  |  |  |  | 398 |  | 
| 23 | 17 |  |  | 17 |  | 2277 | use URI; | 
|  | 17 |  |  |  |  | 11245 |  | 
|  | 17 |  |  |  |  | 3409 |  | 
| 24 | 17 |  |  | 17 |  | 64 | our $VERSION = 'v0.1.0'; | 
| 25 |  |  |  |  |  |  | ## https://en.wikipedia.org/wiki/Path_(computing) | 
| 26 |  |  |  |  |  |  | ## perlport | 
| 27 | 17 |  |  |  |  | 584 | our $OS2SEP  = | 
| 28 |  |  |  |  |  |  | { | 
| 29 |  |  |  |  |  |  | amigaos     => '/', | 
| 30 |  |  |  |  |  |  | android     => '/', | 
| 31 |  |  |  |  |  |  | aix         => '/', | 
| 32 |  |  |  |  |  |  | bsdos       => '/', | 
| 33 |  |  |  |  |  |  | beos        => '/', | 
| 34 |  |  |  |  |  |  | bitrig      => '/', | 
| 35 |  |  |  |  |  |  | cygwin      => '/', | 
| 36 |  |  |  |  |  |  | darwin      => '/', | 
| 37 |  |  |  |  |  |  | dec_osf     => '/', | 
| 38 |  |  |  |  |  |  | dgux        => '/', | 
| 39 |  |  |  |  |  |  | dos         => "\\", | 
| 40 |  |  |  |  |  |  | dragonfly   => '/', | 
| 41 |  |  |  |  |  |  | dynixptx    => '/', | 
| 42 |  |  |  |  |  |  | freebsd     => '/', | 
| 43 |  |  |  |  |  |  | gnu         => '/', | 
| 44 |  |  |  |  |  |  | gnukfreebsd => '/', | 
| 45 |  |  |  |  |  |  | haiku       => '/', | 
| 46 |  |  |  |  |  |  | hpux        => '/', | 
| 47 |  |  |  |  |  |  | interix     => '/', | 
| 48 |  |  |  |  |  |  | iphoneos    => '/', | 
| 49 |  |  |  |  |  |  | irix        => '/', | 
| 50 |  |  |  |  |  |  | linux       => '/', | 
| 51 |  |  |  |  |  |  | machten     => '/', | 
| 52 |  |  |  |  |  |  | macos       => ':', | 
| 53 |  |  |  |  |  |  | midnightbsd => '/', | 
| 54 |  |  |  |  |  |  | minix       => '/', | 
| 55 |  |  |  |  |  |  | mirbsd      => '/', | 
| 56 |  |  |  |  |  |  | mswin32     => "\\", | 
| 57 |  |  |  |  |  |  | msys        => '/', | 
| 58 |  |  |  |  |  |  | netbsd      => '/', | 
| 59 |  |  |  |  |  |  | netware     => "\\", | 
| 60 |  |  |  |  |  |  | next        => '/', | 
| 61 |  |  |  |  |  |  | nto         => '/', | 
| 62 |  |  |  |  |  |  | openbsd     => '/', | 
| 63 |  |  |  |  |  |  | os2         => '/', | 
| 64 |  |  |  |  |  |  | ## Extended Binary Coded Decimal Interchange Code | 
| 65 |  |  |  |  |  |  | os390       => '/', | 
| 66 |  |  |  |  |  |  | os400       => '/', | 
| 67 |  |  |  |  |  |  | qnx         => '/', | 
| 68 |  |  |  |  |  |  | riscos      => '.', | 
| 69 |  |  |  |  |  |  | sco         => '/', | 
| 70 |  |  |  |  |  |  | sco_sv      => '/', | 
| 71 |  |  |  |  |  |  | solaris     => '/', | 
| 72 |  |  |  |  |  |  | sunos       => '/', | 
| 73 |  |  |  |  |  |  | svr4        => '/', | 
| 74 |  |  |  |  |  |  | svr5        => '/', | 
| 75 |  |  |  |  |  |  | symbian     => "\\", | 
| 76 |  |  |  |  |  |  | unicos      => '/', | 
| 77 |  |  |  |  |  |  | unicosmk    => '/', | 
| 78 |  |  |  |  |  |  | vms         => '/', | 
| 79 |  |  |  |  |  |  | vos         => '>', | 
| 80 |  |  |  |  |  |  | win32       => "\\", | 
| 81 |  |  |  |  |  |  | }; | 
| 82 | 17 |  |  |  |  | 8737 | our $DIR_SEP = $OS2SEP->{ lc( $^O ) }; | 
| 83 |  |  |  |  |  |  | }; | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | ## RFC 3986 section 5.2.4 | 
| 86 |  |  |  |  |  |  | ## This is aimed for web URI initially, but is also used for filesystems in a simple way | 
| 87 |  |  |  |  |  |  | sub collapse_dots | 
| 88 |  |  |  |  |  |  | { | 
| 89 | 481 |  |  | 481 | 1 | 7123 | my $self = shift( @_ ); | 
| 90 | 481 |  |  |  |  | 839 | my $path = shift( @_ ); | 
| 91 | 481 |  |  |  |  | 1589 | my $opts = $self->_get_args_as_hash( @_ ); | 
| 92 |  |  |  |  |  |  | ## To avoid warnings | 
| 93 | 481 |  | 100 |  |  | 6147 | $opts->{separator} //= ''; | 
| 94 |  |  |  |  |  |  | ## A path separator is provided when dealing with filesystem and not web URI | 
| 95 |  |  |  |  |  |  | ## We use this to know what to return and how to behave | 
| 96 | 481 | 100 |  |  |  | 1317 | my $sep  = length( $opts->{separator} ) ? $opts->{separator} : '/'; | 
| 97 | 481 | 50 |  |  |  | 1069 | return( '' ) if( !length( $path ) ); | 
| 98 | 481 | 100 |  |  |  | 2241 | my $u = $opts->{separator} ? URI::file->new( $path ) : URI->new( $path ); | 
| 99 | 481 |  |  |  |  | 34416 | my( @callinfo ) = caller; | 
| 100 | 481 |  |  |  |  | 2474 | $self->message( 4, "URI based on '$path' is '$u' (", overload::StrVal( $u ), ") and separator to be used is '$sep' and uri path is '", $u->path, "' called from $callinfo[0] in file $callinfo[1] at line $callinfo[2]." ); | 
| 101 | 481 | 100 |  |  |  | 20384 | $path = $opts->{separator} ? $u->file( $^O ) : $u->path; | 
| 102 | 481 |  |  |  |  | 24613 | my @new = (); | 
| 103 | 481 |  |  |  |  | 783 | my $len = length( $path ); | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | ## "If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer" | 
| 106 | 481 | 100 | 66 |  |  | 5075 | if( substr( $path, 0, 2 ) eq ".${sep}" ) | 
|  |  | 50 | 33 |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | { | 
| 108 | 1 |  |  |  |  | 4 | substr( $path, 0, 2 ) = ''; | 
| 109 |  |  |  |  |  |  | ## $self->message( 3, "Removed './'. Path is now '", substr( $path, 0 ), "'." ); | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  | elsif( substr( $path, 0, 3 ) eq "..${sep}" ) | 
| 112 |  |  |  |  |  |  | { | 
| 113 | 0 |  |  |  |  | 0 | substr( $path, 0, 3 ) = ''; | 
| 114 |  |  |  |  |  |  | } | 
| 115 |  |  |  |  |  |  | ## "if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer" | 
| 116 |  |  |  |  |  |  | elsif( substr( $path, 0, 3 ) eq "${sep}.${sep}" ) | 
| 117 |  |  |  |  |  |  | { | 
| 118 | 0 |  |  |  |  | 0 | substr( $path, 0, 3 ) = $sep; | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  | elsif( substr( $path, 0, 2 ) eq "${sep}." && 2 == $len ) | 
| 121 |  |  |  |  |  |  | { | 
| 122 | 0 |  |  |  |  | 0 | substr( $path, 0, 2 ) = $sep; | 
| 123 |  |  |  |  |  |  | } | 
| 124 |  |  |  |  |  |  | elsif( $path eq '..' || $path eq '.' ) | 
| 125 |  |  |  |  |  |  | { | 
| 126 | 0 |  |  |  |  | 0 | $path = ''; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  | elsif( $path eq $sep ) | 
| 129 |  |  |  |  |  |  | { | 
| 130 | 6 |  |  |  |  | 53 | return( $u ); | 
| 131 |  |  |  |  |  |  | } | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | ## -1 is used to ensure trailing blank entries do not get removed | 
| 134 | 475 |  |  |  |  | 7017 | my @segments = split( "\Q$sep\E", $path, -1 ); | 
| 135 | 475 |  |  | 0 |  | 3598 | $self->message( 3, "Found ", scalar( @segments ), " segments: ", sub{ $self->dump( \@segments ) } ); | 
|  | 0 |  |  |  |  | 0 |  | 
| 136 | 475 |  |  |  |  | 9714 | for( my $i = 0; $i < scalar( @segments ); $i++ ) | 
| 137 |  |  |  |  |  |  | { | 
| 138 | 2358 |  |  |  |  | 3125 | my $segment = $segments[$i]; | 
| 139 |  |  |  |  |  |  | ## "if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer" | 
| 140 | 2358 | 100 |  |  |  | 3817 | if( $segment eq '..' ) | 
|  |  | 100 |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | { | 
| 142 | 19 |  |  |  |  | 35 | pop( @new ); | 
| 143 |  |  |  |  |  |  | } | 
| 144 |  |  |  |  |  |  | elsif( $segment eq '.' ) | 
| 145 |  |  |  |  |  |  | { | 
| 146 | 2 |  |  |  |  | 4 | next; | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  | else | 
| 149 |  |  |  |  |  |  | { | 
| 150 | 2337 | 50 |  |  |  | 5200 | push( @new, ( defined( $segment ) ? $segment : '' ) ); | 
| 151 |  |  |  |  |  |  | } | 
| 152 |  |  |  |  |  |  | } | 
| 153 |  |  |  |  |  |  | ## Finally, the output buffer is returned as the result of remove_dot_segments. | 
| 154 | 475 |  |  |  |  | 1249 | my $new_path = join( $sep, @new ); | 
| 155 |  |  |  |  |  |  | # substr( $new_path, 0, 0 ) = $sep unless( substr( $new_path, 0, 1 ) eq '/' ); | 
| 156 | 475 | 100 |  |  |  | 3452 | substr( $new_path, 0, 0 ) = $sep unless( File::Spec->file_name_is_absolute( $new_path ) ); | 
| 157 | 475 |  |  |  |  | 1983 | $self->message( 4, "Adding back new path '$new_path' to uri '$u'." ); | 
| 158 | 475 | 100 |  |  |  | 9557 | if( $opts->{separator} ) | 
| 159 |  |  |  |  |  |  | { | 
| 160 | 156 |  |  |  |  | 580 | $u = URI::file->new( $new_path ); | 
| 161 |  |  |  |  |  |  | } | 
| 162 |  |  |  |  |  |  | else | 
| 163 |  |  |  |  |  |  | { | 
| 164 | 319 |  |  |  |  | 841 | $u->path( $new_path ); | 
| 165 |  |  |  |  |  |  | } | 
| 166 | 475 | 100 |  |  |  | 25614 | $self->message( 4, "Returning uri '$u' (", ( $opts->{separator} ? $u->file( $^O ) : 'same' ), ")." ); | 
| 167 | 475 |  |  |  |  | 33492 | return( $u ); | 
| 168 |  |  |  |  |  |  | } | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | ## Credits: Path::Tiny | 
| 171 |  |  |  |  |  |  | sub slurp | 
| 172 |  |  |  |  |  |  | { | 
| 173 | 58 |  |  | 58 | 1 | 137 | my $self = shift( @_ ); | 
| 174 | 58 |  |  |  |  | 105 | my $args = {}; | 
| 175 | 17 |  |  | 17 |  | 142 | no warnings 'uninitialized'; | 
|  | 17 |  |  |  |  | 38 |  | 
|  | 17 |  |  |  |  | 8685 |  | 
| 176 | 58 | 0 |  |  |  | 271 | $args = Scalar::Util::reftype( $_[0] ) eq 'HASH' | 
|  |  | 50 |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | ? shift( @_ ) | 
| 178 |  |  |  |  |  |  | : !( scalar( @_ ) % 2 ) | 
| 179 |  |  |  |  |  |  | ? { @_ } | 
| 180 |  |  |  |  |  |  | : {}; | 
| 181 | 58 |  | 0 |  |  | 202 | my $file = $args->{filename} || $args->{file} || $self->filename; | 
| 182 | 58 | 50 |  |  |  | 160 | return( $self->error( "No filename found." ) ) if( !length( $file ) ); | 
| 183 | 58 |  | 50 |  |  | 162 | my $binmode = $args->{binmode} // ''; | 
| 184 | 58 |  |  |  |  | 91 | try | 
| 185 | 58 |  |  | 58 |  | 90 | { | 
| 186 | 58 |  | 50 |  |  | 634 | my $fh = IO::File->new( "<$file" ) || | 
| 187 |  |  |  |  |  |  | return( $self->error( "Unable to open file \"$file\" in read mode: $!" ) ); | 
| 188 | 58 | 50 |  |  |  | 7356 | $fh->binmode( $binmode ) if( length( $binmode ) ); | 
| 189 | 58 |  |  |  |  | 840 | my $size; | 
| 190 | 58 | 50 | 33 |  |  | 338 | if( $binmode eq ':unix' && ( $size = -s( $fh ) ) ) | 
| 191 |  |  |  |  |  |  | { | 
| 192 | 0 |  |  |  |  | 0 | my $buf; | 
| 193 | 0 |  |  |  |  | 0 | $fh->read( $buf, $size ); | 
| 194 | 0 |  |  |  |  | 0 | return( $buf ); | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  | else | 
| 197 |  |  |  |  |  |  | { | 
| 198 | 58 |  |  |  |  | 259 | local $/; | 
| 199 | 58 |  |  |  |  | 2610 | return( scalar( <$fh> ) ); | 
| 200 |  |  |  |  |  |  | } | 
| 201 |  |  |  |  |  |  | } | 
| 202 | 58 | 50 |  |  |  | 467 | catch( $e ) | 
|  | 0 | 50 |  |  |  | 0 |  | 
|  | 58 | 50 |  |  |  | 153 |  | 
|  | 58 | 0 |  |  |  | 93 |  | 
|  | 58 | 50 |  |  |  | 133 |  | 
|  | 58 |  |  |  |  | 75 |  | 
|  | 58 |  |  |  |  | 90 |  | 
|  | 58 |  |  |  |  | 104 |  | 
|  | 58 |  |  |  |  | 215 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 58 |  |  |  |  | 133 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 58 |  |  |  |  | 346 |  | 
|  | 58 |  |  |  |  | 127 |  | 
|  | 58 |  |  |  |  | 145 |  | 
|  | 58 |  |  |  |  | 172 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
| 203 | 0 |  |  | 0 |  | 0 | { | 
| 204 | 0 |  |  |  |  | 0 | return( $self->error( "An error occured while trying to open and read file \"$file\": $e" ) ); | 
| 205 | 0 | 0 | 33 |  |  | 0 | } | 
|  | 0 | 0 | 33 |  |  | 0 |  | 
|  | 0 | 50 |  |  |  | 0 |  | 
|  | 0 | 50 |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 0 |  |  |  |  | 0 |  | 
|  | 58 |  |  |  |  | 519 |  | 
|  | 58 |  |  |  |  | 1338 |  | 
| 206 |  |  |  |  |  |  | } | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | sub slurp_utf8 | 
| 209 |  |  |  |  |  |  | { | 
| 210 | 58 |  |  | 58 | 1 | 468 | my $self = shift( @_ ); | 
| 211 | 58 |  |  |  |  | 99 | my $args = {}; | 
| 212 | 17 |  |  | 17 |  | 120 | no warnings 'uninitialized'; | 
|  | 17 |  |  |  |  | 37 |  | 
|  | 17 |  |  |  |  | 2059 |  | 
| 213 | 58 | 50 |  |  |  | 498 | $args = Scalar::Util::reftype( $_[0] ) eq 'HASH' | 
|  |  | 50 |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | ? shift( @_ ) | 
| 215 |  |  |  |  |  |  | : !( scalar( @_ ) % 2 ) | 
| 216 |  |  |  |  |  |  | ? { @_ } | 
| 217 |  |  |  |  |  |  | : {}; | 
| 218 | 58 |  |  |  |  | 227 | $args->{binmode} = ':utf8'; | 
| 219 | 58 |  | 33 |  |  | 449 | my $file = $args->{filename} || $args->{file} || $self->filename; | 
| 220 | 58 | 50 |  |  |  | 176 | return( $self->error( "No filename found." ) ) if( !length( $file ) ); | 
| 221 | 58 |  |  |  |  | 137 | $args->{filename} = $file; | 
| 222 | 58 |  |  |  |  | 245 | return( $self->slurp( $args ) ); | 
| 223 |  |  |  |  |  |  | } | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  |  | 
| 226 |  |  |  |  |  |  | 1; | 
| 227 |  |  |  |  |  |  |  | 
| 228 |  |  |  |  |  |  | __END__ | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  | =encoding utf-8 | 
| 231 |  |  |  |  |  |  |  | 
| 232 |  |  |  |  |  |  | =head1 NAME | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | Apache2::SSI::Common - Apache2 Server Side Include Common Resources | 
| 235 |  |  |  |  |  |  |  | 
| 236 |  |  |  |  |  |  | =head1 VERSION | 
| 237 |  |  |  |  |  |  |  | 
| 238 |  |  |  |  |  |  | v0.1.0 | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 241 |  |  |  |  |  |  |  | 
| 242 |  |  |  |  |  |  | use parent qw( Apache2::SSI::Common ); | 
| 243 |  |  |  |  |  |  |  | 
| 244 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | There is no specific api for this. This module contains only common resources used by other modules in this distribution. | 
| 247 |  |  |  |  |  |  |  | 
| 248 |  |  |  |  |  |  | =head1 METHODS | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | =head2 collapse_dots | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | Provided with an uri, and this will resolve the path and removing the dots, such as C<.> and C<..> and return an L<URI> object. | 
| 253 |  |  |  |  |  |  |  | 
| 254 |  |  |  |  |  |  | This is done as per the L<RFC 3986 section 5.2.4 algorithm|https://tools.ietf.org/html/rfc3986#page-33> | 
| 255 |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  | my $uri = $ssi->collapse_dots( '/../a/b/../c/./d.html' ); | 
| 257 |  |  |  |  |  |  | # would become /a/c/d.html | 
| 258 |  |  |  |  |  |  | my $uri = $ssi->collapse_dots( '/../a/b/../c/./d.html?foo=../bar' ); | 
| 259 |  |  |  |  |  |  | # would become /a/c/d.html?foo=../bar | 
| 260 |  |  |  |  |  |  | $uri->query # foo=../bar | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | =head2 slurp | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | It returns the content of the L</filename> | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | it takes an hash reference of parameters: | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | =over 4 | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | =item I<binmode> | 
| 271 |  |  |  |  |  |  |  | 
| 272 |  |  |  |  |  |  | my $content = $uri->slurp({ binmode => ':utf-8' }); | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | =back | 
| 275 |  |  |  |  |  |  |  | 
| 276 |  |  |  |  |  |  | It will return undef and sets an L<Module::Generic/error> if there is no L</filename> value set or if the file cannot be opened. | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | =head2 slurp_utf8 | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | It returns the content of the file L</filename> utf-8 decoded. | 
| 281 |  |  |  |  |  |  |  | 
| 282 |  |  |  |  |  |  | This is equivalent to: | 
| 283 |  |  |  |  |  |  |  | 
| 284 |  |  |  |  |  |  | my $content = $uri->slurp({ binmode => ':utf8' }); | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | C<:utf8> is slightly a bit more lax than C<:utf-8>, so it you want strict utf8, you can do: | 
| 287 |  |  |  |  |  |  |  | 
| 288 |  |  |  |  |  |  | my $content = $uri->slurp({ binmode => ':utf-8' }); | 
| 289 |  |  |  |  |  |  |  | 
| 290 |  |  |  |  |  |  | =head1 AUTHOR | 
| 291 |  |  |  |  |  |  |  | 
| 292 |  |  |  |  |  |  | Jacques Deguest E<lt>F<jack@deguest.jp>E<gt> | 
| 293 |  |  |  |  |  |  |  | 
| 294 |  |  |  |  |  |  | CPAN ID: jdeguest | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | L<https://git.deguest.jp/jack/Apache2-SSI> | 
| 297 |  |  |  |  |  |  |  | 
| 298 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | L<Apache2::SSI::File>, L<Apache2::SSI::URI> | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  | =head1 COPYRIGHT & LICENSE | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | Copyright (c) 2020-2021 DEGUEST Pte. Ltd. | 
| 305 |  |  |  |  |  |  |  | 
| 306 |  |  |  |  |  |  | You can use, copy, modify and redistribute this package and associated | 
| 307 |  |  |  |  |  |  | files under the same terms as Perl itself. | 
| 308 |  |  |  |  |  |  |  | 
| 309 |  |  |  |  |  |  | =cut | 
| 310 |  |  |  |  |  |  |  |