Merge commit 'smcv/goto'

master
Joey Hess 2009-01-31 18:52:38 -05:00
commit 3be69a0fe4
9 changed files with 231 additions and 77 deletions

View File

@ -239,6 +239,9 @@ sub check_banned ($$) {
print $q->header(-status => "403 Forbidden");
$session->delete();
print gettext("You are banned.");
# Internet Explorer won't show custom 404 responses
# unless they're >= 512 bytes
print " " x 512;
cgi_savesession($session);
exit;
}
@ -317,7 +320,7 @@ sub cgi (;$$) {
error("\"do\" parameter missing");
}
}
# Need to lock the wiki before getting a session.
lockwiki();
loadindex();

View File

@ -0,0 +1,77 @@
#!/usr/bin/perl
# Copyright © 2009 Simon McVittie <http://smcv.pseudorandom.co.uk/>
# Licensed under the GNU GPL, version 2, or any later version published by the
# Free Software Foundation
package IkiWiki::Plugin::apache404;
use warnings;
use strict;
use IkiWiki 3.00;
sub import {
hook(type => "cgi", id => 'apache404', call => \&cgi);
IkiWiki::loadplugin("goto");
}
sub getsetup () {
return
plugin => {
# not really a matter of safety, but enabling/disabling
# through a web interface is useless - it needs web
# server admin action too
safe => 0,
rebuild => 0,
}
}
sub cgi_page_from_404 ($$$) {
my $path = shift;
my $baseurl = shift;
my $usedirs = shift;
# fail if missing from environment or whatever
return undef unless defined $path;
return undef unless defined $baseurl;
# with usedirs on, path is like /~fred/foo/bar/ or /~fred/foo/bar or
# /~fred/foo/bar/index.html
# with usedirs off, path is like /~fred/foo/bar.html
# baseurl is like 'http://people.example.com/~fred'
# convert baseurl to ~fred
unless ($baseurl =~ s{^https?://[^/]+/?}{}) {
return undef;
}
# convert path to /~fred/foo/bar
if ($usedirs) {
$path =~ s/\/*(?:index\.$config{htmlext})?$//;
}
else {
$path =~ s/\.$config{htmlext}$//;
}
# remove /~fred/
unless ($path =~ s{^/*\Q$baseurl\E/*}{}) {
return undef;
}
# special case for the index
unless ($path) {
return 'index';
}
return $path;
}
sub cgi ($) {
my $cgi=shift;
if ($ENV{REDIRECT_STATUS} eq '404') {
my $page = cgi_page_from_404($ENV{REDIRECT_URL},
$config{url}, $config{usedirs});
IkiWiki::Plugin::goto::cgi_goto($cgi, $page);
}
}
1;

View File

@ -25,8 +25,9 @@ sub import {
hook(type => "sessioncgi", id => 'comment', call => \&sessioncgi);
hook(type => "htmlize", id => "_comment", call => \&htmlize);
hook(type => "pagetemplate", id => "comments", call => \&pagetemplate);
hook(type => "cgi", id => "comments", call => \&linkcgi);
hook(type => "formbuilder_setup", id => "comments", call => \&formbuilder_setup);
# Load goto to fix up user page links for logged-in commenters
IkiWiki::loadplugin("goto");
IkiWiki::loadplugin("inline");
}
@ -167,7 +168,7 @@ sub preprocess {
}
else {
$commentauthorurl = IkiWiki::cgiurl(
do => 'commenter',
do => 'goto',
page => (length $config{userdir}
? "$config{userdir}/$commentuser"
: "$commentuser"));
@ -235,35 +236,6 @@ sub preprocess {
return $content;
}
# This is exactly the same as recentchanges_link :-(
sub linkcgi ($) {
my $cgi=shift;
if (defined $cgi->param('do') && $cgi->param('do') eq "commenter") {
my $page=decode_utf8($cgi->param("page"));
if (! defined $page) {
error("missing page parameter");
}
IkiWiki::loadindex();
my $link=bestlink("", $page);
if (! length $link) {
print "Content-type: text/html\n\n";
print IkiWiki::misctemplate(gettext(gettext("missing page")),
"<p>".
sprintf(gettext("The page %s does not exist."),
htmllink("", "", $page)).
"</p>");
}
else {
IkiWiki::redirect($cgi, urlto($link, undef, 1));
}
exit;
}
}
sub sessioncgi ($$) {
my $cgi=shift;
my $session=shift;

View File

@ -0,0 +1,76 @@
#!/usr/bin/perl
package IkiWiki::Plugin::goto;
use warnings;
use strict;
use IkiWiki 3.00;
sub import {
hook(type => "cgi", id => 'goto', call => \&cgi);
}
sub getsetup () {
return
plugin => {
safe => 1,
rebuild => 0,
}
}
# cgi_goto(CGI, [page])
# Redirect to a specified page, or display "not found". If not specified,
# the page param from the CGI object is used.
sub cgi_goto ($;$) {
my $q = shift;
my $page = shift;
if (!defined $page) {
$page = IkiWiki::decode_utf8($q->param("page"));
if (!defined $page) {
error("missing page parameter");
}
}
IkiWiki::loadindex();
# If the page is internal (like a comment), see if it has a
# permalink. Comments do.
if (IkiWiki::isinternal($page) &&
defined $pagestate{$page}{meta}{permalink}) {
redirect($q, $pagestate{$page}{meta}{permalink});
}
my $link = bestlink("", $page);
if (! length $link) {
print $q->header(-status => "404 Not Found");
print IkiWiki::misctemplate(gettext("missing page"),
"<p>".
sprintf(gettext("The page %s does not exist."),
htmllink("", "", $page)).
"</p>".
# Internet Explorer won't show custom 404 responses
# unless they're >= 512 bytes
(" " x 512));
}
else {
IkiWiki::redirect($q, urlto($link, undef, 1));
}
exit;
}
sub cgi ($) {
my $cgi=shift;
my $do = $cgi->param('do');
if (defined $do && ($do eq 'goto' || $do eq 'commenter' ||
$do eq 'recentchanged_link')) {
# goto is the preferred name for this; recentchanges_link and
# commenter are for compatibility with any saved URLs
cgi_goto($cgi);
}
}
1;

View File

@ -13,7 +13,8 @@ sub import {
hook(type => "refresh", id => "recentchanges", call => \&refresh);
hook(type => "pagetemplate", id => "recentchanges", call => \&pagetemplate);
hook(type => "htmlize", id => "_change", call => \&htmlize);
hook(type => "cgi", id => "recentchanges", call => \&cgi);
# Load goto to fix up links from recentchanges
IkiWiki::loadplugin("goto");
}
sub getsetup () {
@ -79,48 +80,6 @@ sub htmlize (@) {
return $params{content};
}
sub cgi ($) {
my $cgi=shift;
if (defined $cgi->param('do') && $cgi->param('do') eq "recentchanges_link") {
# This is a link from a change page to some
# other page. Since the change pages are only generated
# once, statically, links on them won't be updated if the
# page they link to is deleted, or newly created, or
# changes for whatever reason. So this CGI handles that
# dynamic linking stuff.
my $page=decode_utf8($cgi->param("page"));
if (!defined $page) {
error("missing page parameter");
}
IkiWiki::loadindex();
# If the page is internal (like a comment), see if it has a
# permalink. Comments do.
if (IkiWiki::isinternal($page) &&
defined $pagestate{$page}{meta}{permalink}) {
IkiWiki::redirect($cgi,
$pagestate{$page}{meta}{permalink});
exit;
}
my $link=bestlink("", $page);
if (! length $link) {
print "Content-type: text/html\n\n";
print IkiWiki::misctemplate(gettext(gettext("missing page")),
"<p>".
sprintf(gettext("The page %s does not exist."),
htmllink("", "", $page)).
"</p>");
}
else {
IkiWiki::redirect($cgi, urlto($link, undef, 1));
}
exit;
}
}
sub store ($$$) {
my $change=shift;
@ -138,7 +97,7 @@ sub store ($$$) {
if (length $config{cgiurl}) {
$_->{link} = "<a href=\"".
IkiWiki::cgiurl(
do => "recentchanges_link",
do => "goto",
page => $_->{page}
).
"\" rel=\"nofollow\">".

View File

@ -28,7 +28,8 @@ sub gen_wrapper () {
my @envsave;
push @envsave, qw{REMOTE_ADDR QUERY_STRING REQUEST_METHOD REQUEST_URI
CONTENT_TYPE CONTENT_LENGTH GATEWAY_INTERFACE
HTTP_COOKIE REMOTE_USER HTTPS} if $config{cgi};
HTTP_COOKIE REMOTE_USER HTTPS REDIRECT_STATUS
REDIRECT_URL} if $config{cgi};
my $envsave="";
foreach my $var (@envsave) {
$envsave.=<<"EOF";

View File

@ -0,0 +1,11 @@
[[!template id=plugin name=apache404 author="[[Simon_McVittie|smcv]]"]]
[[!tag type/useful]]
This plugin lets you use the IkiWiki CGI script as an Apache 404 handler,
to give the behaviour of various other wiki engines where visiting a
nonexistent page provides you with a link to create it.
To achieve this, put something like this in the wiki's Apache configuration
file:
ErrorDocument 404 /cgi-bin/ikiwiki.cgi

View File

@ -0,0 +1,10 @@
[[!template id=plugin name=goto author="[[Simon_McVittie|smcv]]"]]
[[!tag type/useful]]
This plugin adds a `do=goto` mode for the IkiWiki CGI script. It's mainly
for internal use by the [[apache404]], [[comments]] and [[recentchanges]]
plugins, which enable it automatically.
With this plugin enabled you can link to `ikiwiki.cgi?do=goto&page=some/where`
to make a link that will redirect to the page `/some/where` if it exists, or
offer a link to create it if it doesn't.

45
t/apache404.t 100755
View File

@ -0,0 +1,45 @@
#!/usr/bin/perl
use warnings;
use strict;
use Test::More tests => 17;
BEGIN { use_ok("IkiWiki::Plugin::apache404"); }
sub cgi_page_from_404 {
return IkiWiki::Plugin::apache404::cgi_page_from_404(shift, shift,
shift);
}
$IkiWiki::config{htmlext} = 'html';
is(cgi_page_from_404('/', 'http://example.com', 1), 'index');
is(cgi_page_from_404('/index.html', 'http://example.com', 0), 'index');
is(cgi_page_from_404('/', 'http://example.com/', 1), 'index');
is(cgi_page_from_404('/index.html', 'http://example.com/', 0), 'index');
is(cgi_page_from_404('/~user/foo/bar', 'http://example.com/~user', 1),
'foo/bar');
is(cgi_page_from_404('/~user/foo/bar/index.html', 'http://example.com/~user', 1),
'foo/bar');
is(cgi_page_from_404('/~user/foo/bar/', 'http://example.com/~user', 1),
'foo/bar');
is(cgi_page_from_404('/~user/foo/bar.html', 'http://example.com/~user', 0),
'foo/bar');
is(cgi_page_from_404('/~user/foo/bar', 'http://example.com/~user/', 1),
'foo/bar');
is(cgi_page_from_404('/~user/foo/bar/index.html', 'http://example.com/~user/', 1),
'foo/bar');
is(cgi_page_from_404('/~user/foo/bar/', 'http://example.com/~user/', 1),
'foo/bar');
is(cgi_page_from_404('/~user/foo/bar.html', 'http://example.com/~user/', 0),
'foo/bar');
is(cgi_page_from_404('/~user/foo', 'https://example.com/~user', 1),
'foo');
is(cgi_page_from_404('/~user/foo/index.html', 'https://example.com/~user', 1),
'foo');
is(cgi_page_from_404('/~user/foo/', 'https://example.com/~user', 1),
'foo');
is(cgi_page_from_404('/~user/foo.html', 'https://example.com/~user', 0),
'foo');