File: files.cgi

package info (click to toggle)
libcgi-tiny-perl 1.003-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 516 kB
  • sloc: perl: 1,307; makefile: 2
file content (40 lines) | stat: -rwxr-xr-x 1,170 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use CGI::Tiny;
use Path::Tiny;
use MIME::Types;
use Unicode::UTF8 qw(encode_utf8 decode_utf8);

cgi {
  my $cgi = $_;

  my $filename = $cgi->query_param('filename');
  unless (length $filename) {
    $cgi->set_response_status(404)->render(text => 'Not Found');
    exit;
  }

  # get files from public/ next to cgi-bin/
  my $public_dir = path(__FILE__)->realpath->parent->sibling('public');
  my $encoded_filename = encode_utf8 $filename;
  my $filepath = $public_dir->child($encoded_filename);

  # ensure file exists, is readable, and is not a directory
  unless (-r $filepath and !-d _) {
    $cgi->set_response_status(404)->render(text => 'Not Found');
    exit;
  }

  # ensure file path doesn't escape the public/ directory
  unless ($public_dir->subsumes($filepath->realpath)) {
    $cgi->set_response_status(404)->render(text => 'Not Found');
    exit;
  }

  my $basename = decode_utf8 $filepath->basename;
  my $mime = MIME::Types->new->mimeTypeOf($basename);
  $cgi->set_response_type($mime->type) if defined $mime;
  $cgi->set_response_disposition(attachment => $basename)->render(file => $filepath);
};