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 )