]> sipb.mit.edu Git - ikiwiki.git/commitdiff
Merge remote branch 'smcv/ready/localurl'
authorJoey Hess <joey@kitenet.net>
Mon, 29 Nov 2010 18:43:57 +0000 (14:43 -0400)
committerJoey Hess <joey@kitenet.net>
Mon, 29 Nov 2010 18:43:57 +0000 (14:43 -0400)
21 files changed:
IkiWiki.pm
IkiWiki/CGI.pm
IkiWiki/Plugin/comments.pm
IkiWiki/Plugin/editpage.pm
IkiWiki/Plugin/goto.pm
IkiWiki/Plugin/img.pm
IkiWiki/Plugin/inline.pm
IkiWiki/Plugin/openid.pm
IkiWiki/Plugin/parentlinks.pm
IkiWiki/Plugin/pinger.pm
IkiWiki/Plugin/poll.pm
IkiWiki/Plugin/recentchanges.pm
IkiWiki/Plugin/relativedate.pm
IkiWiki/Plugin/remove.pm
IkiWiki/Plugin/rename.pm
IkiWiki/Plugin/search.pm
IkiWiki/Plugin/toggle.pm
IkiWiki/Plugin/websetup.pm
IkiWiki/Plugin/wmd.pm
doc/plugins/write.mdwn
t/urlto.t [new file with mode: 0755]

index c06751dd36bc0bf656e9b7abfc49d5c8a9455c47..a893edb3be4765f14f55b8b37509539bc4041a66 100644 (file)
@@ -501,6 +501,12 @@ sub defaultconfig () {
        return @ret;
 }
 
+# URL to top of wiki as a path starting with /, valid from any wiki page or
+# the CGI; if that's not possible, an absolute URL. Either way, it ends with /
+my $local_url;
+# URL to CGI script, similar to $local_url
+my $local_cgiurl;
+
 sub checkconfig () {
        # locale stuff; avoid LC_ALL since it overrides everything
        if (defined $ENV{LC_ALL}) {
@@ -537,7 +543,33 @@ sub checkconfig () {
        if ($config{cgi} && ! length $config{url}) {
                error(gettext("Must specify url to wiki with --url when using --cgi"));
        }
-       
+
+       if (length $config{url}) {
+               eval q{use URI};
+               my $baseurl = URI->new($config{url});
+
+               $local_url = $baseurl->path . "/";
+               $local_cgiurl = undef;
+
+               if (length $config{cgiurl}) {
+                       my $cgiurl = URI->new($config{cgiurl});
+
+                       $local_cgiurl = $cgiurl->path;
+
+                       if ($cgiurl->scheme ne $baseurl->scheme or
+                               $cgiurl->authority ne $baseurl->authority) {
+                               # too far apart, fall back to absolute URLs
+                               $local_url = "$config{url}/";
+                               $local_cgiurl = $config{cgiurl};
+                       }
+               }
+
+               $local_url =~ s{//$}{/};
+       }
+       else {
+               $local_cgiurl = $config{cgiurl};
+       }
+
        $config{wikistatedir}="$config{srcdir}/.ikiwiki"
                unless exists $config{wikistatedir} && defined $config{wikistatedir};
 
@@ -1010,11 +1042,17 @@ sub linkpage ($) {
 sub cgiurl (@) {
        my %params=@_;
 
-       my $cgiurl=$config{cgiurl};
+       my $cgiurl=$local_cgiurl;
+
        if (exists $params{cgiurl}) {
                $cgiurl=$params{cgiurl};
                delete $params{cgiurl};
        }
+
+       unless (%params) {
+               return $cgiurl;
+       }
+
        return $cgiurl."?".
                join("&amp;", map $_."=".uri_escape_utf8($params{$_}), keys %params);
 }
@@ -1022,7 +1060,7 @@ sub cgiurl (@) {
 sub baseurl (;$) {
        my $page=shift;
 
-       return "$config{url}/" if ! defined $page;
+       return $local_url if ! defined $page;
        
        $page=htmlpage($page);
        $page=~s/[^\/]+$//;
@@ -1113,6 +1151,12 @@ sub urlto ($$;$) {
                return $config{url}.beautify_urlpath("/".$to);
        }
 
+       if (! defined $from) {
+               my $u = $local_url;
+               $u =~ s{/$}{};
+               return $u.beautify_urlpath("/".$to);
+       }
+
        my $link = abs2rel($to, dirname(htmlpage($from)));
 
        return beautify_urlpath($link);
index f2a32a9581077553d5b542fde40f428c15a5e41a..e0bfda9ae06d9685a4e4eaed5f8557963560c652 100644 (file)
@@ -116,7 +116,7 @@ sub cgi_signin ($$;$) {
                required => 'NONE',
                javascript => 0,
                params => $q,
-               action => $config{cgiurl},
+               action => cgiurl(),
                header => 0,
                template => {type => 'div'},
                stylesheet => 1,
@@ -198,7 +198,7 @@ sub cgi_prefs ($$) {
                required => 'NONE',
                javascript => 0,
                params => $q,
-               action => $config{cgiurl},
+               action => cgiurl(),
                template => {type => 'div'},
                stylesheet => 1,
                fieldsets => [
@@ -231,11 +231,11 @@ sub cgi_prefs ($$) {
        
        if ($form->submitted eq 'Logout') {
                $session->delete();
-               redirect($q, $config{url});
+               redirect($q, baseurl(undef));
                return;
        }
        elsif ($form->submitted eq 'Cancel') {
-               redirect($q, $config{url});
+               redirect($q, baseurl(undef));
                return;
        }
        elsif ($form->submitted eq 'Save Preferences' && $form->validate) {
index a39dab36cdb81e6c06049d9c0bc312a6e58b1dd2..a3cb7c3d56c784f18251aaa34a14776d6f107962 100644 (file)
@@ -237,7 +237,7 @@ sub preprocess {
        }
 
        if ($params{page} =~ m/\/\Q$config{comments_pagename}\E\d+_/) {
-               $pagestate{$page}{meta}{permalink} = urlto(IkiWiki::dirname($params{page}), undef, 1).
+               $pagestate{$page}{meta}{permalink} = urlto(IkiWiki::dirname($params{page}), undef).
                        "#".page_to_id($params{page});
        }
 
@@ -301,7 +301,7 @@ sub editcomment ($$) {
                required => [qw{editcontent}],
                javascript => 0,
                params => $cgi,
-               action => $config{cgiurl},
+               action => IkiWiki::cgiurl(),
                header => 0,
                table => 0,
                template => { template('editcomment.tmpl') },
@@ -372,7 +372,7 @@ sub editcomment ($$) {
                error(gettext("bad page name"));
        }
 
-       my $baseurl = urlto($page, undef, 1);
+       my $baseurl = urlto($page, undef);
 
        $form->title(sprintf(gettext("commenting on %s"),
                        IkiWiki::pagetitle($page)));
@@ -386,7 +386,7 @@ sub editcomment ($$) {
        if ($form->submitted eq CANCEL) {
                # bounce back to the page they wanted to comment on, and exit.
                # CANCEL need not be considered in future
-               IkiWiki::redirect($cgi, urlto($page, undef, 1));
+               IkiWiki::redirect($cgi, urlto($page, undef));
                exit;
        }
 
@@ -552,7 +552,7 @@ sub editcomment ($$) {
                # Jump to the new comment on the page.
                # The trailing question mark tries to avoid broken
                # caches and get the most recent version of the page.
-               IkiWiki::redirect($cgi, urlto($page, undef, 1).
+               IkiWiki::redirect($cgi, urlto($page, undef).
                        "?updated#".page_to_id($location));
 
        }
@@ -656,6 +656,7 @@ sub commentmoderation ($$) {
        $template->param(
                sid => $session->id,
                comments => \@comments,
+               cgiurl => IkiWiki::cgiurl(),
        );
        IkiWiki::printheader($session);
        my $out=$template->output;
@@ -810,14 +811,14 @@ sub pagetemplate (@) {
        if ($shown) {
                if ($template->query(name => 'commentsurl')) {
                        $template->param(commentsurl =>
-                               urlto($page, undef, 1).'#comments');
+                               urlto($page, undef).'#comments');
                }
 
                if ($template->query(name => 'atomcommentsurl') && $config{usedirs}) {
                        # This will 404 until there are some comments, but I
                        # think that's probably OK...
                        $template->param(atomcommentsurl =>
-                               urlto($page, undef, 1).'comments.atom');
+                               urlto($page, undef).'comments.atom');
                }
 
                if ($template->query(name => 'commentslink')) {
index 1a04a72b5568f2980d8a7e00d0eaaa06a62e0e0d..b3ae1fded1d5792513ded7c8ce745bc4e6362fc2 100644 (file)
@@ -75,7 +75,7 @@ sub cgi_editpage ($$) {
                required => [qw{editcontent}],
                javascript => 0,
                params => $q,
-               action => $config{cgiurl},
+               action => IkiWiki::cgiurl(),
                header => 0,
                table => 0,
                template => { template("editpage.tmpl") },
@@ -98,7 +98,7 @@ sub cgi_editpage ($$) {
                error(gettext("bad page name"));
        }
 
-       my $baseurl = urlto($page, undef, 1);
+       my $baseurl = urlto($page, undef);
 
        my $from;
        if (defined $form->field('from')) {
@@ -156,13 +156,13 @@ sub cgi_editpage ($$) {
        my $previewing=0;
        if ($form->submitted eq "Cancel") {
                if ($form->field("do") eq "create" && defined $from) {
-                       redirect($q, urlto($from, undef, 1));
+                       redirect($q, urlto($from, undef));
                }
                elsif ($form->field("do") eq "create") {
-                       redirect($q, $config{url});
+                       redirect($q, baseurl(undef));
                }
                else {
-                       redirect($q, urlto($page, undef, 1));
+                       redirect($q, urlto($page, undef));
                }
                exit;
        }
@@ -262,7 +262,7 @@ sub cgi_editpage ($$) {
                                        @page_locs=$page;
                                }
                                else {
-                                       redirect($q, urlto($page, undef, 1));
+                                       redirect($q, urlto($page, undef));
                                        exit;
                                }
                        }
@@ -434,7 +434,7 @@ sub cgi_editpage ($$) {
                else {
                        # The trailing question mark tries to avoid broken
                        # caches and get the most recent version of the page.
-                       redirect($q, urlto($page, undef, 1)."?updated");
+                       redirect($q, urlto($page, undef)."?updated");
                }
        }
 
index 348a663efdd936d5004e0735ad41e4c393568c3e..7f31fa5ca87b4fd5f26a609ee7c909bb4d741701 100644 (file)
@@ -64,7 +64,7 @@ sub cgi_goto ($;$) {
                )
        }
        else {
-               IkiWiki::redirect($q, urlto($link, undef, 1));
+               IkiWiki::redirect($q, urlto($link, undef));
        }
 
        exit;
index bd527c8c82c79eb5a8ef1a2ae6aa694f0279121d..b554a3dfc94a6c6cdd380f8e3461e6b2ec648e6a 100644 (file)
@@ -152,8 +152,8 @@ sub preprocess (@) {
                $imgurl=urlto($imglink, $params{destpage});
        }
        else {
-               $fileurl="$config{url}/$file";
-               $imgurl="$config{url}/$imglink";
+               $fileurl=urlto($file, undef);
+               $imgurl=urlto($imglink, undef);
        }
 
        if (! exists $params{class}) {
index 1fe40a5eab4235f82c46cbd0499032c84103e091..76527156406159e381164835b4c1dc3015cb346f 100644 (file)
@@ -300,7 +300,7 @@ sub preprocess_inline (@) {
            IkiWiki->can("cgi_editpage")) {
                # Add a blog post form, with feed buttons.
                my $formtemplate=template_depends("blogpost.tmpl", $params{page}, blind_cache => 1);
-               $formtemplate->param(cgiurl => $config{cgiurl});
+               $formtemplate->param(cgiurl => IkiWiki::cgiurl());
                $formtemplate->param(rootpage => rootpage(%params));
                $formtemplate->param(rssurl => $rssurl) if $feeds && $rss;
                $formtemplate->param(atomurl => $atomurl) if $feeds && $atom;
index fae9fb77f8388a9e750b1d8e7dfdcee700f76a92..0220a3cf67e7e78adf83c52ca4dbe09a312fa3cd 100644 (file)
@@ -77,7 +77,7 @@ sub openid_selector {
 
        my $template=IkiWiki::template("openid-selector.tmpl");
        $template->param(
-               cgiurl => $config{cgiurl},
+               cgiurl => IkiWiki::cgiurl(),
                (defined $openid_error ? (openid_error => $openid_error) : ()),
                (defined $openid_url ? (openid_url => $openid_url) : ()),
                ($real_cgi_signin ? (nonopenidform => $real_cgi_signin->($q, $session, 1)) : ()),
@@ -148,7 +148,7 @@ sub validate ($$$;$) {
        }
 
        my $cgiurl=$config{openid_cgiurl};
-       $cgiurl=$config{cgiurl} if ! defined $cgiurl;
+       $cgiurl=IkiWiki::cgiurl() if ! defined $cgiurl;
 
        my $trust_root=$config{openid_realm};
        $trust_root=$cgiurl if ! defined $trust_root;
@@ -175,7 +175,7 @@ sub auth ($$) {
                        IkiWiki::redirect($q, $setup_url);
                }
                elsif ($csr->user_cancel) {
-                       IkiWiki::redirect($q, $config{url});
+                       IkiWiki::redirect($q, IkiWiki::baseurl(undef));
                }
                elsif (my $vident = $csr->verified_identity) {
                        $session->param(name => $vident->url);
@@ -249,7 +249,7 @@ sub getobj ($$) {
        }
        
        my $cgiurl=$config{openid_cgiurl};
-       $cgiurl=$config{cgiurl} if ! defined $cgiurl;
+       $cgiurl=IkiWiki::cgiurl() if ! defined $cgiurl;
 
        return Net::OpenID::Consumer->new(
                ua => $ua,
index bbd2c5752f58ac4aa94dc932ac4345a5226266a7..203ea13b649e288fe4935d2743469721c15eb1e1 100644 (file)
@@ -27,7 +27,7 @@ sub parentlinks ($) {
        if (! length $page) {
                # dynamic page
                return {
-                       url => $config{url},
+                       url => IkiWiki::baseurl(undef),
                        page => $config{wikiname},
                };
        }
index cc9f52d2b50e7e880882ff56b89d8bafba5c274d..932619496c3d3c7634cb1a550a920dae106140a2 100644 (file)
@@ -106,6 +106,8 @@ sub ping {
                        # only ping when a page was changed, so a ping loop
                        # will still be avoided.
                        next if $url=~/^\Q$config{cgiurl}\E/;
+                       my $local_cgiurl = IkiWiki::cgiurl();
+                       next if $url=~/^\Q$local_cgiurl\E/;
                        
                        $ua->get($url);
                }
index b333e2cdcff485edd81f4df426e1865c261a1199..27df104ab6b05da2208b7d2d7155f49946ab4845 100644 (file)
@@ -52,7 +52,7 @@ sub preprocess (@) {
        foreach my $choice (@choices) {
                if ($open && exists $config{cgiurl}) {
                        # use POST to avoid robots
-                       $ret.="<form method=\"POST\" action=\"$config{cgiurl}\">\n";
+                       $ret.="<form method=\"POST\" action=\"".IkiWiki::cgiurl()."\">\n";
                }
                my $percent=$total > 0 ? int($choices{$choice} / $total * 100) : 0;
                $ret.="<p>\n";
@@ -103,7 +103,7 @@ sub sessioncgi ($$) {
                my $oldchoice=$session->param($choice_param);
                if (defined $oldchoice && $oldchoice eq $choice) {
                        # Same vote; no-op.
-                       IkiWiki::redirect($cgi, urlto($page, undef, 1));
+                       IkiWiki::redirect($cgi, urlto($page, undef));
                        exit;
                }
 
@@ -153,7 +153,7 @@ sub sessioncgi ($$) {
                error($@) if $@;
                my $cookie = CGI::Cookie->new(-name=> $session->name, -value=> $session->id);
                print $cgi->redirect(-cookie => $cookie,
-                       -url => urlto($page, undef, 1));
+                       -url => urlto($page, undef));
                exit;
        }
 }
index 562f61d40f3cc4729f5da0f01e3d6b2c4a20660d..de12bb2c68d0f32ab82f696012f693a4217b8019 100644 (file)
@@ -84,7 +84,7 @@ sub sessioncgi ($$) {
                method => 'POST',
                javascript => 0,
                params => $q,
-               action => $config{cgiurl},
+               action => IkiWiki::cgiurl(),
                stylesheet => 1,
                template => { template('revert.tmpl') },
                fields => [qw{revertmessage do sid rev}],
@@ -127,7 +127,7 @@ sub sessioncgi ($$) {
                exit 0;
        }
 
-       IkiWiki::redirect($q, urlto($config{recentchangespage}, ''));
+       IkiWiki::redirect($q, urlto($config{recentchangespage}, undef));
        exit 0;
 }
 
@@ -178,7 +178,7 @@ sub store ($$$) {
                        else {
                                $_->{link} = pagetitle($_->{page});
                        }
-                       $_->{baseurl}="$config{url}/" if length $config{url};
+                       $_->{baseurl}=IkiWiki::baseurl(undef) if length $config{url};
 
                        $_;
                } @{$change->{pages}}
@@ -226,7 +226,7 @@ sub store ($$$) {
                wikiname => $config{wikiname},
        );
        
-       $template->param(permalink => "$config{url}/$config{recentchangespage}/#change-".titlepage($change->{rev}))
+       $template->param(permalink => urlto($config{recentchangespage}, undef)."#change-".titlepage($change->{rev}))
                if exists $config{url};
        
        IkiWiki::run_hooks(pagetemplate => sub {
index 7296889ab28f21c9c642e468d503dc502428ede7..4ae0be8615852db38222ebd892fd5c216bd5b4bf 100644 (file)
@@ -28,18 +28,17 @@ sub format (@) {
 
        if (! ($params{content}=~s!^(<body[^>]*>)!$1.include_javascript($params{page})!em)) {
                # no <body> tag, probably in preview mode
-               $params{content}=include_javascript($params{page}, 1).$params{content};
+               $params{content}=include_javascript(undef).$params{content};
        }
        return $params{content};
 }
 
-sub include_javascript ($;$) {
-       my $page=shift;
-       my $absolute=shift;
+sub include_javascript ($) {
+       my $from=shift;
        
-       return '<script src="'.urlto("ikiwiki/ikiwiki.js", $page, $absolute).
+       return '<script src="'.urlto("ikiwiki/ikiwiki.js", $from).
                '" type="text/javascript" charset="utf-8"></script>'."\n".
-               '<script src="'.urlto("ikiwiki/relativedate.js", $page, $absolute).
+               '<script src="'.urlto("ikiwiki/relativedate.js", $from).
                '" type="text/javascript" charset="utf-8"></script>';
 }
 
index 1717c8cf3759e07724098390387dedf177ddcbaa..336a781ed527ae65edca735f336396077ac009ef 100644 (file)
@@ -100,7 +100,7 @@ sub confirmation_form ($$) {
                method => 'POST',
                javascript => 0,
                params => $q,
-               action => $config{cgiurl},
+               action => IkiWiki::cgiurl(),
                stylesheet => 1,
                fields => [qw{do page}],
        );
@@ -240,7 +240,7 @@ sub sessioncgi ($$) {
                                if (! exists $pagesources{$parent}) {
                                        $parent="index";
                                }
-                               IkiWiki::redirect($q, urlto($parent, '/', 1));
+                               IkiWiki::redirect($q, urlto($parent, undef));
                        }
                }
                else {
index a05e85be0106462f263a47468f72cf2f2c1261ff..57747d3c9df00141a1ade61e823c453a2ecbcc33 100644 (file)
@@ -126,7 +126,7 @@ sub rename_form ($$$) {
                method => 'POST',
                javascript => 0,
                params => $q,
-               action => $config{cgiurl},
+               action => IkiWiki::cgiurl(),
                stylesheet => 1,
                fields => [qw{do page new_name attachment}],
        );
index 8fb9dff0ca082bb16b6332c052e848408db162b8..78eb750b5f670caabe5840a51f589319eccf1204 100644 (file)
@@ -58,7 +58,7 @@ sub pagetemplate (@) {
        if ($template->query(name => "searchform")) {
                if (! defined $form) {
                        my $searchform = template("searchform.tmpl", blind_cache => 1);
-                       $searchform->param(searchaction => $config{cgiurl});
+                       $searchform->param(searchaction => IkiWiki::cgiurl());
                        $searchform->param(html5 => $config{html5});
                        $form=$searchform->output;
                }
@@ -176,7 +176,7 @@ sub cgi ($) {
                # only works for GET requests
                chdir("$config{wikistatedir}/xapian") || error("chdir: $!");
                $ENV{OMEGA_CONFIG_FILE}="./omega.conf";
-               $ENV{CGIURL}=$config{cgiurl},
+               $ENV{CGIURL}=IkiWiki::cgiurl();
                IkiWiki::loadindex();
                $ENV{HELPLINK}=htmllink("", "", "ikiwiki/searching",
                        noimageinline => 1, linktext => "Help");
index 1f93f87fe5f714e4b22e195cdc9b780311c14c65..af4d2ba3a858774ac6b77be58479fb2a4a18d69c 100644 (file)
@@ -70,19 +70,18 @@ sub format (@) {
                $params{content}=~s/<div class="toggleableend">//g;
                if (! ($params{content}=~s!^(<body[^>]*>)!$1.include_javascript($params{page})!em)) {
                        # no <body> tag, probably in preview mode
-                       $params{content}=include_javascript($params{page}, 1).$params{content};
+                       $params{content}=include_javascript(undef).$params{content};
                }
        }
        return $params{content};
 }
 
-sub include_javascript ($;$) {
-       my $page=shift;
-       my $absolute=shift;
+sub include_javascript ($) {
+       my $from=shift;
        
-       return '<script src="'.urlto("ikiwiki/ikiwiki.js", $page, $absolute).
+       return '<script src="'.urlto("ikiwiki/ikiwiki.js", $from).
                '" type="text/javascript" charset="utf-8"></script>'."\n".
-               '<script src="'.urlto("ikiwiki/toggle.js", $page, $absolute).
+               '<script src="'.urlto("ikiwiki/toggle.js", $from).
                '" type="text/javascript" charset="utf-8"></script>';
 }
 
index 9c032fdc6780884c86b13bdece90a9f972efc7f1..6a51903016830c17339f2130a964f87708ae15b0 100644 (file)
@@ -288,7 +288,7 @@ sub showform ($$) {
                fieldsets => [
                        [main => gettext("main")], 
                ],
-               action => $config{cgiurl},
+               action => IkiWiki::cgiurl(),
                template => {type => 'div'},
                stylesheet => 1,
        );
@@ -344,7 +344,7 @@ sub showform ($$) {
        IkiWiki::decode_form_utf8($form);
        
        if ($form->submitted eq "Cancel") {
-               IkiWiki::redirect($cgi, $config{url});
+               IkiWiki::redirect($cgi, IkiWiki::baseurl(undef));
                return;
        }
        elsif (($form->submitted eq 'Save Setup' || $form->submitted eq 'Rebuild Wiki') && $form->validate) {
index 71d7c9d17f51e49ec17aee087e984f3e8a7b9b79..134cfb9101b51d48bbabc6a47b7aaba1b73ff699 100644 (file)
@@ -31,14 +31,13 @@ sub formbuilder_setup (@) {
                        $form->field("do") eq "comment";
 
        $form->tmpl_param("wmd_preview", "<div class=\"wmd-preview\"></div>\n".
-               include_javascript(undef, 1));
+               include_javascript(undef));
 }
 
-sub include_javascript ($;$) {
-       my $page=shift;
-       my $absolute=shift;
+sub include_javascript ($) {
+       my $from=shift;
 
-       my $wmdjs=urlto("wmd/wmd.js", $page, $absolute);
+       my $wmdjs=urlto("wmd/wmd.js", $from);
        return <<"EOF"
 <script type="text/javascript">
 wmd_options = {
index 6b751f0cd639bf042c7fba2c4813cc918f914e31..33db3e707d8ad816bcc80a807ec8c8098fe72ec7 100644 (file)
@@ -988,6 +988,10 @@ Construct a relative url to the first parameter from the page named by the
 second. The first parameter can be either a page name, or some other
 destination file, as registered by `will_render`.
 
+If the second parameter is `undef`, the URL will be valid from any page on the
+wiki, or from the CGI; if possible it'll be a path starting with `/`, but an
+absolute URL will be used if the wiki and the CGI are on different servers.
+
 If the third parameter is passed and is true, an absolute url will be
 constructed instead of the default relative url.
 
diff --git a/t/urlto.t b/t/urlto.t
new file mode 100755 (executable)
index 0000000..a0b3baa
--- /dev/null
+++ b/t/urlto.t
@@ -0,0 +1,44 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 19;
+
+BEGIN { use_ok("IkiWiki"); }
+
+$IkiWiki::config{srcdir} = '/does/not/exist/';
+$IkiWiki::config{usedirs} = 1;
+$IkiWiki::config{htmlext} = "HTML";
+$IkiWiki::config{wiki_file_chars} = "A-Za-z0-9._";
+
+$IkiWiki::config{url} = "http://smcv.example.co.uk";
+$IkiWiki::config{cgiurl} = "http://smcv.example.co.uk/cgi-bin/ikiwiki.cgi";
+is(IkiWiki::checkconfig(), 1);
+
+# absolute version
+is(IkiWiki::cgiurl(cgiurl => $config{cgiurl}), "http://smcv.example.co.uk/cgi-bin/ikiwiki.cgi");
+is(IkiWiki::cgiurl(cgiurl => $config{cgiurl}, do => 'badger'), "http://smcv.example.co.uk/cgi-bin/ikiwiki.cgi?do=badger");
+is(IkiWiki::urlto('index', undef, 1), "http://smcv.example.co.uk/");
+is(IkiWiki::urlto('stoats', undef, 1), "http://smcv.example.co.uk/stoats/");
+
+# "local" (absolute path within site) version (default for cgiurl)
+is(IkiWiki::cgiurl(), "/cgi-bin/ikiwiki.cgi");
+is(IkiWiki::cgiurl(do => 'badger'), "/cgi-bin/ikiwiki.cgi?do=badger");
+is(IkiWiki::baseurl(undef), "/");
+is(IkiWiki::urlto('index', undef), "/");
+is(IkiWiki::urlto('stoats', undef), "/stoats/");
+
+# fully-relative version (default for urlto and baseurl)
+is(IkiWiki::baseurl('badger/mushroom'), "../../");
+is(IkiWiki::urlto('badger/mushroom', 'snake'), "../badger/mushroom/");
+
+# explicit cgiurl override
+is(IkiWiki::cgiurl(cgiurl => 'https://foo/ikiwiki'), "https://foo/ikiwiki");
+is(IkiWiki::cgiurl(do => 'badger', cgiurl => 'https://foo/ikiwiki'), "https://foo/ikiwiki?do=badger");
+
+# with url and cgiurl on different sites, "local" degrades to absolute
+$IkiWiki::config{url} = "http://example.co.uk/~smcv";
+$IkiWiki::config{cgiurl} = "http://dynamic.example.co.uk/~smcv/ikiwiki.cgi";
+is(IkiWiki::checkconfig(), 1);
+is(IkiWiki::cgiurl(), "http://dynamic.example.co.uk/~smcv/ikiwiki.cgi");
+is(IkiWiki::baseurl(undef), "http://example.co.uk/~smcv/");
+is(IkiWiki::urlto('stoats', undef), "http://example.co.uk/~smcv/stoats/");