App-phoebe
view release on metacpan or search on metacpan
lib/App/Phoebe/Spartan.pm view on Meta::CPAN
use utf8;
no warnings 'redefine';
our $spartan_port ||= 300;
use Mojo::IOLoop;
# start the loop after configuration (so that the user can change $spartan_port)
Mojo::IOLoop->next_tick(\&spartan_startup);
sub spartan_startup {
for my $host (keys %{$server->{host}}) {
for my $address (get_ip_numbers($host)) {
for my $port (ref $spartan_port ? @$spartan_port : $spartan_port) {
$log->info("$host: listening on $address:$port (Spartan)");
Mojo::IOLoop->server({
address => $address,
port => $port,
} => sub {
my ($loop, $stream) = @_;
my $buffer;
my $request_host;
my $path;
my $length;
$stream->on(read => sub {
my ($stream, $bytes) = @_;
$log->debug("Received " . length($bytes) . " bytes via Spartan");
$buffer .= $bytes;
if (not $length and $buffer =~ /^(.*)\r\n/) {
my $request_line = $1;
if (($request_host, $path, $length) = $request_line =~ /^(\S+) (\S+) (\d+)/) {
my $re = host_regex();
if ($request_host !~ /^($re)$/) {
result($stream, "4", "We do not serve $request_host!");
$stream->close_gracefully();
return;
}
$buffer =~ s/^.*\r\n//; # strip request line
} else {
result($stream, "4", "This request is garbage!");
$stream->close_gracefully();
return;
}
}
if (defined $length and $length == length($buffer)) {
serve_spartan($stream, $request_host, $path, $length, $buffer);
} else {
$log->debug("Waiting for more bytes...");
}
});
});
}
}
}
}
sub serve_spartan {
my ($stream, $host, $path, $length, $buffer) = @_;
eval {
local $SIG{'ALRM'} = sub {
$log->error("Timeout processing $host $path $length via Spartan");
};
alarm(10); # timeout
my $spaces = space_regex();
# note that path always starts with a slash!
$log->info("Looking at $host $path $length via Spartan");
my ($space, $id, $n);
no warnings 'redefine';
# we cannot import these subroutines and modify them, otherwise the
# App::Phoebe code remains unchanged
local *gemini_to_url = \&App::Phoebe::to_url;
local *App::Phoebe::to_url = \&spartan_to_url;
local *old_gemini_link = \&App::Phoebe::gemini_link;
local *App::Phoebe::gemini_link = \&spartan_link;
local *App::Phoebe::success = \&success;
local *App::Phoebe::result = \&result;
if (run_extensions($stream, $host, undef, $buffer, $path, $length)) {
# config file goes first (note that $path and $length come at the end)
} elsif (($space) = $path =~ m!^(?:/($spaces))?(?:/page)?/?$!) {
# "up" from page/Alex gives us page or page/ â show main menu
spartan_main_menu($stream, $host, space($stream, $host, $space));
} elsif ($path eq "/do/source") {
seek DATA, 0, 0;
local $/ = undef; # slurp
$stream->write(encode_utf8 <DATA>);
} elsif ($length == 0 and ($space, $id, $n) = $path =~ m!^(?:/($spaces))?/page/([^/]+)(?:/(\d+))?$!) {
$log->debug("Serving $id bytes via Spartan");
serve_page($stream, $host, space($stream, $host, $space), decode_utf8(uri_unescape($id)), $n);
} elsif ($length > 0 and ($space, $id, $n) = $path =~ m!^(?:/($spaces))?/page/([^/]+)$!) {
$log->debug("Saving $length bytes via Spartan");
save_page($stream, $host, space($stream, $host, $space), decode_utf8(uri_unescape($id)),
"text/plain", $buffer, $length);
} elsif (($space, $id) = $path =~ m!^(?:/($spaces))?/raw/([^/]+)$!) {
serve_raw($stream, $host, space($stream, $host, $space), decode_utf8(uri_unescape($id)));
} elsif (($space, $id) = $path =~ m!^(?:/($spaces))?/html/([^/]+)$!) {
serve_html($stream, $host, space($stream, $host, $space), decode_utf8(uri_unescape($id)));
} elsif (($space, $id) = $path =~ m!^(?:/($spaces))?/history/([^/]+)$!) {
serve_history($stream, $host, space($stream, $host, $space), decode_utf8(uri_unescape($id)), 10);
} elsif (($space, $id, $n) = $path =~ m!^(?:/($spaces))?/diff/([^/]+)(?:/(\d+))?$!) {
serve_diff($stream, $host, space($stream, $host, $space), decode_utf8(uri_unescape($id)), $n);
} elsif (($space) = $path =~ m!^(?:/($spaces))?/do/index$!) {
serve_index($stream, $host, space($stream, $host, $space));
} else {
$log->info("No handler for $host $path $length via spartan");
result($stream, "5", "I do not know what to do with $host $path $length");
}
$log->debug("Done");
};
$log->error("Error: $@") if $@;
alarm(0);
$stream->close_gracefully();
}
sub success {
my $stream = shift;
my $type = shift || 'text/gemini; charset=UTF-8';
$stream->write("2 $type\r\n");
}
sub result {
my $stream = shift;
( run in 1.359 second using v1.01-cache-2.11-cpan-39bf76dae61 )