line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CGI::apacheSSI;
|
2
|
2
|
|
|
2
|
|
27245
|
use strict;
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
84
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
# use HTML::SimpleParse;
|
5
|
2
|
|
|
2
|
|
1916
|
use File::Spec::Functions; # catfile()
|
|
2
|
|
|
|
|
1781
|
|
|
2
|
|
|
|
|
273
|
|
6
|
2
|
|
|
2
|
|
3111
|
use FindBin;
|
|
2
|
|
|
|
|
2659
|
|
|
2
|
|
|
|
|
89
|
|
7
|
2
|
|
|
2
|
|
4294
|
use LWP::UserAgent;
|
|
2
|
|
|
|
|
131489
|
|
|
2
|
|
|
|
|
79
|
|
8
|
2
|
|
|
2
|
|
23
|
use HTTP::Response;
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
48
|
|
9
|
2
|
|
|
2
|
|
4944
|
use HTTP::Cookies;
|
|
2
|
|
|
|
|
22171
|
|
|
2
|
|
|
|
|
134
|
|
10
|
2
|
|
|
2
|
|
17
|
use URI;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
52
|
|
11
|
2
|
|
|
2
|
|
848
|
use Date::Format;
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $VERSION = '0.93';
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our $DEBUG = 0;
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub import {
|
18
|
|
|
|
|
|
|
my($class,%args) = @_;
|
19
|
|
|
|
|
|
|
return unless exists $args{'autotie'};
|
20
|
|
|
|
|
|
|
$args{'filehandle'} = $args{'autotie'} =~ /::/ ? $args{'autotie'} : caller().'::'.$args{'autotie'};
|
21
|
|
|
|
|
|
|
no strict 'refs';
|
22
|
|
|
|
|
|
|
my $self = tie(*{$args{'filehandle'}},$class,%args);
|
23
|
|
|
|
|
|
|
return $self;
|
24
|
|
|
|
|
|
|
}
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
my($gmt,$loc,$lmod);
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# NOTE: check for escaped \( or \), what should it do?
|
29
|
|
|
|
|
|
|
our $L; # used to return the brackets count
|
30
|
|
|
|
|
|
|
our $RE_parens_2C = qr/
|
31
|
|
|
|
|
|
|
( # g1, everything inside the brackets, incl brackets
|
32
|
|
|
|
|
|
|
\(
|
33
|
|
|
|
|
|
|
( (?: # g2, everything inside the brackets
|
34
|
|
|
|
|
|
|
(?{ $L = 1 }) # $L counts ('s inside pattern
|
35
|
|
|
|
|
|
|
(?:
|
36
|
|
|
|
|
|
|
(?:"[^"\\]* (?: \\.[^"\\]* )* ")
|
37
|
|
|
|
|
|
|
| (?:'[^'\\]* (?: \\.[^'\\]* )* ')
|
38
|
|
|
|
|
|
|
| (?:`[^`\\]* (?: \\.[^`\\]* )* `)
|
39
|
|
|
|
|
|
|
| (?:[^"'`)(])
|
40
|
|
|
|
|
|
|
| (?: \(
|
41
|
|
|
|
|
|
|
(?{ local $L=$L+1; }) # new set of nested parens
|
42
|
|
|
|
|
|
|
)
|
43
|
|
|
|
|
|
|
| (?: \)
|
44
|
|
|
|
|
|
|
(?{ local $L=$L-1; }) # close a set of nested parens
|
45
|
|
|
|
|
|
|
(?(?{ $L==0 })(?!)) # ...if there was no matching open paren...
|
46
|
|
|
|
|
|
|
)
|
47
|
|
|
|
|
|
|
)*
|
48
|
|
|
|
|
|
|
)* ) # end g2
|
49
|
|
|
|
|
|
|
\)
|
50
|
|
|
|
|
|
|
) # end g1
|
51
|
|
|
|
|
|
|
/x;
|
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
our $RE_quote_dbl_NC = qr/(?:"[^"\\]* (?: \\.[^"\\]* )* ")/x;
|
54
|
|
|
|
|
|
|
our $RE_quote_single_NC = qr/(?:'[^'\\]* (?: \\.[^'\\]* )* ')/x;
|
55
|
|
|
|
|
|
|
our $RE_quote_backtick_NC = qr/(?:`[^`\\]* (?: \\.[^`\\]* )* `)/x;
|
56
|
|
|
|
|
|
|
our $RE_all_quote_NC = qr/$RE_quote_dbl_NC|$RE_quote_single_NC|$RE_quote_backtick_NC/;
|
57
|
|
|
|
|
|
|
our $RE_all_no_quote_NC = qr/$RE_all_quote_NC|[^'"`]/;
|
58
|
|
|
|
|
|
|
our $RE_all_no_paren_NC = qr/$RE_all_quote_NC|[^()'"`]/;
|
59
|
|
|
|
|
|
|
our $RE_all_no_paren_noop_NC = qr/$RE_all_quote_NC | [^()'"`&\|] | &[^&] | \|[^\|]/x;
|
60
|
|
|
|
|
|
|
our $RE_single_quote_false_NC = qr/^ (?:\s*'')+\s* [']* $
|
61
|
|
|
|
|
|
|
|^ '? (?:\\')* $/x;
|
62
|
|
|
|
|
|
|
# empty, or 1+ unspaced single quotes, trivially false
|
63
|
|
|
|
|
|
|
# pairs of empty single quotes, false
|
64
|
|
|
|
|
|
|
# alternating backslash-single quotes, false
|
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# apache's own, special way of quoting strings
|
68
|
|
|
|
|
|
|
our $RE_apache_expr_quote = qr/ (?:"(?:[^"\\]|[\\]+[^\\])*?")
|
69
|
|
|
|
|
|
|
|(?:'(?:[^'\\]|[\\]+[^\\])*?')
|
70
|
|
|
|
|
|
|
|(?:`(?:[^`\\]|[\\]+[^\\])*?`)
|
71
|
|
|
|
|
|
|
/x;
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# NOTE: quotes that would be openers which are immediately preceeded by \w are treated as \w
|
74
|
|
|
|
|
|
|
# NOTE: needs to be preceeded by \s or =, otherwise becomes part of token (parsing oddity with apache 2.2.22)
|
75
|
|
|
|
|
|
|
our $RE_apache_expr_quote_all = qr/ $RE_apache_expr_quote | [^'"`\s]/x;
|
76
|
|
|
|
|
|
|
our $RE_runaway = qr/ \s+ \w+['"`]\S*\s+[^'"`]+['"`]+ /x;
|
77
|
|
|
|
|
|
|
our $RE_token_NC = qr{[[:alpha:]]\S+? (?:\s+ $RE_apache_expr_quote_all*? )*? $RE_runaway? }x;
|
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
sub new {
|
81
|
|
|
|
|
|
|
my($class,%args) = @_;
|
82
|
|
|
|
|
|
|
my $self = bless {}, $class;
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
$self->{'_handle'} = undef;
|
85
|
|
|
|
|
|
|
my $script_name = '';
|
86
|
|
|
|
|
|
|
if(exists $ENV{'SCRIPT_NAME'}) {
|
87
|
|
|
|
|
|
|
($script_name) = $ENV{'SCRIPT_NAME'} =~ /([^\/]+)$/;
|
88
|
|
|
|
|
|
|
}
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
tie $gmt, 'CGI::apacheSSI::Gmt', $self;
|
91
|
|
|
|
|
|
|
tie $loc, 'CGI::apacheSSI::Local', $self;
|
92
|
|
|
|
|
|
|
tie $lmod, 'CGI::apacheSSI::LMOD', $self;
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
$ENV{'DOCUMENT_ROOT'} ||= '';
|
95
|
|
|
|
|
|
|
$self->{'_variables'} = {
|
96
|
|
|
|
|
|
|
DOCUMENT_URI => ($args{'DOCUMENT_URI'} || $ENV{'SCRIPT_NAME'}),
|
97
|
|
|
|
|
|
|
DATE_GMT => $gmt,
|
98
|
|
|
|
|
|
|
DATE_LOCAL => $loc,
|
99
|
|
|
|
|
|
|
LAST_MODIFIED => $lmod,
|
100
|
|
|
|
|
|
|
DOCUMENT_NAME => ($args{'DOCUMENT_NAME'} || $script_name),
|
101
|
|
|
|
|
|
|
DOCUMENT_ROOT => ($args{'DOCUMENT_ROOT'} || $ENV{DOCUMENT_ROOT}),
|
102
|
|
|
|
|
|
|
};
|
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
$self->{'_config'} = { # NOTE: TODO: get these from apache config
|
105
|
|
|
|
|
|
|
errmsg => ($args{'errmsg'} || '[an error occurred while processing this directive]'),
|
106
|
|
|
|
|
|
|
sizefmt => ($args{'sizefmt'} || 'abbrev'),
|
107
|
|
|
|
|
|
|
timefmt => ($args{'timefmt'} || undef),
|
108
|
|
|
|
|
|
|
SSIUndefinedEcho => ($args{'SSIUndefinedEcho'} || '(none)'),
|
109
|
|
|
|
|
|
|
_verbose_errors => ($args{'_verbose_errors'} || 0) # NOTE: TODO: document this option
|
110
|
|
|
|
|
|
|
};
|
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
$self->{_max_recursions} = $args{MAX_RECURSIONS} || 100; # no "infinite" loops
|
113
|
|
|
|
|
|
|
$self->{_recursions} = {};
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
$self->{_cookie_jar} = $args{COOKIE_JAR} || HTTP::Cookies->new();
|
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
$self->{'_in_if'} = 0;
|
118
|
|
|
|
|
|
|
$self->{'_suspend'} = [0];
|
119
|
|
|
|
|
|
|
$self->{'_seen_true'} = [1];
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
return $self;
|
122
|
|
|
|
|
|
|
}
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
sub TIEHANDLE {
|
125
|
|
|
|
|
|
|
my($class,%args) = @_;
|
126
|
|
|
|
|
|
|
my $self = $class->new(%args);
|
127
|
|
|
|
|
|
|
$self->{'_handle'} = do { local *STDOUT };
|
128
|
|
|
|
|
|
|
my $handle_to_tie = '';
|
129
|
|
|
|
|
|
|
if($args{'filehandle'} !~ /::/) {
|
130
|
|
|
|
|
|
|
$handle_to_tie = caller().'::'.$args{'filehandle'};
|
131
|
|
|
|
|
|
|
} else {
|
132
|
|
|
|
|
|
|
$handle_to_tie = $args{'filehandle'};
|
133
|
|
|
|
|
|
|
}
|
134
|
|
|
|
|
|
|
open($self->{'_handle'},'>&'.$handle_to_tie) or die "Failed to copy the filehandle ($handle_to_tie): $!";
|
135
|
|
|
|
|
|
|
return $self;
|
136
|
|
|
|
|
|
|
}
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub PRINT {
|
139
|
|
|
|
|
|
|
my $self = shift;
|
140
|
|
|
|
|
|
|
print {$self->{'_handle'}} map { $self->process($_) } @_;
|
141
|
|
|
|
|
|
|
}
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub PRINTF {
|
144
|
|
|
|
|
|
|
my $self = shift;
|
145
|
|
|
|
|
|
|
my $fmt = shift;
|
146
|
|
|
|
|
|
|
printf {$self->{'_handle'}} $fmt, map { $self->process($_) } @_;
|
147
|
|
|
|
|
|
|
}
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub CLOSE {
|
150
|
|
|
|
|
|
|
my($self) = @_;
|
151
|
|
|
|
|
|
|
close $self->{'_handle'};
|
152
|
|
|
|
|
|
|
}
|
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
sub SSI_WARN {
|
155
|
|
|
|
|
|
|
my($self,$msg) = @_;
|
156
|
|
|
|
|
|
|
warn ref($self)." warn: $msg\n";
|
157
|
|
|
|
|
|
|
}
|
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub SSI_ERROR {
|
160
|
|
|
|
|
|
|
(my $self, $@) = @_;
|
161
|
|
|
|
|
|
|
warn ref($self)." error: $@\n";
|
162
|
|
|
|
|
|
|
return; # returning false here allows us to do one line error returns.
|
163
|
|
|
|
|
|
|
}
|
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub SSI_ERROR_FLUSH {
|
166
|
|
|
|
|
|
|
my($self,$msg) = @_;
|
167
|
|
|
|
|
|
|
if ($msg) {$self->SSI_ERROR($msg);}
|
168
|
|
|
|
|
|
|
$msg=$@; # NOTE: DEBUG ONLY!
|
169
|
|
|
|
|
|
|
undef $@;
|
170
|
|
|
|
|
|
|
return "[SSI ERROR=[$msg]]" if $self->{'_config'}->{'_verbose_errors'}; # NOTE: DEBUG ONLY!
|
171
|
|
|
|
|
|
|
return $self->{'_config'}->{'errmsg'};
|
172
|
|
|
|
|
|
|
}
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# NOTE: "if" allows expr="myexpr1" expr="myexpr2" where myexpr2 overwrites myexpr1.
|
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub process { # NOTE: -- FIXME -- this fails if we comment out the tokens.. ie
|
180
|
|
|
|
|
|
|
# NOTE: -- FIXME -- this should fail if we have any open quotes (ie, the --> doesnt magically close the tag.. in apache 2.2 at least)
|
181
|
|
|
|
|
|
|
my($self,@shtml) = @_;
|
182
|
|
|
|
|
|
|
my $processed = '';
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
# NOTE: FIXME: would this be easier with a global replace s///ge ?
|
185
|
|
|
|
|
|
|
@shtml = split(m/()/sx, join '',@shtml); # this will slurp up anything inside quotes, single or double
|
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
my $count=0;
|
188
|
|
|
|
|
|
|
for my $token (@shtml) {
|
189
|
|
|
|
|
|
|
if($token =~ /^$/sx) {
|
190
|
|
|
|
|
|
|
$processed .= $self->_process_ssi_text($1);
|
191
|
|
|
|
|
|
|
} else {
|
192
|
|
|
|
|
|
|
next if $self->_suspended;
|
193
|
|
|
|
|
|
|
$processed .= $token;
|
194
|
|
|
|
|
|
|
}
|
195
|
|
|
|
|
|
|
}
|
196
|
|
|
|
|
|
|
return $processed;
|
197
|
|
|
|
|
|
|
}
|
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub _process_ssi_text {
|
202
|
|
|
|
|
|
|
my($self,$text) = @_;
|
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# what's the first \S+?
|
205
|
|
|
|
|
|
|
if($text !~ s/^(\S+)\s*//)
|
206
|
|
|
|
|
|
|
{ return $self->SSI_ERROR_FLUSH("failed to find method name at beginning of string: '$text'."); }
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
my $method = $1;
|
209
|
|
|
|
|
|
|
if (! $self->can($method) )
|
210
|
|
|
|
|
|
|
{ return $self->SSI_ERROR_FLUSH("unknown directive \"$method\" in parsed doc."); }
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# are we suspended?
|
213
|
|
|
|
|
|
|
return '' if($self->_suspended and $method !~ /^(?:if|else|elif|endif)\b/);
|
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
my $res = $self->$method( $self->parse_args($text, $method) );
|
216
|
|
|
|
|
|
|
if ($@) { return $self->SSI_ERROR_FLUSH();}
|
217
|
|
|
|
|
|
|
return $res;
|
218
|
|
|
|
|
|
|
}
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# many thanks to HTML::SimpleParse, with a couple of modifications
|
223
|
|
|
|
|
|
|
sub parse_args {
|
224
|
|
|
|
|
|
|
my ($self, $str, $method) = @_;
|
225
|
|
|
|
|
|
|
my @returns;
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# Make sure we start searching at the beginning of the string
|
228
|
|
|
|
|
|
|
pos($str) = 0;
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
while (1) {
|
231
|
|
|
|
|
|
|
next if $str =~ m/\G\s+/gc; # Get rid of leading whitespace
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
if ( $str =~ m/\G
|
234
|
|
|
|
|
|
|
([\w.-]+)\s*=\s* # the key
|
235
|
|
|
|
|
|
|
(?:
|
236
|
|
|
|
|
|
|
# ($RE_all_quote_NC) \s* # anything in quotes
|
237
|
|
|
|
|
|
|
($RE_apache_expr_quote_all) \s* # anything in quotes
|
238
|
|
|
|
|
|
|
| # or
|
239
|
|
|
|
|
|
|
([^\s>]*) \s* # anything else, without whitespace or >
|
240
|
|
|
|
|
|
|
)/gcx ) {
|
241
|
|
|
|
|
|
|
my ($key, $val) = ($1, $+);
|
242
|
|
|
|
|
|
|
# ----- NOTE: if $key is not "expr" trim the quotes..
|
243
|
|
|
|
|
|
|
# ----- (apache evaluates differently depending on the type of quotes)
|
244
|
|
|
|
|
|
|
if ($key ne "expr") {$val =~ s/^['"`]?(.*?)['"`]?$/$1/;}
|
245
|
|
|
|
|
|
|
push @returns, $key, $val;
|
246
|
|
|
|
|
|
|
} elsif ( $str =~ m,\G/?([\w.-]+)\s*,gc ) {
|
247
|
|
|
|
|
|
|
push @returns, $1 , undef;
|
248
|
|
|
|
|
|
|
} else {
|
249
|
|
|
|
|
|
|
if ($str =~ m/\G(.+)/gc) # anything left over??
|
250
|
|
|
|
|
|
|
{
|
251
|
|
|
|
|
|
|
$self->SSI_ERROR("missing argument name for value to tag \"$method\" in");
|
252
|
|
|
|
|
|
|
# NOTE: notice this is NOT a "return".. we want processing to continue normally
|
253
|
|
|
|
|
|
|
}
|
254
|
|
|
|
|
|
|
last;
|
255
|
|
|
|
|
|
|
}
|
256
|
|
|
|
|
|
|
}
|
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# too many arguments for if element in
|
259
|
|
|
|
|
|
|
# else/endif/printenv directive does not take tags in
|
260
|
|
|
|
|
|
|
my %allowed_tag_count; # NOTE: this needs to be moved up
|
261
|
|
|
|
|
|
|
$allowed_tag_count{'if'}=["expr"];
|
262
|
|
|
|
|
|
|
$allowed_tag_count{'else'}=[];
|
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
if (defined $allowed_tag_count{$method})
|
265
|
|
|
|
|
|
|
{
|
266
|
|
|
|
|
|
|
if (@returns > 2 * @{ $allowed_tag_count{$method} })
|
267
|
|
|
|
|
|
|
{
|
268
|
|
|
|
|
|
|
if (@{ $allowed_tag_count{$method} } == 0)
|
269
|
|
|
|
|
|
|
{ $self->SSI_ERROR("\"$method\" directive does not take tags in");}
|
270
|
|
|
|
|
|
|
else
|
271
|
|
|
|
|
|
|
{ $self->SSI_ERROR("too many arguments for \"$method\" element in");}
|
272
|
|
|
|
|
|
|
}
|
273
|
|
|
|
|
|
|
elsif (@returns < 2 * @{ $allowed_tag_count{$method} })
|
274
|
|
|
|
|
|
|
{ $self->SSI_ERROR("missing arguments for directive \"$method\"");} # NOTE: fix this error message
|
275
|
|
|
|
|
|
|
}
|
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
return @returns;
|
278
|
|
|
|
|
|
|
}
|
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub _interp_vars {
|
282
|
|
|
|
|
|
|
local $^W = 0;
|
283
|
|
|
|
|
|
|
my($self,$text,$setcmd) = @_;
|
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# NOTE: var name in ${} MUST start with at least one \w
|
286
|
|
|
|
|
|
|
$text =~ s{ ((\\*) ((\\)|(\$)) (\{)?(\w (?(6)(.*)\}|(\w*)) )) }
|
287
|
|
|
|
|
|
|
{
|
288
|
|
|
|
|
|
|
my ($all,$slashes, $slash,$dollar, $lbrak,$var)=($1,$2, $4,$5, $6,$7);
|
289
|
|
|
|
|
|
|
$slashes .= $slash; # NOTE: this can be improved
|
290
|
|
|
|
|
|
|
if ($lbrak) {chop $var};
|
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
if (! $setcmd)
|
293
|
|
|
|
|
|
|
{ chop($slashes); }
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
if ($dollar && ! $slashes)
|
296
|
|
|
|
|
|
|
{ $var = $self->_echo($var); }
|
297
|
|
|
|
|
|
|
else
|
298
|
|
|
|
|
|
|
{
|
299
|
|
|
|
|
|
|
$var = "{$var}" if ($lbrak) ;
|
300
|
|
|
|
|
|
|
$var = $dollar.$var;
|
301
|
|
|
|
|
|
|
}
|
302
|
|
|
|
|
|
|
$slashes.$var
|
303
|
|
|
|
|
|
|
}exg;
|
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
return $text;
|
306
|
|
|
|
|
|
|
}
|
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
# for internal use only - returns the thing passed in if it's not defined. echo() returns '' in that case.
|
311
|
|
|
|
|
|
|
sub _echo {
|
312
|
|
|
|
|
|
|
my($self,$key,$var) = @_;
|
313
|
|
|
|
|
|
|
$var = $key if @_ == 2;
|
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
if($var eq 'DATE_LOCAL') {
|
316
|
|
|
|
|
|
|
return $loc;
|
317
|
|
|
|
|
|
|
} elsif($var eq 'DATE_GMT') {
|
318
|
|
|
|
|
|
|
return $gmt;
|
319
|
|
|
|
|
|
|
} elsif($var eq 'LAST_MODIFIED') {
|
320
|
|
|
|
|
|
|
return $lmod;
|
321
|
|
|
|
|
|
|
}
|
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
return $self->{'_variables'}->{$var} if exists $self->{'_variables'}->{$var};
|
324
|
|
|
|
|
|
|
return $ENV{$var} if exists $ENV{$var};
|
325
|
|
|
|
|
|
|
return '';
|
326
|
|
|
|
|
|
|
}
|
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
#
|
329
|
|
|
|
|
|
|
# ssi directive methods
|
330
|
|
|
|
|
|
|
#
|
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
sub config {
|
333
|
|
|
|
|
|
|
my($self,$type,$value) = @_;
|
334
|
|
|
|
|
|
|
if($type =~ /^timefmt$/i) {
|
335
|
|
|
|
|
|
|
$self->{'_config'}->{'timefmt'} = $value;
|
336
|
|
|
|
|
|
|
} elsif($type =~ /^sizefmt$/i) {
|
337
|
|
|
|
|
|
|
if(lc $value eq 'abbrev') {
|
338
|
|
|
|
|
|
|
$self->{'_config'}->{'sizefmt'} = 'abbrev';
|
339
|
|
|
|
|
|
|
} elsif(lc $value eq 'bytes') {
|
340
|
|
|
|
|
|
|
$self->{'_config'}->{'sizefmt'} = 'bytes';
|
341
|
|
|
|
|
|
|
} else {
|
342
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("value for sizefmt is '$value'. It must be 'abbrev' or 'bytes'.");
|
343
|
|
|
|
|
|
|
}
|
344
|
|
|
|
|
|
|
} elsif($type =~ /^errmsg$/i) {
|
345
|
|
|
|
|
|
|
$self->{'_config'}->{'errmsg'} = $value;
|
346
|
|
|
|
|
|
|
} elsif($type =~ /^_verbose_errors/i) {
|
347
|
|
|
|
|
|
|
$self->{'_config'}->{'_verbose_errors'} = $value;
|
348
|
|
|
|
|
|
|
} else {
|
349
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("arg to config is '$type'. It must be one of: 'timefmt', 'sizefmt', or 'errmsg'.");
|
350
|
|
|
|
|
|
|
}
|
351
|
|
|
|
|
|
|
return '';
|
352
|
|
|
|
|
|
|
}
|
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
sub set {
|
355
|
|
|
|
|
|
|
my($self,%args) = @_;
|
356
|
|
|
|
|
|
|
if(scalar keys %args > 1) {
|
357
|
|
|
|
|
|
|
$self->{'_variables'}->{$args{'var'}} = $self->_interp_vars($args{'value'}, 1);
|
358
|
|
|
|
|
|
|
} else { # var => value notation
|
359
|
|
|
|
|
|
|
my($var,$value) = %args;
|
360
|
|
|
|
|
|
|
$self->{'_variables'}->{$var} = $self->_interp_vars($value, 1);
|
361
|
|
|
|
|
|
|
}
|
362
|
|
|
|
|
|
|
return '';
|
363
|
|
|
|
|
|
|
}
|
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
sub escaped {
|
366
|
|
|
|
|
|
|
my ($t)=@_;
|
367
|
|
|
|
|
|
|
$t =~ s/\\\$/\$/g;
|
368
|
|
|
|
|
|
|
return $t ;
|
369
|
|
|
|
|
|
|
}
|
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub echo {
|
372
|
|
|
|
|
|
|
my($self,$key,$var) = @_;
|
373
|
|
|
|
|
|
|
$var = $key if @_ == 2;
|
374
|
|
|
|
|
|
|
my $encoding;
|
375
|
|
|
|
|
|
|
if ($key eq 'encoding') {
|
376
|
|
|
|
|
|
|
$encoding = $var; # NOTE: TODO: handle encoding.
|
377
|
|
|
|
|
|
|
($key,$var) = @_[3,4];
|
378
|
|
|
|
|
|
|
$var = $key if (!$var);
|
379
|
|
|
|
|
|
|
}
|
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
if($var eq 'DATE_LOCAL') {
|
382
|
|
|
|
|
|
|
return $loc;
|
383
|
|
|
|
|
|
|
} elsif($var eq 'DATE_GMT') {
|
384
|
|
|
|
|
|
|
return $gmt;
|
385
|
|
|
|
|
|
|
} elsif($var eq 'LAST_MODIFIED') {
|
386
|
|
|
|
|
|
|
return $lmod;
|
387
|
|
|
|
|
|
|
}
|
388
|
|
|
|
|
|
|
# it seems apache's "echo" command escapes out instances of "\$" to display just "$"
|
389
|
|
|
|
|
|
|
return &escaped($self->{'_variables'}->{$var}) if exists $self->{'_variables'}->{$var};
|
390
|
|
|
|
|
|
|
return &escaped($ENV{$var}) if exists $ENV{$var};
|
391
|
|
|
|
|
|
|
return $self->{'_config'}->{'SSIUndefinedEcho'};
|
392
|
|
|
|
|
|
|
}
|
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
sub printenv {
|
395
|
|
|
|
|
|
|
return join "\n",map {"$_=$ENV{$_}"} keys %ENV;
|
396
|
|
|
|
|
|
|
}
|
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
sub include {
|
399
|
|
|
|
|
|
|
$DEBUG and do { local $" = "','"; warn "DEBUG: include('@_')\n" };
|
400
|
|
|
|
|
|
|
my($self,$type,$filename) = @_;
|
401
|
|
|
|
|
|
|
if(lc $type eq 'file') {
|
402
|
|
|
|
|
|
|
return $self->_include_file($filename);
|
403
|
|
|
|
|
|
|
} elsif(lc $type eq 'virtual') {
|
404
|
|
|
|
|
|
|
return $self->_include_virtual($filename);
|
405
|
|
|
|
|
|
|
} else {
|
406
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("arg to include is '$type'. It must be one of: 'file' or 'virtual'.");
|
407
|
|
|
|
|
|
|
}
|
408
|
|
|
|
|
|
|
}
|
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
sub _include_file {
|
411
|
|
|
|
|
|
|
$DEBUG and do { local $" = "','"; warn "DEBUG: _include_file('@_')\n" };
|
412
|
|
|
|
|
|
|
my($self,$filename) = @_;
|
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
# get the filename to open
|
415
|
|
|
|
|
|
|
$filename = catfile($FindBin::Bin,$filename) unless -e $filename;
|
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
# if we've reached MAX_RECURSIONS for this filename, warn and return the error
|
418
|
|
|
|
|
|
|
if(++$self->{_recursions}->{$filename} >= $self->{_max_recursions}) {
|
419
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("the maximum number of 'include file' recursions has been exceeded for '$filename'.");
|
420
|
|
|
|
|
|
|
}
|
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
# open the file, or warn and return an error
|
423
|
|
|
|
|
|
|
my $fh = do { local *STDIN };
|
424
|
|
|
|
|
|
|
open($fh,$filename) or do {
|
425
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("failed to open file ($filename): $!");
|
426
|
|
|
|
|
|
|
};
|
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
# process the included file and return the result
|
429
|
|
|
|
|
|
|
return $self->process(join '',<$fh>);
|
430
|
|
|
|
|
|
|
}
|
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
sub _include_virtual {
|
433
|
|
|
|
|
|
|
$DEBUG and do { local $" = "','"; warn "DEBUG: _include_virtual('@_')\n" };
|
434
|
|
|
|
|
|
|
my($self,$filename) = @_;
|
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
# if this is a local file that we can just read, let's do that instead of getting it virtually
|
437
|
|
|
|
|
|
|
if($filename =~ m|^/(.+)|) { # could be on the local server: absolute filename, relative to ., relative to $ENV{DOCUMENT_ROOT}
|
438
|
|
|
|
|
|
|
my $file = $1;
|
439
|
|
|
|
|
|
|
if(-e '/'.$file) { # back to the original
|
440
|
|
|
|
|
|
|
$file = '/'.$file;
|
441
|
|
|
|
|
|
|
} elsif(-e catfile($self->{'_variables'}->{'DOCUMENT_ROOT'},$file)) {
|
442
|
|
|
|
|
|
|
$file = catfile($self->{'_variables'}->{'DOCUMENT_ROOT'},$file);
|
443
|
|
|
|
|
|
|
} elsif(-e catfile($FindBin::Bin,$file)) {
|
444
|
|
|
|
|
|
|
# $file = atfile($FindBin::Bin,$file); # <----- NOTE: is this a typo here??
|
445
|
|
|
|
|
|
|
$file = catfile($FindBin::Bin,$file); # fixing it just in case
|
446
|
|
|
|
|
|
|
}
|
447
|
|
|
|
|
|
|
return $self->_include_file($file) if -e $file;
|
448
|
|
|
|
|
|
|
}
|
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
# create the URI to get(), or warn and return the error
|
451
|
|
|
|
|
|
|
my $uri = eval {
|
452
|
|
|
|
|
|
|
my $uri = URI->new($filename);
|
453
|
|
|
|
|
|
|
$uri->scheme($uri->scheme || ($ENV{HTTPS} ? 'https' : 'http')); # ??
|
454
|
|
|
|
|
|
|
$uri->host($uri->host || $ENV{'HTTP_HOST'} || $ENV{'SERVER_NAME'} || 'localhost');
|
455
|
|
|
|
|
|
|
$uri;
|
456
|
|
|
|
|
|
|
} or do {
|
457
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("failed to create a URI based on '$filename'.");
|
458
|
|
|
|
|
|
|
};
|
459
|
|
|
|
|
|
|
if($@) {
|
460
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("failed to create a URI based on '$filename'.");
|
461
|
|
|
|
|
|
|
}
|
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
# get the content of the request
|
464
|
|
|
|
|
|
|
$self->{_ua} ||= $self->_get_ua();
|
465
|
|
|
|
|
|
|
my $url = $uri->canonical;
|
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
# have we reached MAX_RECURSIONS?
|
468
|
|
|
|
|
|
|
if(++$self->{_recursions}->{$url} >= $self->{_max_recursions}) {
|
469
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("the maximum number of 'include virtual' recursions has been exceeded for '$url'.");
|
470
|
|
|
|
|
|
|
}
|
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
my $response = $self->{_ua}->get($url);
|
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
# is it a success?
|
475
|
|
|
|
|
|
|
unless($response->is_success) {
|
476
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("failed to get('$url'): ".$response->status_line.".");
|
477
|
|
|
|
|
|
|
}
|
478
|
|
|
|
|
|
|
# process the included content and return the result
|
479
|
|
|
|
|
|
|
return $self->process($response->content);
|
480
|
|
|
|
|
|
|
}
|
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
sub _get_ua {
|
483
|
|
|
|
|
|
|
my $self = shift;
|
484
|
|
|
|
|
|
|
my %conf = ();
|
485
|
|
|
|
|
|
|
$conf{agent} = $ENV{HTTP_USER_AGENT} if $ENV{HTTP_USER_AGENT};
|
486
|
|
|
|
|
|
|
my $ua = LWP::UserAgent->new(%conf);
|
487
|
|
|
|
|
|
|
$ua->cookie_jar($self->{_cookie_jar});
|
488
|
|
|
|
|
|
|
return $ua;
|
489
|
|
|
|
|
|
|
}
|
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
sub cookie_jar {
|
492
|
|
|
|
|
|
|
my $self = shift;
|
493
|
|
|
|
|
|
|
if(my $jar = shift) {
|
494
|
|
|
|
|
|
|
$self->{_cookie_jar} = $jar;
|
495
|
|
|
|
|
|
|
}
|
496
|
|
|
|
|
|
|
return $self->{_cookie_jar};
|
497
|
|
|
|
|
|
|
}
|
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
sub exec {
|
500
|
|
|
|
|
|
|
my($self,$type,$filename) = @_;
|
501
|
|
|
|
|
|
|
if(lc $type eq 'cmd') {
|
502
|
|
|
|
|
|
|
return $self->_exec_cmd($filename);
|
503
|
|
|
|
|
|
|
} elsif(lc $type eq 'cgi') {
|
504
|
|
|
|
|
|
|
return $self->_exec_cgi($filename);
|
505
|
|
|
|
|
|
|
} else {
|
506
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("arg to exec() is '$type'. It must be one of: 'cmd' or 'cgi'.");
|
507
|
|
|
|
|
|
|
}
|
508
|
|
|
|
|
|
|
}
|
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
sub _exec_cmd {
|
511
|
|
|
|
|
|
|
my($self,$filename) = @_;
|
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
# have we reached MAX_RECURSIONS?
|
514
|
|
|
|
|
|
|
if(++$self->{_recursions}->{$filename} >= $self->{_max_recursions}) {
|
515
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("the maximum number of 'exec cmd' recursions has been exceeded for '$filename'.");
|
516
|
|
|
|
|
|
|
}
|
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
my $output = `$filename`; # security here is mighty bad.
|
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
# was the command a success?
|
521
|
|
|
|
|
|
|
if($?) {
|
522
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("`$filename` was not successful.");
|
523
|
|
|
|
|
|
|
}
|
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
# process the output, and return the result
|
526
|
|
|
|
|
|
|
return $self->process($output);
|
527
|
|
|
|
|
|
|
}
|
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
sub _exec_cgi { # no relative $filename allowed.
|
530
|
|
|
|
|
|
|
my($self,$filename) = @_;
|
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
# have we reached MAX_RECURSIONS?
|
533
|
|
|
|
|
|
|
if(++$self->{_recursions}->{$filename} >= $self->{_max_recursions}) {
|
534
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("the maximum number of 'exec cgi' recursions has been exceeded for '$filename'.");
|
535
|
|
|
|
|
|
|
}
|
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
# create the URI from the filename
|
538
|
|
|
|
|
|
|
my $uri = eval {
|
539
|
|
|
|
|
|
|
my $uri = URI->new($filename);
|
540
|
|
|
|
|
|
|
$uri->scheme($uri->scheme || ($ENV{HTTPS} ? 'https' : 'http')); # ??
|
541
|
|
|
|
|
|
|
$uri->host($uri->host || $ENV{'HTTP_HOST'} || $ENV{'SERVER_NAME'});
|
542
|
|
|
|
|
|
|
$uri->query($uri->query || $ENV{'QUERY_STRING'});
|
543
|
|
|
|
|
|
|
$uri;
|
544
|
|
|
|
|
|
|
} or do {
|
545
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("failed to create a URI from '$filename'.");
|
546
|
|
|
|
|
|
|
};
|
547
|
|
|
|
|
|
|
if($@) {
|
548
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("failed to create a URI from '$filename'.");
|
549
|
|
|
|
|
|
|
}
|
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
# get the content
|
552
|
|
|
|
|
|
|
$self->{_ua} ||= $self->_get_ua();
|
553
|
|
|
|
|
|
|
my $url = $uri->canonical;
|
554
|
|
|
|
|
|
|
my $response = $self->{_ua}->get($url);
|
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
# success?
|
557
|
|
|
|
|
|
|
unless($response->is_success) {
|
558
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("failed to get('$filename').");
|
559
|
|
|
|
|
|
|
}
|
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
# process the content and return the result
|
562
|
|
|
|
|
|
|
return $self->process($response->content);
|
563
|
|
|
|
|
|
|
}
|
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
sub flastmod {
|
566
|
|
|
|
|
|
|
my($self,$type,$filename) = @_;
|
567
|
|
|
|
|
|
|
|
568
|
|
|
|
|
|
|
if(lc $type eq 'file') {
|
569
|
|
|
|
|
|
|
$filename = catfile($FindBin::Bin,$filename) unless -e $filename;
|
570
|
|
|
|
|
|
|
} elsif(lc $type eq 'virtual') {
|
571
|
|
|
|
|
|
|
$filename = catfile($self->{'_variables'}->{'DOCUMENT_ROOT'},$filename)
|
572
|
|
|
|
|
|
|
unless $filename =~ /$self->{'_variables'}->{'DOCUMENT_ROOT'}/;
|
573
|
|
|
|
|
|
|
} else {
|
574
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("the first argument to flastmod is '$type'. It must be one of: 'file' or 'virtual'.");
|
575
|
|
|
|
|
|
|
}
|
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
unless(-e $filename) {
|
578
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("flastmod failed to find '$filename'.");
|
579
|
|
|
|
|
|
|
}
|
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
my $flastmod = (stat $filename)[9];
|
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
if($self->{'_config'}->{'timefmt'}) {
|
584
|
|
|
|
|
|
|
my @localtime = localtime($flastmod); # need this??
|
585
|
|
|
|
|
|
|
return Date::Format::strftime($self->{'_config'}->{'timefmt'},@localtime);
|
586
|
|
|
|
|
|
|
} else {
|
587
|
|
|
|
|
|
|
return scalar localtime($flastmod);
|
588
|
|
|
|
|
|
|
}
|
589
|
|
|
|
|
|
|
}
|
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
sub fsize {
|
592
|
|
|
|
|
|
|
my($self,$type,$filename) = @_;
|
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
if(lc $type eq 'file') {
|
595
|
|
|
|
|
|
|
$filename = catfile($FindBin::Bin,$filename) unless -e $filename;
|
596
|
|
|
|
|
|
|
} elsif(lc $type eq 'virtual') {
|
597
|
|
|
|
|
|
|
$filename = catfile($ENV{'DOCUMENT_ROOT'},$filename) unless $filename =~ /$ENV{'DOCUMENT_ROOT'}/;
|
598
|
|
|
|
|
|
|
} else {
|
599
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("the first argument to fsize is '$type'. It must be one of: 'file' or 'virtual'.");
|
600
|
|
|
|
|
|
|
}
|
601
|
|
|
|
|
|
|
unless(-e $filename) {
|
602
|
|
|
|
|
|
|
return $self->SSI_ERROR_FLUSH("fsize failed to find '$filename'.");
|
603
|
|
|
|
|
|
|
}
|
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
my $fsize = (stat $filename)[7];
|
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
if(lc $self->{'_config'}->{'sizefmt'} eq 'bytes') {
|
608
|
|
|
|
|
|
|
1 while $fsize =~ s/^(\d+)(\d{3})/$1,$2/g;
|
609
|
|
|
|
|
|
|
return $fsize;
|
610
|
|
|
|
|
|
|
} else { # abbrev
|
611
|
|
|
|
|
|
|
# gratefully lifted from Apache::SSI
|
612
|
|
|
|
|
|
|
return " 0k" unless $fsize;
|
613
|
|
|
|
|
|
|
return " 1k" if $fsize < 1024;
|
614
|
|
|
|
|
|
|
return sprintf("%4dk", ($fsize + 512)/1024) if $fsize < 1048576;
|
615
|
|
|
|
|
|
|
return sprintf("%4.1fM", $fsize/1048576.0) if $fsize < 103809024;
|
616
|
|
|
|
|
|
|
return sprintf("%4dM", ($fsize + 524288)/1048576) if $fsize < 1048576;
|
617
|
|
|
|
|
|
|
}
|
618
|
|
|
|
|
|
|
}
|
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
#
|
621
|
|
|
|
|
|
|
# if/elsif/else/endif and related methods
|
622
|
|
|
|
|
|
|
#
|
623
|
|
|
|
|
|
|
# NOTE: anything calling _test should check $@
|
624
|
|
|
|
|
|
|
sub _test {
|
625
|
|
|
|
|
|
|
my($self,$test) = @_;
|
626
|
|
|
|
|
|
|
my $quote;
|
627
|
|
|
|
|
|
|
my ($pound, $pounds);
|
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
$test =~ s/^(['"`])\s*(.*?)\s*(\1)$/$2/; # trim off surrounding (matching) quotes, and whitespace
|
630
|
|
|
|
|
|
|
$quote= $1;
|
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
# trivial test returns:
|
633
|
|
|
|
|
|
|
return 0 if $test =~ /$RE_single_quote_false_NC/;
|
634
|
|
|
|
|
|
|
return 1 if $test =~ /^["`]+$/; # 1+ double quotes or backticks, trivially true
|
635
|
|
|
|
|
|
|
return 1 if $test =~ /^[\s`'"]*?([`'"])?[\s]+?\1$/; # whitespace inside second set of quotes, trivially true
|
636
|
|
|
|
|
|
|
return 1 if $test =~ /^[\w]+$/; # bareword (alphanum) trivially true
|
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
if (1) # ($test =~ m{^\(})
|
639
|
|
|
|
|
|
|
{ # need to do this otherwise it creates infinite loop for some reason
|
640
|
|
|
|
|
|
|
if ($test =~ m{
|
641
|
|
|
|
|
|
|
((?:\!\s*)*) \s* # $1
|
642
|
|
|
|
|
|
|
( # $2
|
643
|
|
|
|
|
|
|
$RE_parens_2C # ($3, $4) has 2 capture groups
|
644
|
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
(?:$RE_all_no_paren_noop_NC)*
|
646
|
|
|
|
|
|
|
) \s*
|
647
|
|
|
|
|
|
|
(?:
|
648
|
|
|
|
|
|
|
(\&\& | \|\| )? \s* # $5
|
649
|
|
|
|
|
|
|
(.*) # $6
|
650
|
|
|
|
|
|
|
)? \s*
|
651
|
|
|
|
|
|
|
}x)
|
652
|
|
|
|
|
|
|
{
|
653
|
|
|
|
|
|
|
# $1 is pound, $4 is inside the brackets, $5 is the op, $6 is the RHS
|
654
|
|
|
|
|
|
|
my $LHS=$2;
|
655
|
|
|
|
|
|
|
my $LHS_parens=$4; # inside parentheses, does not include the parentheses
|
656
|
|
|
|
|
|
|
my $OP=$5;
|
657
|
|
|
|
|
|
|
my $RHS=$6;
|
658
|
|
|
|
|
|
|
# expr="x == '\\x'" is split into: LHS=[ x == ] RHS=[ '\\x' ]
|
659
|
|
|
|
|
|
|
$pounds=$pound=$1;
|
660
|
|
|
|
|
|
|
$pound=~s/(?:\!\s*\!\s*)*//; # remove even # of !s, as these cancel out
|
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
# if no op, and LHS and RHS, FAIL... because (x) b.. -- can be no LHS but RHS and noop
|
663
|
|
|
|
|
|
|
# if no op and no $RHS, return pound != test(LHS)
|
664
|
|
|
|
|
|
|
# if op, and no RHS or no LHS, FAIL
|
665
|
|
|
|
|
|
|
# if op, do op.. return [pound != test(LHS)] op [test(LHS)]
|
666
|
|
|
|
|
|
|
if ($OP)
|
667
|
|
|
|
|
|
|
{ # LOGICAL COMPARISON && and ||
|
668
|
|
|
|
|
|
|
# NOTE: && and || have equal precedence
|
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
if ($LHS=~/^\s*$/)
|
671
|
|
|
|
|
|
|
{
|
672
|
|
|
|
|
|
|
return $self->SSI_ERROR("empty logical comparison in expr.");
|
673
|
|
|
|
|
|
|
}
|
674
|
|
|
|
|
|
|
if ($RHS=~/^\s*$/)
|
675
|
|
|
|
|
|
|
{
|
676
|
|
|
|
|
|
|
return $self->SSI_ERROR("empty logical comparison in expr.");
|
677
|
|
|
|
|
|
|
}
|
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
if ($LHS_parens) {$LHS = $LHS_parens;} # needs to be done here, because of empty comparison checker
|
680
|
|
|
|
|
|
|
$LHS = $self->_test($quote.$LHS.$quote);
|
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
if ($@) {return;} # there were errors in the test
|
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
if ($pound) {$LHS = !$LHS;}
|
685
|
|
|
|
|
|
|
$RHS = $quote.$RHS.$quote;
|
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
if ($OP eq "&&")
|
688
|
|
|
|
|
|
|
{ return ($LHS && $self->_test($RHS)); } # short circuits, faster
|
689
|
|
|
|
|
|
|
else # ($OP eq "||")
|
690
|
|
|
|
|
|
|
{ return ($LHS || $self->_test($RHS)); } # short circuits, faster
|
691
|
|
|
|
|
|
|
}
|
692
|
|
|
|
|
|
|
else
|
693
|
|
|
|
|
|
|
{ # NO OP
|
694
|
|
|
|
|
|
|
if ($LHS && $RHS)
|
695
|
|
|
|
|
|
|
{
|
696
|
|
|
|
|
|
|
if ($LHS_parens)
|
697
|
|
|
|
|
|
|
{
|
698
|
|
|
|
|
|
|
# return $self->SSI_ERROR("error in expression."); # NOTE: FIXME: improve this error msg..
|
699
|
|
|
|
|
|
|
# return $self->SSI_ERROR("error in expression. LHS and RHS but no OP"); # NOTE: FIXME: improve this error msg..
|
700
|
|
|
|
|
|
|
return $self->SSI_ERROR("error in expression. LHS [$LHS] and RHS [$RHS] but no OP"); # NOTE: FIXME: improve this error msg..
|
701
|
|
|
|
|
|
|
}
|
702
|
|
|
|
|
|
|
$test = $LHS.$RHS;
|
703
|
|
|
|
|
|
|
}
|
704
|
|
|
|
|
|
|
elsif ($LHS) # brackets or balanced quotes
|
705
|
|
|
|
|
|
|
{
|
706
|
|
|
|
|
|
|
if ($LHS_parens)
|
707
|
|
|
|
|
|
|
{
|
708
|
|
|
|
|
|
|
$LHS = $self->_test($quote.$LHS_parens.$quote);
|
709
|
|
|
|
|
|
|
if ($pound) {$LHS = !$LHS;}
|
710
|
|
|
|
|
|
|
return $LHS;
|
711
|
|
|
|
|
|
|
}
|
712
|
|
|
|
|
|
|
$test = $LHS; # NOTE: is this redundant?
|
713
|
|
|
|
|
|
|
}
|
714
|
|
|
|
|
|
|
elsif ($RHS) # unbalanced quotes
|
715
|
|
|
|
|
|
|
{ $test = $RHS; } # NOTE: is this redundant?
|
716
|
|
|
|
|
|
|
}
|
717
|
|
|
|
|
|
|
}
|
718
|
|
|
|
|
|
|
else
|
719
|
|
|
|
|
|
|
{
|
720
|
|
|
|
|
|
|
return $self->SSI_ERROR("unknown error in expression."); # SHOULD NOT REACH THIS
|
721
|
|
|
|
|
|
|
}
|
722
|
|
|
|
|
|
|
}
|
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
#--------------------------
|
726
|
|
|
|
|
|
|
# BAREWORD (no comparison sign)
|
727
|
|
|
|
|
|
|
if ($test =~ /^(?:$RE_all_quote_NC|(?:[^=<>\/]|[\\]\/)*)$/) # BAREWORD
|
728
|
|
|
|
|
|
|
{
|
729
|
|
|
|
|
|
|
if ($test =~ /^(['])(.*?)(?:\1)$/) {$test=$2;} # need to trim surrounding single quotes
|
730
|
|
|
|
|
|
|
if ($test =~ /^$/) {return ($pound);} # no need to parse
|
731
|
|
|
|
|
|
|
if ($test =~ /^["]/) {return (! $pound);} # no need to parse
|
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
my $interp_test = $self->_interp_vars($test);
|
734
|
|
|
|
|
|
|
my $RET = ($interp_test =~ /[^']+/);
|
735
|
|
|
|
|
|
|
if ($interp_test ne $test)
|
736
|
|
|
|
|
|
|
{ # var interpolation occurred, NOTE: apache deems only '' or empty to be false in this case.
|
737
|
|
|
|
|
|
|
$test = ($interp_test !~ /^$/) ;
|
738
|
|
|
|
|
|
|
return (($pound) xor ($test));
|
739
|
|
|
|
|
|
|
}
|
740
|
|
|
|
|
|
|
return (($pound) xor ($RET)); # non empty string is true,
|
741
|
|
|
|
|
|
|
}
|
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
#--------------------------
|
745
|
|
|
|
|
|
|
# STRING COMPARISON >,<,==,!=,=~
|
746
|
|
|
|
|
|
|
if ($test =~ m{ \s*((?:$RE_all_quote_NC|[^<>=])*?)\s*([<>=!]=?)\s*([^<>=]*)\s* }x)
|
747
|
|
|
|
|
|
|
{
|
748
|
|
|
|
|
|
|
if ($pounds)
|
749
|
|
|
|
|
|
|
{ return $self->SSI_ERROR("invalid expression $quote$test$quote in file"); } # NOTE: FIXME
|
750
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
my ($s1,$cmp,$s2)=($1, $2, $3);
|
752
|
|
|
|
|
|
|
if ($s1=~/^\s*$/)
|
753
|
|
|
|
|
|
|
{ return $self->SSI_ERROR("problem in REGEX. blank comparison \$s1"); } # NOTE: FIXME
|
754
|
|
|
|
|
|
|
if ($s2=~/^\s*$/)
|
755
|
|
|
|
|
|
|
{ return $self->SSI_ERROR("problem in REGEX. blank comparison \$s2"); } # NOTE: FIXME
|
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
if ($s2 =~ m{^ \s* (?: (?:/\s*[^/]*) | // ) \s* $}x) # NOTE: what about escaped or stringed
|
758
|
|
|
|
|
|
|
{
|
759
|
|
|
|
|
|
|
if ($cmp =~ m/^==?$/) {return 1;}
|
760
|
|
|
|
|
|
|
elsif ($cmp =~ m/^!=$/) {return;}
|
761
|
|
|
|
|
|
|
else { return $self->SSI_ERROR("Invalid expression $quote$test$quote in string comparison."); }
|
762
|
|
|
|
|
|
|
}
|
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
$s1=$self->_interp_vars($s1);
|
765
|
|
|
|
|
|
|
if ($s1 =~ /^(['"`])(.*?)(?:\1)$/) {$s1=$2;} # trim off surrounding (matching) quotes
|
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
# REGEX
|
768
|
|
|
|
|
|
|
if ($s2 =~ m{^\s* / ((?:(?:(?:\\\\)*\\/) | [^/] )*) / (.*?)\s*$}x) # wrapped by /xx/
|
769
|
|
|
|
|
|
|
{
|
770
|
|
|
|
|
|
|
if ($2)
|
771
|
|
|
|
|
|
|
{ return $self->SSI_ERROR("problem in REGEX. s2=[$s2] extra stuff=[$2]"); } # NOTE: FIXME
|
772
|
|
|
|
|
|
|
$s2=qr/$1/; # regex s2
|
773
|
|
|
|
|
|
|
$s2 = $self->_interp_vars($s2);
|
774
|
|
|
|
|
|
|
if ($cmp =~ m/^==?$/)
|
775
|
|
|
|
|
|
|
{ return ($s1 =~ m/$s2/);}
|
776
|
|
|
|
|
|
|
elsif ($cmp eq "!=")
|
777
|
|
|
|
|
|
|
{ return ($s1 !~ $s2); } # NOTE: FIXME!!!
|
778
|
|
|
|
|
|
|
}
|
779
|
|
|
|
|
|
|
else
|
780
|
|
|
|
|
|
|
{
|
781
|
|
|
|
|
|
|
if ($s2=~m|^[^\s/]+\s+/|) # unquoted, unescaped slash
|
782
|
|
|
|
|
|
|
{ return $self->SSI_ERROR("problem in REGEX unquoted slash. s2=[$s2]"); } # NOTE: FIXME
|
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
$s2 = $self->_interp_vars($s2);
|
785
|
|
|
|
|
|
|
if ($s2 =~ /^(['"])(.*?)(\1)$/) {$s2 = $2;} # trim off surrounding (matching) quotes
|
786
|
|
|
|
|
|
|
}
|
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
my $ret;
|
789
|
|
|
|
|
|
|
$ret = $s1 cmp $s2;
|
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
if ($cmp =~ m/^==?$/) {$ret = ($ret eq 0);}
|
792
|
|
|
|
|
|
|
elsif ($cmp =~ m/^!=$/) {$ret = ($ret ne 0);}
|
793
|
|
|
|
|
|
|
|
794
|
|
|
|
|
|
|
elsif ($cmp =~ m/^<$/) {$ret = ($ret lt 0);}
|
795
|
|
|
|
|
|
|
elsif ($cmp =~ m/^<=$/) {$ret = ($ret le 0);}
|
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
elsif ($cmp =~ m/^>$/) {$ret = ($ret gt 0);}
|
798
|
|
|
|
|
|
|
elsif ($cmp =~ m/^>=$/) {$ret = ($ret ge 0);}
|
799
|
|
|
|
|
|
|
|
800
|
|
|
|
|
|
|
else { return $self->SSI_ERROR("unknown comparison"); } # UNKNOWN COMPARISON -- should never reach this
|
801
|
|
|
|
|
|
|
|
802
|
|
|
|
|
|
|
return $ret;
|
803
|
|
|
|
|
|
|
}
|
804
|
|
|
|
|
|
|
else
|
805
|
|
|
|
|
|
|
{
|
806
|
|
|
|
|
|
|
if ($test =~ m{[^/]+\s+/}) # NOTE: UNFINISHED!! FIXME non empty unrecognized string that didnt fail
|
807
|
|
|
|
|
|
|
{ return $self->SSI_ERROR("error in expression, regex found in string"); }
|
808
|
|
|
|
|
|
|
return 1;
|
809
|
|
|
|
|
|
|
}
|
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
return; # return false.. it seems none of the ops applied..
|
812
|
|
|
|
|
|
|
}
|
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
sub _entering_if {
|
815
|
|
|
|
|
|
|
my $self = shift;
|
816
|
|
|
|
|
|
|
$self->{'_in_if'}++;
|
817
|
|
|
|
|
|
|
$self->{'_suspend'}->[$self->{'_in_if'}] = $self->{'_suspend'}->[$self->{'_in_if'} - 1];
|
818
|
|
|
|
|
|
|
$self->{'_seen_true'}->[$self->{'_in_if'}] = 0;
|
819
|
|
|
|
|
|
|
}
|
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
sub _seen_true {
|
822
|
|
|
|
|
|
|
my $self = shift;
|
823
|
|
|
|
|
|
|
return $self->{'_seen_true'}->[$self->{'_in_if'}];
|
824
|
|
|
|
|
|
|
}
|
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
sub _suspended {
|
827
|
|
|
|
|
|
|
my $self = shift;
|
828
|
|
|
|
|
|
|
return $self->{'_suspend'}->[$self->{'_in_if'}];
|
829
|
|
|
|
|
|
|
}
|
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
sub _leaving_if {
|
832
|
|
|
|
|
|
|
my $self = shift;
|
833
|
|
|
|
|
|
|
$self->{'_in_if'}-- if $self->{'_in_if'};
|
834
|
|
|
|
|
|
|
}
|
835
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
sub _true {
|
837
|
|
|
|
|
|
|
my $self = shift;
|
838
|
|
|
|
|
|
|
return $self->{'_seen_true'}->[$self->{'_in_if'}]++;
|
839
|
|
|
|
|
|
|
}
|
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
sub _suspend {
|
842
|
|
|
|
|
|
|
my $self = shift;
|
843
|
|
|
|
|
|
|
$self->{'_suspend'}->[$self->{'_in_if'}]++;
|
844
|
|
|
|
|
|
|
}
|
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
sub _resume {
|
847
|
|
|
|
|
|
|
my $self = shift;
|
848
|
|
|
|
|
|
|
$self->{'_suspend'}->[$self->{'_in_if'}]--
|
849
|
|
|
|
|
|
|
if $self->{'_suspend'}->[$self->{'_in_if'}];
|
850
|
|
|
|
|
|
|
}
|
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
sub _in_if {
|
853
|
|
|
|
|
|
|
my $self = shift;
|
854
|
|
|
|
|
|
|
return $self->{'_in_if'};
|
855
|
|
|
|
|
|
|
}
|
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
sub if {
|
858
|
|
|
|
|
|
|
my($self,$expr,$test) = @_;
|
859
|
|
|
|
|
|
|
$expr = $test if @_ == 3;
|
860
|
|
|
|
|
|
|
$self->_entering_if();
|
861
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
my $res=$self->_test($expr);
|
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
if($@) {
|
865
|
|
|
|
|
|
|
$self->_true();
|
866
|
|
|
|
|
|
|
return;
|
867
|
|
|
|
|
|
|
} # any errors cause the expr to evaluate to true..??
|
868
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
if($res) {
|
870
|
|
|
|
|
|
|
$self->_true();
|
871
|
|
|
|
|
|
|
} else {
|
872
|
|
|
|
|
|
|
$self->_suspend();
|
873
|
|
|
|
|
|
|
}
|
874
|
|
|
|
|
|
|
return '';
|
875
|
|
|
|
|
|
|
}
|
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
sub elif {
|
878
|
|
|
|
|
|
|
my($self,$expr,$test) = @_;
|
879
|
|
|
|
|
|
|
|
880
|
|
|
|
|
|
|
if (! $self->_in_if() )
|
881
|
|
|
|
|
|
|
{
|
882
|
|
|
|
|
|
|
$self->SSI_WARN("Incorrect use of elif ssi directive: no preceeding 'if'."); # NOTE: just a "warn"
|
883
|
|
|
|
|
|
|
$self->_suspend() unless $self->_suspended();
|
884
|
|
|
|
|
|
|
return;
|
885
|
|
|
|
|
|
|
}
|
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
if ($self->_seen_true())
|
888
|
|
|
|
|
|
|
{
|
889
|
|
|
|
|
|
|
$self->_suspend() unless $self->_suspended();
|
890
|
|
|
|
|
|
|
return;
|
891
|
|
|
|
|
|
|
}
|
892
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
$expr = $test if @_ == 3;
|
894
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
my $res= $self->_test($expr);
|
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
if($@) {
|
899
|
|
|
|
|
|
|
$self->_suspend() unless $self->_suspended();
|
900
|
|
|
|
|
|
|
return;
|
901
|
|
|
|
|
|
|
}
|
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
if($res) {
|
904
|
|
|
|
|
|
|
$self->_true();
|
905
|
|
|
|
|
|
|
$self->_resume();
|
906
|
|
|
|
|
|
|
} else {
|
907
|
|
|
|
|
|
|
$self->_suspend() unless $self->_suspended();
|
908
|
|
|
|
|
|
|
}
|
909
|
|
|
|
|
|
|
return '';
|
910
|
|
|
|
|
|
|
}
|
911
|
|
|
|
|
|
|
|
912
|
|
|
|
|
|
|
sub else {
|
913
|
|
|
|
|
|
|
my $self = shift;
|
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
if (! $self->_in_if() ) {
|
916
|
|
|
|
|
|
|
$self->SSI_WARN("Incorrect use of else ssi directive: no preceeding 'if'."); # NOTE: just a "warn"
|
917
|
|
|
|
|
|
|
$self->_suspend() unless $self->_suspended();
|
918
|
|
|
|
|
|
|
return;
|
919
|
|
|
|
|
|
|
}
|
920
|
|
|
|
|
|
|
if ($self->_seen_true()) {
|
921
|
|
|
|
|
|
|
$self->_suspend() unless $self->_suspended(); }
|
922
|
|
|
|
|
|
|
else {
|
923
|
|
|
|
|
|
|
$self->_resume(); }
|
924
|
|
|
|
|
|
|
return '';
|
925
|
|
|
|
|
|
|
}
|
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
sub endif {
|
928
|
|
|
|
|
|
|
my $self = shift;
|
929
|
|
|
|
|
|
|
if (! $self->_in_if() )
|
930
|
|
|
|
|
|
|
{
|
931
|
|
|
|
|
|
|
# $self->SSI_ERROR("Incorrect use of endif ssi directive: no preceeding 'if'.");
|
932
|
|
|
|
|
|
|
$self->SSI_WARN("Incorrect use of endif ssi directive: no preceeding 'if'.");
|
933
|
|
|
|
|
|
|
}
|
934
|
|
|
|
|
|
|
else
|
935
|
|
|
|
|
|
|
{ $self->_leaving_if(); }
|
936
|
|
|
|
|
|
|
$self->_resume() if $self->_suspended(); # might be suspended even if not in "if"
|
937
|
|
|
|
|
|
|
return '';
|
938
|
|
|
|
|
|
|
}
|
939
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
#
|
941
|
|
|
|
|
|
|
# if we're called like this, it means that we're to handle a CGI request ourselves.
|
942
|
|
|
|
|
|
|
# that means that we're to open the file and process the content, sending it to STDOUT
|
943
|
|
|
|
|
|
|
# along with a standard HTTP content header
|
944
|
|
|
|
|
|
|
#
|
945
|
|
|
|
|
|
|
unless(caller) {
|
946
|
|
|
|
|
|
|
goto &handler;
|
947
|
|
|
|
|
|
|
}
|
948
|
|
|
|
|
|
|
|
949
|
|
|
|
|
|
|
sub handler {
|
950
|
|
|
|
|
|
|
eval "use CGI qw(:standard);";
|
951
|
|
|
|
|
|
|
print header();
|
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
unless(UNIVERSAL::isa(tied(*STDOUT),'CGI::apacheSSI')) {
|
954
|
|
|
|
|
|
|
tie *STDOUT, 'CGI::apacheSSI', filehandle => 'main::STDOUT';
|
955
|
|
|
|
|
|
|
}
|
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
my $filename = "$ENV{DOCUMENT_ROOT}$ENV{REQUEST_URI}";
|
958
|
|
|
|
|
|
|
if(-f $filename) {
|
959
|
|
|
|
|
|
|
open my $fh, '<', $filename or die "Failed to open file ($filename): $!";
|
960
|
|
|
|
|
|
|
print <$fh>;
|
961
|
|
|
|
|
|
|
} else {
|
962
|
|
|
|
|
|
|
print "Failed to find file ($filename).";
|
963
|
|
|
|
|
|
|
}
|
964
|
|
|
|
|
|
|
|
965
|
|
|
|
|
|
|
exit;
|
966
|
|
|
|
|
|
|
}
|
967
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
#
|
969
|
|
|
|
|
|
|
# packages for tie()
|
970
|
|
|
|
|
|
|
#
|
971
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
package CGI::apacheSSI::Gmt;
|
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
sub TIESCALAR { bless [@_], shift() }
|
975
|
|
|
|
|
|
|
sub FETCH {
|
976
|
|
|
|
|
|
|
my $self = shift;
|
977
|
|
|
|
|
|
|
if($self->[-1]->{'_config'}->{'timefmt'}) {
|
978
|
|
|
|
|
|
|
my @gt = gmtime;
|
979
|
|
|
|
|
|
|
return Date::Format::strftime($self->[-1]->{'_config'}->{'timefmt'},@gt);
|
980
|
|
|
|
|
|
|
} else {
|
981
|
|
|
|
|
|
|
return scalar gmtime;
|
982
|
|
|
|
|
|
|
}
|
983
|
|
|
|
|
|
|
}
|
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
package CGI::apacheSSI::Local;
|
986
|
|
|
|
|
|
|
|
987
|
|
|
|
|
|
|
sub TIESCALAR { bless [@_], shift() }
|
988
|
|
|
|
|
|
|
sub FETCH {
|
989
|
|
|
|
|
|
|
my $self = shift;
|
990
|
|
|
|
|
|
|
if($self->[-1]->{'_config'}->{'timefmt'}) {
|
991
|
|
|
|
|
|
|
my @lt = localtime;
|
992
|
|
|
|
|
|
|
return Date::Format::strftime($self->[-1]->{'_config'}->{'timefmt'},@lt);
|
993
|
|
|
|
|
|
|
} else {
|
994
|
|
|
|
|
|
|
return scalar localtime;
|
995
|
|
|
|
|
|
|
}
|
996
|
|
|
|
|
|
|
}
|
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
package CGI::apacheSSI::LMOD;
|
999
|
|
|
|
|
|
|
|
1000
|
|
|
|
|
|
|
sub TIESCALAR { bless [@_], shift() }
|
1001
|
|
|
|
|
|
|
sub FETCH {
|
1002
|
|
|
|
|
|
|
my $self = shift;
|
1003
|
|
|
|
|
|
|
return $self->[-1]->flastmod('file', $ENV{'SCRIPT_FILENAME'} || $ENV{'PATH_TRANSLATED'} || '');
|
1004
|
|
|
|
|
|
|
}
|
1005
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
1;
|
1007
|
|
|
|
|
|
|
__END__
|