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);
# 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 )