File Coverage

lib/Remote/Perl/ModuleServer.pm
Criterion Covered Total %
statement 30 30 100.0
branch 7 8 87.5
condition 6 11 54.5
subroutine 5 5 100.0
pod 0 2 0.0
total 48 56 85.7


line stmt bran cond sub pod time code
1 132     132   1867 use v5.36;
  132         559  
2             package Remote::Perl::ModuleServer;
3             our $VERSION = '0.004';
4              
5 132     132   943 use autodie qw(open close);
  132         273  
  132         853  
6 132     132   65988 use File::Spec;
  132         198  
  132         56245  
7              
8             # Searches a list of directories for a module file and returns its source.
9             #
10             # new(inc => \@dirs, serve_filter => sub($path){...})
11             # inc -- dirs to search; defaults to \@INC if omitted
12             # serve_filter -- optional callback: receives the resolved file path,
13             # returns true to allow serving, false to deny
14             # find($filename) -- returns source string, or undef if not found/denied
15              
16 38     38 0 235 sub new($class, %args) {
  38         92  
  38         185  
  38         94  
17             return bless {
18             inc => $args{inc} // \@INC,
19             serve_filter => $args{serve_filter},
20 38   50     902 }, $class;
21             }
22              
23             # Search for $filename (e.g. 'Foo/Bar.pm') in the configured directories.
24             # Returns the file's raw bytes, or undef if not found.
25             # Rejects filenames containing path traversal sequences.
26 28     28 0 69 sub find($self, $filename) {
  28         75  
  28         56  
  28         48  
27             # Reject any filename with directory traversal components.
28 28         648 my @parts = File::Spec->splitdir($filename);
29 28 100       149 return if grep { $_ eq '..' } @parts;
  116         292  
30              
31 24         40 for my $dir (@{ $self->{inc} }) {
  24         109  
32             # @INC entries can be code refs or objects (handled by Perl itself);
33             # we only search plain directory strings.
34 24 50 33     1177 next unless defined $dir && !ref($dir) && -d $dir;
      33        
35 24         602 my $path = File::Spec->catfile($dir, @parts);
36 24 100       1080 if (-f $path) {
37 18 100 100     115 next if $self->{serve_filter} && !$self->{serve_filter}->($path);
38 16         142 open(my $fh, '<', $path);
39 16         14019 local $/;
40 16         694 return scalar <$fh>;
41             }
42             }
43 8         132 return;
44             }
45              
46             1;
47              
48             __END__