App-Phoebe

 view release on metacpan or  search on metacpan

lib/App/Phoebe.pm  view on Meta::CPAN

F<conf.d> directory. Once you're happy with the changes you've made, restart the
server, or send a SIGHUP if you know the PID.

Here are the ways you can hook into Phoebe code:

C<@extensions> is a list of code references allowing you to handle additional
URLs; return 1 if you handle a URL; each code reference gets called with $stream
(L<Mojo::IOLoop::Stream>), the first line of the request (a Gemini URL, a Gopher
selector, a finger user, a HTTP request line), a hash reference (with the
headers of HTTP requests or the parameters of Titan requests), a buffer of bytes
(e.g. for Titan or HTTP PUT or POST requests), and (sometimes) size.

C<@main_menu> adds more lines to the main menu, possibly links that aren't
simply links to existing pages.

C<@footer> is a list of code references allowing you to add things like licenses
or contact information to every page; each code reference gets called with
$stream (L<Mojo::IOLoop::Stream>), $host, $space, $id, $revision, and $format
('gemini' or 'html') used to serve the page; return a gemtext string to append
at the end; the alternative is to overwrite the C<footer> or C<html_footer> subs
– the default implementation for Gemini adds History, Raw text and HTML link,

lib/App/Phoebe/WebDAV.pm  view on Meta::CPAN

L<davs://localhost:1965/> instead. This forces Gnome Files to ask you for a
username and password, and once you provide it, Gnome Text Editor can save
files.

=head1 SEE ALSO

L<RFC 4918|https://datatracker.ietf.org/doc/html/rfc4918> defines WebDAV
including the PROPFIND method.

L<RFC 2616|https://datatracker.ietf.org/doc/html/rfc2616> defines HTTP/1.1
including the OPTION and PUT methods.

L<RFC 2617|https://datatracker.ietf.org/doc/html/rfc2617> defines Basic
Authentication.

=cut

package App::Phoebe::WebDAV;
use App::Phoebe::Web qw(handle_http_header);
use App::Phoebe qw(@request_handlers @extensions run_extensions $server
		   $log host_regex space_regex space port wiki_dir pages files

lib/App/Phoebe/WebDAV.pm  view on Meta::CPAN

use Encode qw(encode_utf8 decode_utf8);
use Mojo::Util qw(b64_decode);
use File::stat;
use Modern::Perl;
use File::MimeInfo::Magic;
use URI::Escape;
use XML::LibXML;
use IO::Scalar;
use utf8;

unshift(@request_handlers, '^(OPTIONS|PROPFIND|PUT|DELETE|COPY|MOVE) .* HTTP/1\.1$' => \&handle_http_header);

# note that the requests handled here must be protected in
# App::Phoebe::RegisteredEditorsOnly!
push(@extensions, \&process_webdav);

sub process_webdav {
  my ($stream, $request, $headers, $buffer) = @_;
  my $hosts = host_regex();
  my $port = port($stream);
  my $spaces = space_regex();

lib/App/Phoebe/WebDAV.pm  view on Meta::CPAN

  if (($space, $path, $id)
      = $request =~ m!^OPTIONS (?:/($spaces))?(/(?:login|(?:file|page|raw)(?:/([^/]*))?)?)? HTTP/1\.1$!
      and ($host) = $headers->{host} =~ m!^($hosts)(?::$port)$!) {
    return if $path eq "/login" and not authorize($stream, $host, space($stream, $host, $space), $headers);
    options($stream, map { decode_utf8(uri_unescape($_)) } $path, $id);
  } elsif (($space, $path, $id)
	   = $request =~ m!^PROPFIND (?:/($spaces))?(/(?:login/?|(?:file|page|raw)(?:/([^/]*))?)?)? HTTP/1\.1$!
	   and ($host) = $headers->{host} =~ m!^($hosts)(?::$port)$!) {
    propfind($stream, $host, space($stream, $host, $space), (map { decode_utf8(uri_unescape($_)) } $path, $id), $headers, $buffer);
  } elsif (($space, $path, $id)
	   = $request =~ m!^PUT (?:/($spaces))?(/(?:file|raw)/([^/]*)) HTTP/1\.1$!
	   and ($host) = $headers->{host} =~ m!^($hosts)(?::$port)$!) {
    put($stream, $host, space($stream, $host, $space), (map { decode_utf8(uri_unescape($_)) } $path, $id), $headers, $buffer);
  } elsif (($space, $path, $id)
	   = $request =~ m!^DELETE (?:/($spaces))?(/(?:file|raw)/([^/]*)) HTTP/1\.1$!
	   and ($host) = $headers->{host} =~ m!^($hosts)(?::$port)$!) {
    remove($stream, $host, space($stream, $host, $space), (map { decode_utf8(uri_unescape($_)) } $path, $id), $headers);
  } elsif (($space, $path, $id)
	   = $request =~ m!^COPY (?:/($spaces))?(/(?:file|raw)/([^/]*)) HTTP/1\.1$!
	   and ($host) = $headers->{host} =~ m!^($hosts)(?::$port)$!) {
    copy($stream, $host, space($stream, $host, $space), (map { decode_utf8(uri_unescape($_)) } $path, $id), $headers);

t/WebDAV.t  view on Meta::CPAN


# Open a fresh wiki
ok($dav->open(-url => "https://$host:$port/"), "Open URL: " . $dav->message);

# Check options
for my $d (qw(/ /page /page/ /raw /raw/ /file /file/)) {
  my $options = $dav->options(-url => "https://$host:$port$d");
  for my $op (qw(OPTIONS PROPFIND)) {
    like($options, qr/$op/, "$op supported for $d");
  }
  for my $op (qw(GET PUT DELETE)) {
    unlike($options, qr/$op/, "$op not supported for $d");
  }
}
for my $d (qw(/page/x)) {
  my $options = $dav->options(-url => "https://$host:$port$d");
  for my $op (qw(OPTIONS PROPFIND GET)) {
    like($options, qr/$op/, "$op supported for $d");
  }
  for my $op (qw(PUT DELETE)) {
    unlike($options, qr/$op/, "$op not supported for $d");
  }
}
for my $d (qw(/raw/x /file/x)) {
  my $options = $dav->options(-url => "https://$host:$port$d");
  for my $op (qw(OPTIONS PROPFIND PUT GET DELETE)) {
    like($options, qr/$op/, "$op supported for $d");
  }
}

# Read directories
my $resource = $dav->propfind(-url=>"/", -depth=>1);
ok($resource && $resource->is_collection, "Found /");
my @list = $resource->get_resourcelist->get_resources;
my $item = first { $_->get_uri->path eq "/page/" } @list;
ok($item && $item->is_collection, "Found /page");



( run in 0.465 second using v1.01-cache-2.11-cpan-4e96b696675 )