App-MBUtiny
view release on metacpan or search on metacpan
eg/server.cgi view on Meta::CPAN
Copyright (C) 1998-2019 D&D Corporation. All Rights Reserved
=head1 LICENSE
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
See C<LICENSE> file and L<https://dev.perl.org/licenses/>
=cut
use CGI qw/-putdata_upload/;
use Cwd qw/getcwd/;
use Fcntl qw(:flock);
use File::Spec;
use File::Path qw/mkpath/;
use File::Find;
use constant BASE_URI_PREFIX => '/mbuserver';
#use constant BASE_URI_PREFIX => '/server.cgi';
use constant {
CONTENT_TYPE => 'text/plain',
DEFAULT_METHOD => 'GET',
DEFAULT_PATH => '/',
BUFFER_SIZE => 4*1024, # 4kB
};
my $q = new CGI;
my $meth = $q->request_method || DEFAULT_METHOD;
my $ruri = $q->request_uri || DEFAULT_PATH;
$ruri =~ s/[?\#](.*)$//;
$ruri =~ s/\/+$//;
my $path = $ruri;
my $info = $q->path_info();
if ($info) {
$path = $info;
} else {
my $i = index($path, BASE_URI_PREFIX);
substr($path, $i, length(BASE_URI_PREFIX), '') if $i > -1;
}
$path = DEFAULT_PATH unless length($path);
my $reqkey = sprintf("%s %s", $meth, $path);
my $root = $ENV{DOCUMENT_ROOT} // getcwd();
if ($reqkey eq 'GET /') { # lwp-request -E "http://localhost/mbuserver"
print $q->header(-type => CONTENT_TYPE, -charset => 'utf-8',);
print get_list($root);
} elsif ($meth eq 'GET') { # lwp-request -E "http://localhost/mbuserver/foo/bar/test.txt"
my $file = File::Spec->catfile($root, $path);
if (-f $file) {
raise("Incorrect path: %s. Check BASE_URI_PREFIX constant first", $ruri) if $ruri eq $path;
print $q->redirect($path);
} elsif (-d $file) {
print $q->header(-type => CONTENT_TYPE, -charset => 'utf-8',);
print get_list($file);
} else {
print $q->header(
-type => CONTENT_TYPE,
-charset => 'utf-8',
-status => '404 Not Found',
);
print "Not Found";
}
} elsif ($meth eq 'HEAD') { # lwp-request -E -m HEAD "http://localhost/mbuserver/foo/bar/test.txt"
my $file = File::Spec->catfile($root, $path);
if (-f $file) {
raise("Incorrect path: %s. Check BASE_URI_PREFIX constant first", $ruri) if $ruri eq $path;
print $q->redirect($path);
} elsif (-d $file) {
my $content = get_list($file);
print $q->header(-type => CONTENT_TYPE, -charset => 'utf-8', -content_length => length($content));
} else {
print $q->header(
-type => CONTENT_TYPE,
-charset => 'utf-8',
-status => '404 Not Found',
);
}
} elsif ($meth eq 'PUT') { # lwp-request -E -m PUT -c "application/octet-stream" "http://localhost/mbuserver/foo/bar/test.txt" < test.txt
# Get filename
my ($volume, $directories, $file) = File::Spec->splitpath( $path );
my $dir = File::Spec->catfile($root, $directories);
unless (-d $dir or -l $dir) {
mkpath( $dir, {verbose => 0} );
}
# Uploading
my $out_file = File::Spec->catfile($dir, $file);
my $got_size = 0;
UPLOADBLOCK: {
my $buffer = "";
my $io_handle = $q->upload('PUTDATA') or last UPLOADBLOCK;
open( MBUUPLOAD, '>', $out_file ) or raise("Can't open file %s", $out_file);
flock(MBUUPLOAD, LOCK_EX) or raise("Can't lock file %s: %s", $out_file, $!);
binmode(MBUUPLOAD);
while (my $bytesread = $io_handle->read($buffer, BUFFER_SIZE) ) {
print MBUUPLOAD $buffer;
$got_size += $bytesread;
}
close MBUUPLOAD;
}
raise("Can't upload file %s", $file) unless $got_size && $got_size == -s $out_file;
# Response
print $q->header(
-type => 'application/octet-stream',
-content_location => $ruri,
-status => '201 Created',
);
} elsif ($meth eq 'DELETE') { # lwp-request -E -m DELETE "http://localhost/mbuserver/foo/bar/test.txt"
my $file = File::Spec->catfile($root, $path);
if (-f $file) {
unlink $file or raise("Could not unlink %s: %s", $file, $!);
print $q->header(
-status => '204 No Content',
);
} elsif (-d $file) {
print $q->header(
-type => CONTENT_TYPE,
-charset => 'utf-8',
-status => '405 Method Not Allowed',
);
print "Method Not Allowed";
} else {
print $q->header(
-type => CONTENT_TYPE,
-charset => 'utf-8',
-status => '404 Not Found',
);
print "Not Found";
}
} else {
print $q->header(
-type => CONTENT_TYPE,
-charset => 'utf-8',
-status => '501 Not Implemented',
);
printf "Not Implemented: %s", $reqkey;
}
sub get_list {
my $r = shift || $root;
my $name = $q->param("name") || $q->param("host");
my @list = ();
find({wanted => sub {
return if $File::Find::dir ne $r;
return if $name && index($_, $name) < 0;
push @list, $_ if -f $_;
}}, $r);
return join "\n", @list;
}
sub raise {
my $format = shift || "Unknown error";
my @err = @_;
print $q->header(
-type => CONTENT_TYPE,
-charset => 'utf-8',
-status => '500 Internal Server Error',
);
printf $format, @err;
exit 0;
}
1;
__END__
( run in 2.755 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )