From c2dafcb4e5e8c9f654c0ad5719607366cf84b75a Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 14:36:23 +0000 Subject: CGI: add cgi_goto(CGI, [page]) This redirects to the given page (or if none is given, the page parameter given to the CGI), or displays an error with a create link if the page doesn't exist. --- IkiWiki/CGI.pm | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index 3fadc462e..a6b485edb 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -291,6 +291,47 @@ sub cgi_savesession ($) { umask($oldmask); } +# 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 = decode_utf8($q->param("page")); + + if (!defined $page) { + error("missing page parameter"); + } + } + + loadindex(); + + # If the page is internal (like a comment), see if it has a + # permalink. Comments do. + if (isinternal($page) && + defined $pagestate{$page}{meta}{permalink}) { + redirect($q, $pagestate{$page}{meta}{permalink}); + } + + my $link = bestlink("", $page); + + if (! length $link) { + print "Content-type: text/html\n\n"; + print misctemplate(gettext("missing page"), + "

". + sprintf(gettext("The page %s does not exist."), + htmllink("", "", $page)). + "

"); + } + else { + redirect($q, urlto($link, undef, 1)); + } + + exit; +} + sub cgi (;$$) { my $q=shift; my $session=shift; -- cgit v1.2.3 From 18f4aeffb1841f8b455a5e31811695102262a06a Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 14:48:44 +0000 Subject: CGI: if the "do" parameter is goto, recentchanges_link or commenter, redirect to a page This can replace equivalent functionality in comments and recentchanges. --- IkiWiki/CGI.pm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index a6b485edb..949390e68 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -358,7 +358,12 @@ sub cgi (;$$) { error("\"do\" parameter missing"); } } - + + if ($do eq 'goto' || $do eq 'recentchanges_link' || + $do eq 'commenter') { + cgi_goto($q); + } + # Need to lock the wiki before getting a session. lockwiki(); loadindex(); -- cgit v1.2.3 From 4e92548ebc39c083e7ed8b870f4c13ba229127cd Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 14:49:12 +0000 Subject: comments: delete cgi hook in favour of the global one --- IkiWiki/Plugin/comments.pm | 32 +------------------------------- 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/IkiWiki/Plugin/comments.pm b/IkiWiki/Plugin/comments.pm index cbb3374c2..995d1f4eb 100644 --- a/IkiWiki/Plugin/comments.pm +++ b/IkiWiki/Plugin/comments.pm @@ -25,7 +25,6 @@ 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); IkiWiki::loadplugin("inline"); } @@ -167,7 +166,7 @@ sub preprocess { } else { $commentauthorurl = IkiWiki::cgiurl( - do => 'commenter', + do => 'goto', page => (length $config{userdir} ? "$config{userdir}/$commentuser" : "$commentuser")); @@ -235,35 +234,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")), - "

". - sprintf(gettext("The page %s does not exist."), - htmllink("", "", $page)). - "

"); - } - else { - IkiWiki::redirect($cgi, urlto($link, undef, 1)); - } - - exit; - } -} - sub sessioncgi ($$) { my $cgi=shift; my $session=shift; -- cgit v1.2.3 From a981d6857f1eab350460116c1b5d868ed0215d29 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 14:49:25 +0000 Subject: recentchanges: delete CGI hook in favour of the global one --- IkiWiki/Plugin/recentchanges.pm | 45 +---------------------------------------- 1 file changed, 1 insertion(+), 44 deletions(-) diff --git a/IkiWiki/Plugin/recentchanges.pm b/IkiWiki/Plugin/recentchanges.pm index ef108b3f0..56e80e7b8 100644 --- a/IkiWiki/Plugin/recentchanges.pm +++ b/IkiWiki/Plugin/recentchanges.pm @@ -13,7 +13,6 @@ 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); } sub getsetup () { @@ -79,48 +78,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")), - "

". - sprintf(gettext("The page %s does not exist."), - htmllink("", "", $page)). - "

"); - } - else { - IkiWiki::redirect($cgi, urlto($link, undef, 1)); - } - - exit; - } -} - sub store ($$$) { my $change=shift; @@ -138,7 +95,7 @@ sub store ($$$) { if (length $config{cgiurl}) { $_->{link} = " "recentchanges_link", + do => "goto", page => $_->{page} ). "\" rel=\"nofollow\">". -- cgit v1.2.3 From 5ce3a0130030f3b07e163727f16d212b2fda6259 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 15:05:17 +0000 Subject: CGI: document why commenter and recentchanges_link are supported --- IkiWiki/CGI.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index 949390e68..f23d44fd6 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -359,6 +359,8 @@ sub cgi (;$$) { } } + # goto is the preferred name for this; recentchanges_link and + # commenter are for compatibility with any saved URLs if ($do eq 'goto' || $do eq 'recentchanges_link' || $do eq 'commenter') { cgi_goto($q); -- cgit v1.2.3 From 78d1b2340eeacdad7bcccb9c7fa450ac47728341 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 16:51:13 +0000 Subject: CGI: if the page is missing, give the "missing page" a 404 status --- IkiWiki/CGI.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index f23d44fd6..fe8457262 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -318,7 +318,7 @@ sub cgi_goto ($;$) { my $link = bestlink("", $page); if (! length $link) { - print "Content-type: text/html\n\n"; + print $q->header(-status => "404 Not Found"); print misctemplate(gettext("missing page"), "

". sprintf(gettext("The page %s does not exist."), -- cgit v1.2.3 From 3e290ce7eef9de6bad7d30b5855de14090b5edd2 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 18:06:44 +0000 Subject: IkiWiki::Wrapper: allow REDIRECT_STATUS and REDIRECT_URL through from environment This is useful to act as an Apache 404 ErrorDocument. --- IkiWiki/Wrapper.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IkiWiki/Wrapper.pm b/IkiWiki/Wrapper.pm index dd9971a34..8a6340f58 100644 --- a/IkiWiki/Wrapper.pm +++ b/IkiWiki/Wrapper.pm @@ -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"; -- cgit v1.2.3 From 8322b8c9c82941c4052bcc8a0d1824a92d6426a0 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 18:07:42 +0000 Subject: CGI: add cgi_page_from_404(), which remaps a path like $REDIRECT_URL to an IkiWiki page name Also add a regression test --- IkiWiki/CGI.pm | 40 ++++++++++++++++++++++++++++++++++++++++ t/cgi_page_from_404.t | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100755 t/cgi_page_from_404.t diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index fe8457262..82cad40c8 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -332,6 +332,46 @@ sub cgi_goto ($;$) { exit; } +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 $q=shift; my $session=shift; diff --git a/t/cgi_page_from_404.t b/t/cgi_page_from_404.t new file mode 100755 index 000000000..adbbdf874 --- /dev/null +++ b/t/cgi_page_from_404.t @@ -0,0 +1,43 @@ +#!/usr/bin/perl +use warnings; +use strict; +use Test::More tests => 18; + +BEGIN { use_ok("IkiWiki"); } +BEGIN { use_ok("IkiWiki::CGI"); } + +sub cgi_page_from_404 { return IkiWiki::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'); -- cgit v1.2.3 From 170b86a2efb1908355f5812eaa3f3de4a2dcaa49 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 18:09:24 +0000 Subject: CGI: set up goto hook so that /ikiwiki.cgi?do=goto can be an Apache ErrorDocument --- IkiWiki/CGI.pm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index 82cad40c8..7e968d966 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -403,7 +403,14 @@ sub cgi (;$$) { # commenter are for compatibility with any saved URLs if ($do eq 'goto' || $do eq 'recentchanges_link' || $do eq 'commenter') { - cgi_goto($q); + my $page = undef; + + if ($ENV{REDIRECT_STATUS} eq '404') { + $page = cgi_page_from_404($ENV{REDIRECT_URL}, + $config{url}, $config{usedirs}); + } + + cgi_goto($q, $page); } # Need to lock the wiki before getting a session. -- cgit v1.2.3 From dedbe110f27e77051c8e49e0a53b8cdd148dd752 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 18:26:37 +0000 Subject: CGI: pad error responses with 512 bytes of spaces so IE will display them IE displays its own error responses unless the server's was >= 512 bytes. http://support.microsoft.com/default.aspx?scid=kb;en-us;Q294807 --- IkiWiki/CGI.pm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index 7e968d966..8734cdd49 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -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; } @@ -323,7 +326,10 @@ sub cgi_goto ($;$) { "

". sprintf(gettext("The page %s does not exist."), htmllink("", "", $page)). - "

"); + "

". + # Internet Explorer won't show custom 404 responses + # unless they're >= 512 bytes + (" " x 512)); } else { redirect($q, urlto($link, undef, 1)); -- cgit v1.2.3 From fb0e3a7dbc7f71f8684c99c20d319671e60354b1 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 18:27:54 +0000 Subject: Add tip explaining how to use ikiwiki as a 404 handler --- doc/tips/apache_404_handler.mdwn | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 doc/tips/apache_404_handler.mdwn diff --git a/doc/tips/apache_404_handler.mdwn b/doc/tips/apache_404_handler.mdwn new file mode 100644 index 000000000..0fda759e7 --- /dev/null +++ b/doc/tips/apache_404_handler.mdwn @@ -0,0 +1,10 @@ +[[!meta title="Apache 404 handler"]] + +Sufficiently recent versions of IkiWiki can be used 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?do=goto -- cgit v1.2.3 From 46b880f8390ac82d746add01de38a05155743374 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 22:32:10 +0000 Subject: Split apache404 into an independent plugin Also make it ignore the 'do' parameter at Joey's suggestion, to have one less thing to remember when configuring. --- IkiWiki/CGI.pm | 49 +------------------------- IkiWiki/Plugin/apache404.pm | 76 ++++++++++++++++++++++++++++++++++++++++ doc/plugins/apache404.mdwn | 11 ++++++ doc/tips/apache_404_handler.mdwn | 10 ------ t/apache404.t | 45 ++++++++++++++++++++++++ t/cgi_page_from_404.t | 43 ----------------------- 6 files changed, 133 insertions(+), 101 deletions(-) create mode 100644 IkiWiki/Plugin/apache404.pm create mode 100644 doc/plugins/apache404.mdwn delete mode 100644 doc/tips/apache_404_handler.mdwn create mode 100755 t/apache404.t delete mode 100755 t/cgi_page_from_404.t diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index 8734cdd49..e75ebcd27 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -338,46 +338,6 @@ sub cgi_goto ($;$) { exit; } -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 $q=shift; my $session=shift; @@ -409,14 +369,7 @@ sub cgi (;$$) { # commenter are for compatibility with any saved URLs if ($do eq 'goto' || $do eq 'recentchanges_link' || $do eq 'commenter') { - my $page = undef; - - if ($ENV{REDIRECT_STATUS} eq '404') { - $page = cgi_page_from_404($ENV{REDIRECT_URL}, - $config{url}, $config{usedirs}); - } - - cgi_goto($q, $page); + cgi_goto($q); } # Need to lock the wiki before getting a session. diff --git a/IkiWiki/Plugin/apache404.pm b/IkiWiki/Plugin/apache404.pm new file mode 100644 index 000000000..3ac6b3af5 --- /dev/null +++ b/IkiWiki/Plugin/apache404.pm @@ -0,0 +1,76 @@ +#!/usr/bin/perl +# Copyright © 2009 Simon McVittie +# 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); +} + +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::cgi_goto($cgi, $page); + } +} + +1; diff --git a/doc/plugins/apache404.mdwn b/doc/plugins/apache404.mdwn new file mode 100644 index 000000000..bab8fb59d --- /dev/null +++ b/doc/plugins/apache404.mdwn @@ -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 diff --git a/doc/tips/apache_404_handler.mdwn b/doc/tips/apache_404_handler.mdwn deleted file mode 100644 index 0fda759e7..000000000 --- a/doc/tips/apache_404_handler.mdwn +++ /dev/null @@ -1,10 +0,0 @@ -[[!meta title="Apache 404 handler"]] - -Sufficiently recent versions of IkiWiki can be used 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?do=goto diff --git a/t/apache404.t b/t/apache404.t new file mode 100755 index 000000000..00fc35250 --- /dev/null +++ b/t/apache404.t @@ -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'); diff --git a/t/cgi_page_from_404.t b/t/cgi_page_from_404.t deleted file mode 100755 index adbbdf874..000000000 --- a/t/cgi_page_from_404.t +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/perl -use warnings; -use strict; -use Test::More tests => 18; - -BEGIN { use_ok("IkiWiki"); } -BEGIN { use_ok("IkiWiki::CGI"); } - -sub cgi_page_from_404 { return IkiWiki::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'); -- cgit v1.2.3 From c886bea32084a920f3ba26b3f96327681f5db917 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Sat, 31 Jan 2009 23:01:10 +0000 Subject: Split cgi_goto into a goto plugin --- IkiWiki/CGI.pm | 51 --------------------------- IkiWiki/Plugin/apache404.pm | 3 +- IkiWiki/Plugin/comments.pm | 2 ++ IkiWiki/Plugin/goto.pm | 76 +++++++++++++++++++++++++++++++++++++++++ IkiWiki/Plugin/recentchanges.pm | 2 ++ doc/plugins/goto.mdwn | 10 ++++++ 6 files changed, 92 insertions(+), 52 deletions(-) create mode 100644 IkiWiki/Plugin/goto.pm create mode 100644 doc/plugins/goto.mdwn diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index e75ebcd27..c91914564 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -294,50 +294,6 @@ sub cgi_savesession ($) { umask($oldmask); } -# 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 = decode_utf8($q->param("page")); - - if (!defined $page) { - error("missing page parameter"); - } - } - - loadindex(); - - # If the page is internal (like a comment), see if it has a - # permalink. Comments do. - if (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 misctemplate(gettext("missing page"), - "

". - sprintf(gettext("The page %s does not exist."), - htmllink("", "", $page)). - "

". - # Internet Explorer won't show custom 404 responses - # unless they're >= 512 bytes - (" " x 512)); - } - else { - redirect($q, urlto($link, undef, 1)); - } - - exit; -} - sub cgi (;$$) { my $q=shift; my $session=shift; @@ -365,13 +321,6 @@ sub cgi (;$$) { } } - # goto is the preferred name for this; recentchanges_link and - # commenter are for compatibility with any saved URLs - if ($do eq 'goto' || $do eq 'recentchanges_link' || - $do eq 'commenter') { - cgi_goto($q); - } - # Need to lock the wiki before getting a session. lockwiki(); loadindex(); diff --git a/IkiWiki/Plugin/apache404.pm b/IkiWiki/Plugin/apache404.pm index 3ac6b3af5..e7ce70435 100644 --- a/IkiWiki/Plugin/apache404.pm +++ b/IkiWiki/Plugin/apache404.pm @@ -10,6 +10,7 @@ use IkiWiki 3.00; sub import { hook(type => "cgi", id => 'apache404', call => \&cgi); + IkiWiki::loadplugin("goto"); } sub getsetup () { @@ -69,7 +70,7 @@ sub cgi ($) { if ($ENV{REDIRECT_STATUS} eq '404') { my $page = cgi_page_from_404($ENV{REDIRECT_URL}, $config{url}, $config{usedirs}); - IkiWiki::cgi_goto($cgi, $page); + IkiWiki::Plugin::goto::cgi_goto($cgi, $page); } } diff --git a/IkiWiki/Plugin/comments.pm b/IkiWiki/Plugin/comments.pm index 995d1f4eb..3cdffe856 100644 --- a/IkiWiki/Plugin/comments.pm +++ b/IkiWiki/Plugin/comments.pm @@ -26,6 +26,8 @@ sub import { hook(type => "htmlize", id => "_comment", call => \&htmlize); hook(type => "pagetemplate", id => "comments", call => \&pagetemplate); 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"); } diff --git a/IkiWiki/Plugin/goto.pm b/IkiWiki/Plugin/goto.pm new file mode 100644 index 000000000..9e7a2621f --- /dev/null +++ b/IkiWiki/Plugin/goto.pm @@ -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"), + "

". + sprintf(gettext("The page %s does not exist."), + htmllink("", "", $page)). + "

". + # 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; diff --git a/IkiWiki/Plugin/recentchanges.pm b/IkiWiki/Plugin/recentchanges.pm index 56e80e7b8..329dd6f32 100644 --- a/IkiWiki/Plugin/recentchanges.pm +++ b/IkiWiki/Plugin/recentchanges.pm @@ -13,6 +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); + # Load goto to fix up links from recentchanges + IkiWiki::loadplugin("goto"); } sub getsetup () { diff --git a/doc/plugins/goto.mdwn b/doc/plugins/goto.mdwn new file mode 100644 index 000000000..21dda16b2 --- /dev/null +++ b/doc/plugins/goto.mdwn @@ -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. -- cgit v1.2.3