App-phoebe
view release on metacpan - search on metacpan
view release on metacpan or search on metacpan
lib/App/Phoebe.pm view on Meta::CPAN
}
} elsif (@{$server->{wiki_space}}) {
@spaces = @{$server->{wiki_space}};
}
return join("|", map { quotemeta } @spaces);
}
# A regular expression matching parts of reserved paths in URLs. When looking at
# gemini://localhost:1965/page/test or gemini://localhost:1965/do/index and
# using a client that has an "up" command, you'd end up at
# gemini://localhost:1965/page â but what should happen in this case? We should
# redirect these requests to gemini://localhost:1965/, I think.
sub reserved_regex {
return join("|", qw(do page raw file html history diff));
}
sub success {
my $stream = shift;
my $type = shift || 'text/gemini; charset=UTF-8';
my $lang = shift;
if ($lang) {
result($stream, "20", "$type; lang=$lang");
} else {
result($stream, "20", "$type");
}
}
sub result {
my $stream = shift;
my $code = shift;
my $meta = shift;
my $data = shift||"";
$stream->write("$code $meta\r\n$data");
}
sub handle_titan {
my $stream = shift;
my $data = shift;
# extra processing of the request if we didn't do that, yet
$data->{upload} ||= is_upload($stream, $data->{request}) or return;
my $size = $data->{upload}->{params}->{size};
my $actual = length($data->{buffer});
if ($actual == $size) {
$log->debug("Handle Titan request");
process_titan($stream, $data->{request}, $data->{upload}, $data->{buffer}, $size);
# do not close in case we're waiting for the lock
return;
} elsif ($actual > $size) {
$log->debug("Received more than the promised $size bytes");
result($stream, "59", "Received more than the promised $size bytes");
$stream->close_gracefully();
return;
}
$log->debug("Waiting for " . ($size - $actual) . " more bytes");
}
sub process_titan {
my ($stream, $request, $upload, $buffer, $size) = @_;
eval {
local $SIG{'ALRM'} = sub { $log->error("Timeout processing upload $request") };
alarm(10); # timeout
save_page($stream, $upload->{host}, $upload->{space}, $upload->{id},
$upload->{params}->{mime}, $buffer, $size);
alarm(0);
};
return unless $@;
$log->error("Error: $@");
$stream->close_gracefully();
}
sub save_page {
my $stream = shift;
my $host = shift;
my $space = shift;
my $id = shift;
my $type = shift;
my $data = shift;
my $length = shift;
if ($type ne "text/plain") {
if ($length == 0) {
with_lock($stream, $host, $space, sub { delete_file($stream, $host, $space, $id) } );
} else {
with_lock($stream, $host, $space, sub { write_file($stream, $host, $space, $id, $data, $type) } );
}
} elsif ($length == 0) {
with_lock($stream, $host, $space, sub { delete_page($stream, $host, $space, $id) } );
} elsif (utf8::decode($data)) { # decodes in-place and returns success
with_lock($stream, $host, $space, sub { write_page($stream, $host, $space, $id, $data) } );
} else {
$log->debug("The text is invalid UTF-8");
result($stream, "59", "The text is invalid UTF-8");
$stream->close_gracefully();
}
}
# We can't use C<flock> because this defaults to C<fcntl> which means they are
# I<per process>
sub with_lock {
my $stream = shift;
my $host = shift;
my $space = shift;
my $code = shift;
my $count = shift || 0;
my $dir = wiki_dir($host, $space);
my $lock = "$dir/locked";
# remove stale locks
if (-e $lock) {
my $age = time() - modified($lock);
$log->debug("lock is ${age}s old");
rmdir $lock if -e $lock and $age > 5;
}
if (mkdir($lock)) {
$log->debug("Running code with lock $lock");
eval { $code->() }; # protect against exceptions
if ($@) {
$log->error("Unable to run code with locked $lock: $@");
result($stream, "40", "An error occured, unfortunately");
}
rmdir($lock);
$stream->close_gracefully();
view all matches for this distributionview release on metacpan - search on metacpan
( run in 1.042 second using v1.00-cache-2.02-grep-82fe00e-cpan-2c419f77a38b )