File Coverage

blib/lib/Apache/ASP.pm
Criterion Covered Total %
statement 791 1088 72.7
branch 317 568 55.8
condition 91 189 48.1
subroutine 85 100 85.0
pod 5 45 11.1
total 1289 1990 64.7


line stmt bran cond sub pod time code
1              
2             # For documentation for this module, please see the end of this file
3             # or try `perldoc Apache::ASP`
4              
5             package Apache::ASP;
6              
7             $VERSION = 2.62;
8              
9             #require DynaLoader;
10             #@ISA = qw(DynaLoader);
11             #bootstrap Apache::ASP $VERSION;
12              
13 57     57   5072 use Digest::MD5 qw(md5_hex);
  57         647  
  57         8387  
14 57     57   400 use Cwd qw(cwd);
  57         162  
  57         4884  
15              
16             # create multiple entries for this symbols for StatINC
17 52     52   372 use Fcntl qw(:flock O_RDWR O_CREAT);
  52         202  
  52         10032  
18              
19             # load these always, but only load ::State, ::Session, ::Application
20             # at runtime in non mod_perl environments since they may not be needed
21 52     52   39877 use Apache::ASP::GlobalASA;
  52         266  
  52         2979  
22 47     47   65136 use Apache::ASP::Response;
  47         241  
  47         2141  
23 47     47   37683 use Apache::ASP::Request;
  47         162  
  47         1695  
24 47     47   37325 use Apache::ASP::Server;
  47         127  
  47         1674  
25 47     47   33829 use Apache::ASP::Date;
  46         181  
  46         3997  
26 46     47   35876 use Apache::ASP::Lang::PerlScript;
  46         121  
  46         1898  
27              
28 46     47   5083 use Carp qw(confess cluck);
  46         93  
  46         4116  
29              
30 46     46   258 use strict;
  46         89  
  46         1774  
31 46     46   357 no strict qw(refs);
  46         93  
  46         2312  
32 46         183423 use vars qw($VERSION
33             %NetConfig %LoadedModules %LoadModuleErrors
34             %Codes %includes %Includes %CompiledIncludes
35             @Objects %Register %XSLT
36             $ServerID $ServerPID $SrandPid
37             $CompileErrorSize $CacheSize @CompileChecksumKeys
38             %ScriptLanguages $ShareDir $INCDir $AbsoluteFileMatch
39             $QuickStartTime
40             $SessionCookieName
41             $LoadModPerl
42             $ModPerl2
43 46     46   232 );
  46         86  
44              
45             # other common modules load now, these are optional though, so we do not error upon failure
46             # just do this once perl mod_perl parent startup
47             unless($LoadModPerl++) {
48             my @load_modules = qw( Config lib Time::HiRes );
49             if($ENV{MOD_PERL}) {
50             # Only pre-load these if in a mod_perl environment for sharing memory post fork.
51             # These will not be loaded then for CGI until absolutely necessary at runtime
52             push(@load_modules, qw(
53             mod_perl
54             MLDBM::Serializer::Data::Dumper Devel::Symdump CGI
55             Apache::ASP::StateManager Apache::ASP::Session Apache::ASP::Application
56             Apache::ASP::StatINC Apache::ASP::Error
57             )
58             );
59             }
60            
61             for my $module ( @load_modules ) {
62 46     46   461 eval "use $module ();";
  46     46   111  
  46     46   573  
  46         48237  
  46         35450  
  46         565  
  46         51076  
  46         137956  
  46         844  
63             }
64              
65             if(exists $ENV{MOD_PERL_API_VERSION}) {
66             if($ModPerl2 = ($ENV{MOD_PERL_API_VERSION} >= 2)) {
67             if($ModPerl2) {
68             eval "use Apache::ASP::ApacheCommon ();";
69             die($@) if $@;
70             }
71             }
72             }
73             }
74              
75             ## HEADER TOKEN TWEAK
76             # This must be called outside the above load module block, so that
77             # its gets run whenever this module is loaded
78             # This didn't work in 1.27 mod_perl, with DSO enabled, would
79             # put the Apache::ASP token in front.
80             # eval { &Apache::add_version_component("Apache::ASP/$VERSION"); };
81             # $Apache::Server::AddPerlVersion = 1;
82              
83             #use integer; # don't use screws up important numeric logic
84              
85             @Objects = ('Application', 'Session', 'Response', 'Server', 'Request');
86 45     45 0 953 map { eval "sub $_ { shift->{$_} }" } @Objects;
  0     0 0 0  
  0     0 0 0  
  0     0 0 0  
  23     23 0 1227  
87              
88             # use regexp directly, not sub for speed
89             $AbsoluteFileMatch = '^(/|[a-zA-Z]:)';
90             $CacheSize = 1024*1024*10;
91             $SessionCookieName = 'session-id';
92              
93             # ServerID creates a unique identifier for the server
94             srand();
95             $ServerID = substr(md5_hex($$.rand().time().(-M('..')||'').(-M('/')||'')), 0, 16);
96             $ServerPID = $$;
97              
98             # DEFAULT VALUES
99             $Apache::ASP::CompileErrorSize = 500;
100             @CompileChecksumKeys = qw ( Global DynamicIncludes UseStrict XMLSubsMatch XMLSubsPerlArgs XMLSubsStrict GlobalPackage UniquePackages IncludesDir InodeNames PodComments );
101              
102             %ScriptLanguages = (
103             'PerlScript' => 1,
104             );
105              
106             &InitPaths();
107              
108             %Apache::ASP::LoadModuleErrors =
109             (
110             'Filter' =>
111             "Apache::Filter was not loaded correctly for using SSI filtering. ".
112             "If you don't want to use filtering, make sure you turn the Filter ".
113             "config option off whereever it's being used",
114              
115             Clean => undef,
116            
117             CreateObject =>
118             'OLE-active objects not supported for this platform, '.
119             'try installing Win32::OLE',
120            
121             Gzip =>
122             'Compress::Zlib is needed to make gzip content-encoding work, '.
123             'If you want to use this feature, get yourself the latest '.
124             'Compress::Zlib from CPAN. ',
125            
126             HiRes => undef,
127              
128             FormFill =>
129             'HTML::FillInForm is needed to use the FormFill feature '.
130             'for auto filling forms with $Response->Form() data',
131              
132             MailAlert => undef,
133            
134             SendMail => "No mailing support",
135            
136             StateDB =>
137             'cannot load StateDB '.
138             'must be a valid perl module with a db tied hash interface '.
139             'such as: SDBM_File (default), or DB_File',
140            
141             StateSerializer =>
142             'cannot load StateSerializer '.
143             'must be a valid serializing perl module for use with MLDBM '.
144             'such as Data::Dumper (default), or Storable',
145              
146             StatINC => "You need this module for StatINC, please download it from CPAN",
147            
148             'Cache' => "You need this module for xml output caching",
149              
150             XSLT => 'Cannot load XML::XSLT. Try installing the module.',
151              
152             );
153              
154              
155             sub handler {
156 48     48 0 210 my($package, $r) = @_;
157 48         130 my $status = 200;
158            
159             # allows it to be called as an object method
160 48 100       381 ref $package and $r = $package;
161              
162             # default to Apache request object if not passed in, for possible DSO fix
163             # rarely happens, but just in case
164 48         103 my $filename;
165 48 50       133 unless($filename = eval { $r->filename }) {
  48         2336  
166 0 0       0 my $rtest = $ModPerl2 ? Apache2::RequestUtil->request() : Apache->request();
167 0 0       0 if($filename = eval { $rtest->filename }) {
  0         0  
168 0         0 $r = $rtest;
169             } else {
170 0         0 return &DSOError($rtest);
171             }
172             }
173              
174             # better error checking ?
175 48   33     743 $filename ||= $r->filename();
176             # using _ is optimized to use last stat() record
177 48 50 33     2090 return(404) if (! -e $filename or -d _);
178              
179             # alias $0 to filename, bind to glob for bug workaround
180 48         187 local *0 = \$filename;
181              
182             # ASP object creation, a lot goes on in there!
183             # method call used for speed optimization, as OO calls are slow
184 48         292 my $self = &Apache::ASP::new('Apache::ASP', $r, $filename);
185              
186             # for runtime use/require library loads from global/INCDir
187             # do this in the handler section to cover all the execution stages
188             # following object set up as possible.
189 48         692 local @INC = ($self->{global}, $INCDir, @INC);
190              
191             # Execute if no errors
192 48 50       1499 $self->{errs} || &Run($self);
193            
194             # moved print of object to the end, so we'll pick up all the
195             # runtime config directives set while the code is running
196              
197 48 100       277 $self->{dbg} && $self->Debug("ASP Done Processing $self", $self );
198              
199             # error processing
200 48 50       215 if($self->{errs}) {
201 0         0 require Apache::ASP::Error;
202 0         0 $status = $self->ProcessErrors;
203             }
204              
205             # XX return code of 302 hangs server on WinNT
206             # STATUS hook back to Apache
207 48         147 my $response = $self->{Response};
208 48 50 66     537 if($status != 500 and defined $response->{Status} and $response->{Status} != 302) {
      66        
209             # if still default then set to what has been set by the
210             # developer
211 0         0 $status = $response->{Status};
212             }
213              
214             # X: we DESTROY in register_cleanup, but if we are filtering, and we
215             # handle a virtual request to an asp app, we need to free up the
216             # the locked resources now, or the session requests will collide
217             # a performance hack would be to share an asp object created between
218             # virtual requests, but don't worry about it for now since using SSI
219             # is not really performance oriented anyway.
220             #
221             # If we are not filtering, we let RegisterCleanup get it, since
222             # there will be a perceived performance increase on the client side
223             # since the connection is terminated before the garabage collection is run.
224             #
225             # Also need to destroy if we return a 500, as we could be serving an
226             # error doc next, before the cleanup phase
227              
228 48 50 33     1706 if($self->{filter} || ($status == 500) || ( $r->isa('Apache::ASP::CGI'))) {
      33        
229 48         256 $self->DESTROY();
230             }
231              
232 48 50       228 if($status eq '200') {
233 48         108 $status = 0; # OK status code is default unless there was an internal error
234             }
235              
236 48         347 $status;
237             }
238              
239             sub Warn {
240 0 0 0 0 0 0 shift if(ref($_[0]) or $_[0] eq 'Apache::ASP');
241 0         0 print STDERR "[ASP WARN] ", @_;
242             }
243              
244             sub new {
245 69     69 0 346 my($class, $r, $filename) = @_;
246 69 50       286 $r || die("need Apache->request() object to Apache::ASP->new(\$r)");
247              
248             # $StartTime is set by asp-perl early on before modules are loaded
249             # for more accurate per time tracking. Unset, so this init load time does
250             # not get used more than once.
251 69         325 my $start_time;
252 69 100       262 if($QuickStartTime) {
253 1         3 $start_time = $QuickStartTime;
254 1         4 $QuickStartTime = undef;
255             } else {
256 68   33     155 $start_time = eval { &Time::HiRes::time(); } || time();
257             }
258              
259 69         601 local $SIG{__DIE__} = \&Carp::confess;
260             # like cgi, operate in the scripts directory
261 69   66     855 $filename ||= $r->filename();
262 69         1001 $filename =~ m|^(.*?[/\\]?)([^/\\]+)$|;
263 69   100     403 my $dirname = $1 || '.';
264 69         499 my $basename = $2;
265 69 50       1729 chdir($dirname) || die("can't chdir to $dirname: $!");
266              
267             # temp object just to call config() on, do not bless since we
268             # do not want the object to be DESTROY()'d
269 69         2165 my $dir_config = $r->dir_config;
270 69         2427 my $headers_in = $r->headers_in;
271 69         855 my $self = { r => $r, dir_config => $dir_config };
272              
273             # global is the default for the state dir and also
274             # a default lib path for perl, as well as where global.asa
275             # can be found
276 69   100     420 my $global = &get_dir_config($dir_config, 'Global') || '.';
277 69         417 $global = &AbsPath($global, $dirname);
278              
279             # asp object is handy for passing state around
280 69 50 100     416 $self = bless
281             {
282             'basename' => $basename,
283             'cleanup' => [],
284             'dbg' => &get_dir_config($dir_config, 'Debug') || 0, # debug level
285             'destroy' => 1,
286             'dir_config' => $dir_config,
287             'headers_in' => $headers_in,
288             filename => $filename,
289             global => $global,
290             global_package => &get_dir_config($dir_config, 'GlobalPackage'),
291             inode_names => &get_dir_config($dir_config, 'InodeNames'),
292             no_cache => &get_dir_config($dir_config, 'NoCache'),
293             'r' => $r, # apache request object
294             start_time => $start_time,
295             stat_scripts => &config($self, 'StatScripts', undef, 1),
296             stat_inc => &get_dir_config($dir_config, 'StatINC'),
297             stat_inc_match => &get_dir_config($dir_config, 'StatINCMatch'),
298             use_strict => &get_dir_config($dir_config, 'UseStrict'),
299             win32 => ($^O eq 'MSWin32') ? 1 : 0,
300             xslt => &get_dir_config($dir_config, 'XSLT'),
301             }, $class;
302              
303             # Only if debug is negative do we kick out all the internal stuff
304 69 100       2454 if($self->{dbg}) {
305 9 50       37 if($self->{dbg} < 0) {
306 0         0 *Debug = *Out;
307 0         0 $self->{dbg} = -1 * $self->{dbg};
308             } else {
309 9         54 *Debug = *Null;
310             }
311 9         211 $self->Debug('RUN ASP (v'. $VERSION .") for $self->{filename}");
312              
313             } else {
314 60         377 *Debug = *Null;
315             }
316            
317             # Ken said no need for seed ;), now we just make sure its called post fork
318             # Patch from Ime suggested no need for %SrandPid, just srand() again when $$ has changed
319 69 100 66     712 unless($SrandPid && $SrandPid == $$) {
320 46 100       398 $self->{dbg} && $self->Debug("call srand() post fork");
321 46         2499 srand();
322 46         273 $SrandPid = $$;
323             }
324              
325             # filtering support
326 69         241 my $filter_config = &get_dir_config($dir_config, 'Filter');
327 69 50       286 if($filter_config) {
328 0 0       0 if($self->LoadModules('Filter', 'Apache::Filter')) {
329             # new filter_register with Apache::Filter 1.013
330 0 0       0 if($r->can('filter_register')) {
331 0         0 $self->{r} = $r = $r->filter_register;
332             }
333            
334 0 0 0     0 if ($r->can('filter_input') && $r->can('get_handlers')) {
335 0         0 $self->{filter} = 1;
336             #X: do something with the return code, can't now because
337             # apache constants aren't working on my win32
338 0         0 my($fh, $rc) = $r->filter_input();
339 0         0 $self->{filehandle} = $fh;
340             }
341             } else {
342 0 0       0 if(! $r->can('get_handlers')) {
343 0         0 $self->Error("You need at least mod_perl 1.16 to use SSI filtering");
344             } else {
345 0         0 $self->Error("Apache::Filter was not loaded correctly for using SSI filtering. ".
346             "If you don't want to use filtering, make sure you turn the Filter ".
347             "config option off whereever it's being used");
348             }
349             }
350             }
351            
352             # gzip content encoding option by ime@iae.nl 28/4/2000
353 69         491 my $compressgzip_config = &get_dir_config($dir_config, 'CompressGzip');
354 69 50       330 if($compressgzip_config) {
355 0 0       0 if($self->LoadModule('Gzip','Compress::Zlib')) {
356 0         0 $self->{compressgzip} = 1;
357             }
358             }
359            
360             # must have global directory into which we put the global.asa
361             # and possibly state files, optimize out the case of . or ..
362 69 100       1355 if($self->{global} !~ /^(\.|\.\.)$/) {
363 28 50       1140 -d $self->{global} or
364             $self->Error("global path, $self->{global}, is not a directory");
365             }
366              
367             # includes_dir calculation
368 69 100       435 if($filename =~ m,^((/|[a-zA-Z]:).*[/\\])[^/\\]+?$,) {
369 2         9 $self->{dirname} = $1;
370             } else {
371 67         293 $self->{dirname} = '.';
372             }
373 69   50     700 $self->{includes_dir} = [
374             $self->{dirname},
375             $self->{global},
376             split(/;/, &config($self, 'IncludesDir') || ''),
377             ];
378              
379             # register cleanup before the state files get set in InitObjects
380             # this way DESTROY gets called every time this script is done
381             # we must cache $self for lookups later
382 69     67   908 &RegisterCleanup($self, sub { $self->DESTROY });
  67         228  
383              
384             #### WAS INIT OBJECTS, REMOVED DECOMP FOR SPEED
385              
386             # GLOBALASA, RESPONSE, REQUEST, SERVER
387             # always create these
388             # global_asa assigns itself to parent object automatically
389 69         583 my $global_asa = &Apache::ASP::GlobalASA::new($self);
390 69         507 $self->{Request} = &Apache::ASP::Request::new($self);
391 69         894 $self->{Response} = &Apache::ASP::Response::new($self);
392             # Server::new() is just one line, so execute directly
393 69         575 $self->{Server} = bless {asp => $self}, 'Apache::ASP::Server';
394             #&Apache::ASP::Server::new($self);
395              
396             # After GlobalASA Init, init the package that this script will execute in
397             # must be here, and not end of new before things like Application_OnStart get run
398             # UniquePackages & NoCache configs do not work together, NoCache wins here
399 69 100       338 if(&config($self, 'UniquePackages')) {
400             # id is not generally useful for the ASP object now, so calculate
401             # it here now, only to twist the package object for this script
402              
403             # pass in basename for where to find the file for InodeNames, and the full path
404             # for the FileId otherwise
405 1         7 my $package = $global_asa->{'package'}.'::'.&FileId($self, $self->{basename}, $self->{filename});
406 1         4 $self->{'package'} = $package;
407 1         6 $self->{init_packages} = ['main', $global_asa->{'package'}, $self->{'package'}];
408             } else {
409 68         222 $self->{'package'} = $global_asa->{'package'};
410 68         401 $self->{init_packages} = ['main', $global_asa->{'package'}];
411             }
412              
413 69         359 $self->{state_dir} = &config($self, 'StateDir', undef, $self->{global}.'/.state');
414 69         255 $self->{state_dir} =~ tr///; # untaint
415              
416             # if no state has been config'd, then set up none of the
417             # state objects: Application, Internal, Session
418 69 100       421 unless(&get_dir_config($dir_config, 'NoState')) {
419             # load at runtime for CGI environments, preloaded for mod_perl
420 28         7799 require Apache::ASP::StateManager;
421 28         136 &InitState($self);
422             }
423              
424 69         644 $self;
425             }
426              
427             # called upon every end of connection by RegisterCleanup
428             sub DESTROY {
429 135     135   471 my $self = shift;
430              
431 135 100       721 return unless $self->{destroy}; # still active object
432 68 100       293 $self->{dbg} && $self->Debug("destroying ASP object $self");
433              
434             # do before undef'ing the object references in main
435 68         139 for my $code ( @{$self->{cleanup}} ) {
  68         370  
436 0 0       0 $self->{dbg} && $self->Debug("executing cleanup $code");
437 0         0 eval { &$code() };
  0         0  
438 0 0       0 $@ && $self->Error("executing cleanup $code error: $@");
439             }
440              
441 68         326 local $^W = 0; # suppress untie while x inner references warnings
442 68         395 select(STDOUT);
443 68 100       741 untie *RESPONSE if tied *RESPONSE;
444              
445             # can't move this to Request::DESTROY(), then CGI object compatibility
446             # in test ./site/eg/cgi.htm test fails, don't know why, --jc, 12/06/2002
447 68 50       288 untie *STDIN if tied *STDIN;
448              
449             # in case there is a dummy session here by the
450             # end of object execution
451 68 100       291 if($self->{Session}) {
452 28 50       58 if(eval { $self->{Session}->isa('Apache::ASP::Session') }) {
  28         255  
453             # only the cleanup master may cleanup groups now, so OK
454             # to call just CleanupGroups
455 28         155 $self->CleanupGroups();
456             } else {
457 0         0 $self->Debug("$self->{Session} is not an Apache::ASP::Session");
458 0         0 eval { $self->{Session}->DESTROY };
  0         0  
459 0         0 $self->{Session} = undef;
460             }
461             }
462              
463             # free file handles here. mod_perl tends to be pretty clingy
464             # to memory
465 68         221 for('Application', 'Internal', 'Session') {
466             # all this stuff in here is very necessary for total cleanup
467             # the DESTROY is the most important, as we need to explicitly free
468             # state objects, just in case anyone else is keeping references to them
469             # But the destroy won't work without first untieing, go figure
470 204 100       757 next unless defined $self->{$_};
471 84         95 my $tied = tied %{$self->{$_}};
  84         189  
472 84 50       199 next unless $tied;
473 84         95 untie %{$self->{$_}};
  84         352  
474 84         297 $tied->DESTROY(); # call explicit DESTROY
475             }
476              
477 68 100       579 if(my $caches = $self->{Caches}) {
478             # default cache size to 10M
479 1   33     3 $self->{cache_size} = &config($self, 'CacheSize') || $CacheSize;
480 1 50       12 if($self->{cache_size} =~ /^([\d\.]+)(M|K|B)?$/) {
481 1         6 my($size, $unit) = ($1, $2);
482 1 50       7 if($unit eq 'M') {
    50          
483 0         0 $size *= 1024*1024;
484             } elsif($unit eq 'K') {
485 1         6 $size *= 1024;
486             }
487 1 50       5 if($size ne $self->{cache_size}) {
488 1 50       4 $self->{dbg} && $self->Debug("converting CacheSize $self->{cache_size} to $size bytes");
489 1         2 $self->{cache_size} = $size;
490             }
491             }
492 1         4 for my $cache (values %$caches) {
493 1         2 my $tied = $cache;
494 1 50 33     11 if($tied->{writes} && $tied->Size > $self->{cache_size}) {
495 1 50       157 $self->{dbg} && $self->Debug("deleting cache $cache, size: ".$tied->Size);
496 1         7 $tied->Delete;
497             } else {
498 0 0       0 $self->{dbg} && $self->Debug("cache $cache OK size, size: ".$tied->Size);
499             }
500 1         2596 $tied->DESTROY();
501             }
502             }
503              
504             # $self->{'dbg'} && $self->Debug("END ASP DESTROY");
505 68 50       655 $self->{Request} && &Apache::ASP::Request::DESTROY($self->{Request});
506 68 50       377 $self->{Server} && ( %{$self->{Server}} = () );
  68         235  
507 68 50       323 $self->{Response} && ( %{$self->{Response}} = () );
  68         488  
508 68         2244 %$self = ();
509              
510 68         280 1;
511             }
512              
513             sub RegisterCleanup {
514 79     79 1 211 my $self = shift;
515              
516 79 50       311 if($ModPerl2) {
517 0         0 $self->{r}->pool->cleanup_register(@_);
518             } else {
519 79         512 $self->{r}->register_cleanup(@_);
520             }
521             }
522              
523             sub InitPaths {
524              
525             # we load this module just to detect where the shared directory really is
526 46     46   45641 use Apache::ASP::Share::CORE;
  46         183  
  46         1033898  
527              
528             # major problem with %INC if we cannot get this information
529 46   50 46 0 319 my $share_path = $INC{'Apache/ASP/Share/CORE.pm'}
530             || die(q(can't find path for $INC{'Apache/ASP/Share/CORE.pm'}));
531              
532 46         374 $share_path =~ s/CORE\.pm$//s;
533 46 100       1951 unless($share_path =~ /$AbsoluteFileMatch/) {
534             # this %ENV manipulation is just to allow cwd() to run in taint check mode
535 2         318 local %ENV = %ENV;
536 2         54 $ENV{PATH} = '/bin:/usr/bin:/usr/sbin';
537 2         35 delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
538 2         10694 my $currdir = cwd();
539 2         399 $share_path = "$currdir/$share_path";
540             }
541              
542             # not finding the ShareDir creates a hard error, because the Apache/ASP/Share
543             # directory will become one of the fundamental underpinings of the project
544             # People will need to rely on being able to load shared includes, and not have
545             # to discover the lack of loading Share:: at runtime, rather this is a compile
546             # time error.
547 46 50       1903 -d $share_path || die("Apache::ASP::Share directory not found. ".
548             "Please make sure to install all the modules that make up the Apache::ASP installation."
549             );
550 46         178 $ShareDir = $share_path;
551              
552             # once we find the $ShareDir, we can truncate the library path
553             # and push it onto @INC with use lib... this is to help with loading
554             # future Apache::ASP::* modules when the lib path it was found at is
555             # relative to some directory. This was needed to have the "make test"
556             # test suite to work which loads libraries from "blib/lib", but Apache::ASP
557             # will chdir() into the script directory so that can ruin this
558             # library lookup.
559             #
560 46         131 my $lib_path = $share_path;
561 46         1094 $lib_path =~ s/Apache.ASP.Share.?$//s;
562 46 50       1159 -d $lib_path || die("\%INC library path $lib_path not found.");
563 46         247 $INCDir = $lib_path;
564            
565             # clear taint, for some reason, tr/// or s/^(.*)$/ did not work on perl 5.6.1
566 46         356 $INCDir =~ /^(.*)$/s;
567 46         232 $INCDir = $1;
568              
569             # make sure this gets on @INC at startup, can't hurt
570 46     46   389 eval "use lib qw($INCDir);";
  46         121  
  46         450  
  46         6933  
571              
572 46         16330 1;
573             }
574              
575             sub FileId {
576 160     160 0 441 my($self, $file, $abs_file, $no_compile_checksum) = @_;
577 160 50       494 $file || die("no file passed to FileId()");
578 160         245 my $id;
579              
580             # calculate compile checksum for file id
581 160 100       653 unless($self->{compile_checksum}) {
582 69         169 my $r = $self->{r};
583 759 100       1554 my $checksum = md5_hex(join('&-+',
584             $VERSION,
585 69         253 map { &config($self, $_) || '' }
586             @CompileChecksumKeys
587             )
588             );
589             # $self->{dbg} && $self->Debug("compile checksum $checksum");
590 69         616 $self->{compile_checksum} = $checksum;
591             }
592              
593 160 100       534 my $compile_checksum = $no_compile_checksum ? '' : $self->{compile_checksum};
594              
595 160         367 my @inode_stat = ();
596 160 100       672 if($self->{inode_names}) {
597 1         13 @inode_stat = stat($file);
598             # one or the other device or file ids must be not 0
599 1 0 33     5 unless($inode_stat[0] || $inode_stat[1]) {
600 0         0 @inode_stat = ();
601             }
602             }
603              
604 160 100       805 if(@inode_stat) {
605 1         7 $id = sprintf("____DEV%X_INODE%X",@inode_stat[0,1]);
606 1         4 $id .= 'x'.$compile_checksum;
607             } else {
608 159 100       2786 if($abs_file) {
609 1         3 $file = $abs_file;
610             }
611 159         832 $file =~ s|/+|/|sg;
612 159         988 $file =~ s/[\Wx]/_/sg;
613 159         357 my $file_name_length = length($file);
614 159 100       571 if($file_name_length >= 35) {
615 9         30 $id = substr($file, $file_name_length - 35, 36);
616             # only do the hex of the original file to create a unique identifier for the long id
617 9         84 $id .= 'x'.&md5_hex($file.$compile_checksum);
618             } else {
619 150         481 $id = $file.'x'.$compile_checksum;
620             }
621             }
622              
623 160         692 $id = '__ASP_'.$id;
624             }
625              
626             # defaults to parsing the script's file, or data from a file handle
627             # in the case of filtering, but we can also pass in text to parse,
628             # which is useful for doing includes separately for compiling
629             sub Parse {
630 96     96 0 251 my($self, $file) = @_;
631 96         168 my $file_exists = 0;
632 96         273 my $parse_file = $file;
633 96         214 my $r = $self->{r};
634 96         152 my $data;
635              
636             # get script data, from varied data sources;
637 96 50       334 $file || die("can't parse without file data");
638              
639 96 100       397 $self->{dbg} && $self->Debug("parse file $file");
640             # file can be a filename, scalar ref, or scalar
641 96 100 33     1875 if(ref $file) {
    50 33        
642 22 50       107 if ($file =~ /SCALAR/) {
    0          
643 22         53 $data = $$file;
644             } elsif ($file =~ /GLOB/) {
645 0         0 local $/ = undef;
646 0         0 $data = <$file>
647             }
648             } elsif((length($file) < 1024) && ($file !~ /^GLOB/) && (-e $file)) {
649             # filename has length < 1024, should be fine across OS's
650 74 100       440 $self->{dbg} && $self->Debug("parsing $file");
651 74         125 $data = ${$self->ReadFile($file)};
  74         314  
652 74         272 $file_exists = 1;
653 74         333 $self->{parse_file_count}++;
654             } else {
655 0         0 $data = $file; # raw script, no ref
656             }
657              
658             # moved parsing config here since not needed for normal
659             # eval execution of scripts after compilation
660 96 100       731 unless($self->{parse_config}) {
661 50         146 $self->{parse_config} = 1;
662 50         171 $self->{compile_includes} = &config($self, 'DynamicIncludes');
663 50         347 $self->{pod_comments} = &config($self, 'PodComments', undef, 1);
664 50         157 $self->{xml_subs_strict} = &config($self, 'XMLSubsStrict');
665             # default XMLSubsPerlArgs to 1 for now, until 3.0
666 50         176 $self->{xml_subs_perl_args} = &config($self, 'XMLSubsPerlArgs', undef, 1);
667              
668             # reduce (pattern) patterns to (?:pattern) to not create $1 side effect
669 50 100       177 if($self->{xml_subs_match} = &config($self, 'XMLSubsMatch')) {
670 10         45 $self->{xml_subs_match} =~ s/\(\?\:([^\)]*)\)/($1)/isg;
671 10         36 $self->{xml_subs_match} =~ s/\(([^\)]*)\)/(?:$1)/isg;
672             }
673              
674 50         188 my $lang = &config($self, 'ScriptLanguage', undef, 'PerlScript');
675 50         182 my $module = "Apache::ASP::Lang::".$lang;
676 50 50       300 unless($ScriptLanguages{$lang}) {
677             # eval "use $module;";
678 0         0 $self->Error("ScriptLanguage for $lang could not be loaded: $@");
679 0         0 return;
680             }
681 50         110 eval {
682 50         799 my $lang_object = $module->new(ASP => $self);
683 50         173 $self->{lang_object} = $lang_object;
684 50         145 $self->{lang_module} = $module;
685 50         127 $self->{lang_language} = $lang;
686 50         304 $self->{lang_comment} = $lang_object->CommentStart;
687             };
688 50 50       477 if($@) {
689 0         0 $self->Error("ScriptLanguage object for $lang failed init: $@");
690 0         0 return;
691             }
692             }
693              
694 96         324 my $comment = $self->{lang_comment};
695 96 100       285 if(&config($self, 'CgiDoSelf')) {
696 85         540 $data =~ s,^(.*?)__END__,,so;
697             }
698              
699             # do both before and after, so =pods can span includes with =pods
700 96 50       416 if($self->{pod_comments}) {
701 96         383 &PodComments($self, \$data);
702             }
703              
704             # if compiling includes, then do now before includes conversion
705             # each include will also have its Script_OnParse run on it.
706 96 50 33     804 if($self->{compile_includes} && $self->{GlobalASA}{'exists'}) {
707 0         0 $self->{Server}{ScriptRef} = \$data;
708 0         0 $self->{GlobalASA}->ExecuteEvent('Script_OnParse');
709             }
710              
711             # do includes as early as possible !! so included text gets done too
712             # this section is for file includes, we do this here instead of ssi
713             # so it can be parsed and compiled with the script
714 96         248 local %includes; # trap recursive includes with this
715              
716             # JUST ONCE
717             # there should only be one of these, <%@ LANGUAGE="PerlScript" %>, rip it out
718             # we keep white space and substitue text in so the perlscript sync's up with lines
719             # only take out the first one
720 96         233 $data =~ s/^\#\![^\n]+(\n\s*)/\<\%$1\%\>/s; #X cgi compat ?
721 96         490 $data =~ s/^(\s*)\<\%(\s*)\@([^\n]*?)\%\>/$1\<\%$2 ; \%\>/so;
722              
723 96         188 my $root_file = $file;
724 96         163 my $line1_added = 0;
725 96         189 my $munge = $data;
726 96         177 $data = '';
727 96         154 my($file_context, $file_line_number, $code_block);
728 96         549 while($munge =~ s/^(.*?)\