(no commit message)
[ikiwiki.git] / t / relativity.t
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4
5 use Test::More;
6 plan(skip_all => "IPC::Run not available")
7         unless eval q{
8                 use IPC::Run qw(run);
9                 1;
10         };
11
12 use IkiWiki;
13
14 use Cwd qw(getcwd);
15 use Errno qw(ENOENT);
16
17 # Black-box (ish) test for relative linking between CGI and static content
18
19 sub parse_cgi_content {
20         my $content = shift;
21         my %bits;
22         if ($content =~ qr{<base href="([^"]+)" */>}) {
23                 $bits{basehref} = $1;
24         }
25         if ($content =~ qr{href="([^"]+/style.css)"}) {
26                 $bits{stylehref} = $1;
27         }
28         if ($content =~ qr{class="parentlinks">\s+<a href="([^"]+)">this is the name of my wiki</a>/}s) {
29                 $bits{tophref} = $1;
30         }
31         if ($content =~ qr{<a[^>]+href="([^"]+)\?do=prefs"}) {
32                 $bits{cgihref} = $1;
33         }
34         return %bits;
35 }
36
37 sub write_old_file {
38         my $name = shift;
39         my $content = shift;
40
41         writefile($name, "t/tmp/in", $content);
42         ok(utime(333333333, 333333333, "t/tmp/in/$name"));
43 }
44
45 sub write_setup_file {
46         my (%args) = @_;
47         my $urlline = defined $args{url} ? "url: $args{url}" : "";
48         my $w3mmodeline = defined $args{w3mmode} ? "w3mmode: $args{w3mmode}" : "";
49         my $reverseproxyline = defined $args{reverse_proxy} ? "reverse_proxy: $args{reverse_proxy}" : "";
50
51         writefile("test.setup", "t/tmp", <<EOF
52 # IkiWiki::Setup::Yaml - YAML formatted setup file
53 wikiname: this is the name of my wiki
54 srcdir: t/tmp/in
55 destdir: t/tmp/out
56 templatedir: templates
57 $urlline
58 cgiurl: $args{cgiurl}
59 $w3mmodeline
60 cgi_wrapper: t/tmp/ikiwiki.cgi
61 cgi_wrappermode: 0754
62 html5: $args{html5}
63 # make it easier to test previewing
64 add_plugins:
65 - anonok
66 anonok_pagespec: "*"
67 $reverseproxyline
68 ENV: { 'PERL5LIB': 'blib/lib:blib/arch' }
69 EOF
70         );
71 }
72
73 sub thoroughly_rebuild {
74         ok(unlink("t/tmp/ikiwiki.cgi") || $!{ENOENT});
75         ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
76 }
77
78 sub check_cgi_mode_bits {
79         my (undef, undef, $mode, undef, undef,
80                 undef, undef, undef, undef, undef,
81                 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
82         is($mode & 07777, 0754);
83 }
84
85 sub check_generated_content {
86         my $cgiurl_regex = shift;
87         ok(-e "t/tmp/out/a/b/c/index.html");
88         my $content = readfile("t/tmp/out/a/b/c/index.html");
89         # no <base> on static HTML
90         unlike($content, qr{<base\W});
91         like($content, $cgiurl_regex);
92         # cross-links between static pages are relative
93         like($content, qr{<li>A: <a href="../../">a</a></li>});
94         like($content, qr{<li>B: <a href="../">b</a></li>});
95         like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
96 }
97
98 sub run_cgi {
99         my (%args) = @_;
100         my ($in, $out);
101         my $is_preview = delete $args{is_preview};
102         my $is_https = delete $args{is_https};
103         my %defaults = (
104                 SCRIPT_NAME     => '/cgi-bin/ikiwiki.cgi',
105                 HTTP_HOST       => 'example.com',
106         );
107         if (defined $is_preview) {
108                 $defaults{REQUEST_METHOD} = 'POST';
109                 $in = 'do=edit&page=a/b/c&Preview';
110                 $defaults{CONTENT_LENGTH} = length $in;
111         } else {
112                 $defaults{REQUEST_METHOD} = 'GET';
113                 $defaults{QUERY_STRING} = 'do=prefs';
114         }
115         if (defined $is_https) {
116                 $defaults{SERVER_PORT} = '443';
117                 $defaults{HTTPS} = 'on';
118         } else {
119                 $defaults{SERVER_PORT} = '80';
120         }
121         my %envvars = (
122                 %defaults,
123                 %args,
124         );
125         run(["./t/tmp/ikiwiki.cgi"], \$in, \$out, init => sub {
126                 map {
127                         $ENV{$_} = $envvars{$_}
128                 } keys(%envvars);
129         });
130
131         return $out;
132 }
133
134 sub test_startup {
135         ok(! system("make -s ikiwiki.out"));
136         ok(! system("rm -rf t/tmp"));
137         ok(! system("mkdir t/tmp"));
138
139         write_old_file("a.mdwn", "A");
140         write_old_file("a/b.mdwn", "B");
141         write_old_file("a/b/c.mdwn",
142         "* A: [[a]]\n".
143         "* B: [[b]]\n".
144         "* E: [[a/d/e]]\n");
145         write_old_file("a/d.mdwn", "D");
146         write_old_file("a/d/e.mdwn", "E");
147 }
148
149 sub test_site1_perfectly_ordinary_ikiwiki {
150         write_setup_file(
151                 html5   => 0,
152                 url     => "http://example.com/wiki/",
153                 cgiurl  => "http://example.com/cgi-bin/ikiwiki.cgi",
154         );
155         thoroughly_rebuild();
156         check_cgi_mode_bits();
157         # url and cgiurl are on the same host so the cgiurl is host-relative
158         check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
159         my %bits = parse_cgi_content(run_cgi());
160         is($bits{basehref}, "http://example.com/wiki/");
161         like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
162         like($bits{tophref}, qr{^(?:/wiki|\.)/$});
163         like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
164
165         # when accessed via HTTPS, links are secure
166         %bits = parse_cgi_content(run_cgi(is_https => 1));
167         is($bits{basehref}, "https://example.com/wiki/");
168         like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
169         like($bits{tophref}, qr{^(?:/wiki|\.)/$});
170         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
171
172         # when accessed via a different hostname, links stay on that host
173         %bits = parse_cgi_content(run_cgi(HTTP_HOST => 'staging.example.net'));
174         is($bits{basehref}, "http://staging.example.net/wiki/");
175         like($bits{stylehref}, qr{^(?:(?:http:)?//staging.example.net)?/wiki/style.css$});
176         like($bits{tophref}, qr{^(?:/wiki|\.)/$});
177         like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
178
179         # previewing a page
180         %bits = parse_cgi_content(run_cgi(is_preview => 1));
181         is($bits{basehref}, "http://example.com/wiki/a/b/c/");
182         like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
183         like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
184         like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
185
186         # in html5, the <base> is allowed to be relative, and we take full
187         # advantage of that
188         write_setup_file(
189                 html5   => 1,
190                 url     => "http://example.com/wiki/",
191                 cgiurl  => "http://example.com/cgi-bin/ikiwiki.cgi",
192         );
193         thoroughly_rebuild();
194         check_cgi_mode_bits();
195         # url and cgiurl are on the same host so the cgiurl is host-relative
196         check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
197
198         %bits = parse_cgi_content(run_cgi());
199         is($bits{basehref}, "/wiki/");
200         is($bits{stylehref}, "/wiki/style.css");
201         is($bits{tophref}, "/wiki/");
202         is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
203
204         # when accessed via HTTPS, links are secure - this is easy because under
205         # html5 they're independent of the URL at which the CGI was accessed
206         %bits = parse_cgi_content(run_cgi(is_https => 1));
207         is($bits{basehref}, "/wiki/");
208         is($bits{stylehref}, "/wiki/style.css");
209         is($bits{tophref}, "/wiki/");
210         is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
211
212         # when accessed via a different hostname, links stay on that host -
213         # this is really easy in html5 because we can use relative URLs
214         %bits = parse_cgi_content(run_cgi(HTTP_HOST => 'staging.example.net'));
215         is($bits{basehref}, "/wiki/");
216         is($bits{stylehref}, "/wiki/style.css");
217         is($bits{tophref}, "/wiki/");
218         is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
219
220         # previewing a page
221         %bits = parse_cgi_content(run_cgi(is_preview => 1));
222         is($bits{basehref}, "/wiki/a/b/c/");
223         is($bits{stylehref}, "/wiki/style.css");
224         like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
225         is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
226 }
227
228 sub test_site2_static_content_and_cgi_on_different_servers {
229         write_setup_file(
230                 html5   => 0,
231                 url     => "http://static.example.com/",
232                 cgiurl  => "http://cgi.example.com/ikiwiki.cgi",
233         );
234         thoroughly_rebuild();
235         check_cgi_mode_bits();
236         # url and cgiurl are not on the same host so the cgiurl has to be
237         # protocol-relative or absolute
238         check_generated_content(qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
239
240         my %bits = parse_cgi_content(run_cgi(SCRIPT_NAME => '/ikiwiki.cgi', HTTP_HOST => 'cgi.example.com'));
241         like($bits{basehref}, qr{^http://static.example.com/$});
242         like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com)?/style.css$});
243         like($bits{tophref}, qr{^(?:http:)?//static.example.com/$});
244         like($bits{cgihref}, qr{^(?:(?:http:)?//cgi.example.com)?/ikiwiki.cgi$});
245
246         # when accessed via HTTPS, links are secure
247         %bits = parse_cgi_content(run_cgi(is_https => 1, SCRIPT_NAME => '/ikiwiki.cgi', HTTP_HOST => 'cgi.example.com'));
248         like($bits{basehref}, qr{^https://static.example.com/$});
249         like($bits{stylehref}, qr{^(?:(?:https:)?//static.example.com)?/style.css$});
250         like($bits{tophref}, qr{^(?:https:)?//static.example.com/$});
251         like($bits{cgihref}, qr{^(?:(?:https:)?//cgi.example.com)?/ikiwiki.cgi$});
252
253         # when accessed via a different hostname, links to the CGI (only) should
254         # stay on that host?
255         %bits = parse_cgi_content(run_cgi(is_preview => 1, SCRIPT_NAME => '/ikiwiki.cgi', HTTP_HOST => 'staging.example.net'));
256         like($bits{basehref}, qr{^http://static.example.com/a/b/c/$});
257         like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/style.css$});
258         like($bits{tophref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/$});
259         like($bits{cgihref}, qr{^(?:(?:http:)?//(?:staging\.example\.net|cgi\.example\.com))?/ikiwiki.cgi$});
260         TODO: {
261         local $TODO = "use self-referential CGI URL?";
262         like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/ikiwiki.cgi$});
263         }
264
265         write_setup_file(
266                 html5   => 1,
267                 url     => "http://static.example.com/",
268                 cgiurl  => "http://cgi.example.com/ikiwiki.cgi",
269         );
270         thoroughly_rebuild();
271         check_cgi_mode_bits();
272         # url and cgiurl are not on the same host so the cgiurl has to be
273         # protocol-relative or absolute
274         check_generated_content(qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
275
276         %bits = parse_cgi_content(run_cgi(SCRIPT_NAME => '/ikiwiki.cgi', HTTP_HOST => 'cgi.example.com'));
277         is($bits{basehref}, "//static.example.com/");
278         is($bits{stylehref}, "//static.example.com/style.css");
279         is($bits{tophref}, "//static.example.com/");
280         is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
281
282         # when accessed via HTTPS, links are secure - in fact they're exactly the
283         # same as when accessed via HTTP
284         %bits = parse_cgi_content(run_cgi(is_https => 1, SCRIPT_NAME => '/ikiwiki.cgi', HTTP_HOST => 'cgi.example.com'));
285         is($bits{basehref}, "//static.example.com/");
286         is($bits{stylehref}, "//static.example.com/style.css");
287         is($bits{tophref}, "//static.example.com/");
288         is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
289
290         # when accessed via a different hostname, links to the CGI (only) should
291         # stay on that host?
292         %bits = parse_cgi_content(run_cgi(is_preview => 1, SCRIPT_NAME => '/ikiwiki.cgi', HTTP_HOST => 'staging.example.net'));
293         is($bits{basehref}, "//static.example.com/a/b/c/");
294         is($bits{stylehref}, "//static.example.com/style.css");
295         is($bits{tophref}, "../../../");
296         like($bits{cgihref}, qr{//(?:staging\.example\.net|cgi\.example\.com)/ikiwiki\.cgi});
297         TODO: {
298         local $TODO = "use self-referential CGI URL maybe?";
299         is($bits{cgihref}, "//staging.example.net/ikiwiki.cgi");
300         }
301 }
302
303 sub test_site3_we_specifically_want_everything_to_be_secure {
304         write_setup_file(
305                 html5   => 0,
306                 url     => "https://example.com/wiki/",
307                 cgiurl  => "https://example.com/cgi-bin/ikiwiki.cgi",
308         );
309         thoroughly_rebuild();
310         check_cgi_mode_bits();
311         # url and cgiurl are on the same host so the cgiurl is host-relative
312         check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
313
314         # when accessed via HTTPS, links are secure
315         my %bits = parse_cgi_content(run_cgi(is_https => 1));
316         is($bits{basehref}, "https://example.com/wiki/");
317         like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
318         like($bits{tophref}, qr{^(?:/wiki|\.)/$});
319         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
320
321         # when not accessed via HTTPS, links should still be secure
322         # (but if this happens, that's a sign of web server misconfiguration)
323         %bits = parse_cgi_content(run_cgi());
324         like($bits{tophref}, qr{^(?:/wiki|\.)/$});
325         TODO: {
326         local $TODO = "treat https in configured url, cgiurl as required?";
327         is($bits{basehref}, "https://example.com/wiki/");
328         like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
329         }
330         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
331
332         # when accessed via a different hostname, links stay on that host
333         %bits = parse_cgi_content(run_cgi(is_https => 1, HTTP_HOST => 'staging.example.net'));
334         is($bits{basehref}, "https://staging.example.net/wiki/");
335         like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
336         like($bits{tophref}, qr{^(?:/wiki|\.)/$});
337         like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
338
339         # previewing a page
340         %bits = parse_cgi_content(run_cgi(is_preview => 1, is_https => 1));
341         is($bits{basehref}, "https://example.com/wiki/a/b/c/");
342         like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
343         like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
344         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
345
346         # not testing html5: 0 here because that ends up identical to site 1
347 }
348
349 sub test_site4_cgi_is_secure_static_content_doesnt_have_to_be {
350         # (NetBSD wiki)
351         write_setup_file(
352                 html5   => 0,
353                 url     => "http://example.com/wiki/",
354                 cgiurl  => "https://example.com/cgi-bin/ikiwiki.cgi",
355         );
356         thoroughly_rebuild();
357         check_cgi_mode_bits();
358         # url and cgiurl are on the same host but different schemes
359         check_generated_content(qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
360
361         # when accessed via HTTPS, links are secure (to avoid mixed-content)
362         my %bits = parse_cgi_content(run_cgi(is_https => 1));
363         is($bits{basehref}, "https://example.com/wiki/");
364         like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
365         like($bits{tophref}, qr{^(?:/wiki|\.)/$});
366         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
367
368         # when not accessed via HTTPS, ???
369         %bits = parse_cgi_content(run_cgi());
370         like($bits{basehref}, qr{^https?://example.com/wiki/$});
371         like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
372         like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
373         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
374
375         # when accessed via a different hostname, links stay on that host
376         %bits = parse_cgi_content(run_cgi(is_https => 1, HTTP_HOST => 'staging.example.net'));
377         # because the static and dynamic stuff is on the same server, we assume that
378         # both are also on the staging server
379         like($bits{basehref}, qr{^https://staging.example.net/wiki/$});
380         like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
381         like($bits{tophref}, qr{^(?:(?:(?:https:)?//staging.example.net)?/wiki|\.)/$});
382         like($bits{cgihref}, qr{^(?:(?:https:)?//(?:staging\.example\.net|example\.com))?/cgi-bin/ikiwiki.cgi$});
383         TODO: {
384         local $TODO = "this should really point back to itself but currently points to example.com";
385         like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
386         }
387
388         # previewing a page
389         %bits = parse_cgi_content(run_cgi(is_preview => 1, is_https => 1));
390         is($bits{basehref}, "https://example.com/wiki/a/b/c/");
391         like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
392         like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
393         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
394
395         write_setup_file(
396                 html5   => 1,
397                 url     => "http://example.com/wiki/",
398                 cgiurl  => "https://example.com/cgi-bin/ikiwiki.cgi",
399         );
400         thoroughly_rebuild();
401         check_cgi_mode_bits();
402         # url and cgiurl are on the same host but different schemes
403         check_generated_content(qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
404
405         # when accessed via HTTPS, links are secure (to avoid mixed-content)
406         %bits = parse_cgi_content(run_cgi(is_https => 1));
407         is($bits{basehref}, "/wiki/");
408         is($bits{stylehref}, "/wiki/style.css");
409         is($bits{tophref}, "/wiki/");
410         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
411
412         # when not accessed via HTTPS, ???
413         %bits = parse_cgi_content(run_cgi());
414         like($bits{basehref}, qr{^(?:https?://example.com)?/wiki/$});
415         like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
416         like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
417         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
418
419         # when accessed via a different hostname, links stay on that host
420         %bits = parse_cgi_content(run_cgi(is_https => 1, HTTP_HOST => 'staging.example.net'));
421         # because the static and dynamic stuff is on the same server, we assume that
422         # both are also on the staging server
423         is($bits{basehref}, "/wiki/");
424         is($bits{stylehref}, "/wiki/style.css");
425         like($bits{tophref}, qr{^(?:/wiki|\.)/$});
426         like($bits{cgihref}, qr{^(?:(?:https:)?//(?:example\.com|staging\.example\.net))?/cgi-bin/ikiwiki.cgi$});
427         TODO: {
428         local $TODO = "this should really point back to itself but currently points to example.com";
429         like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
430         }
431
432         # previewing a page
433         %bits = parse_cgi_content(run_cgi(is_preview => 1, is_https => 1));
434         is($bits{basehref}, "/wiki/a/b/c/");
435         is($bits{stylehref}, "/wiki/style.css");
436         like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
437         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
438
439         # Deliberately not testing https static content with http cgiurl,
440         # because that makes remarkably little sense.
441 }
442
443 sub test_site5_w3mmode {
444         # as documented in [[w3mmode]]
445         write_setup_file(
446                 html5   => 0, 
447                 url     => undef,
448                 cgiurl  => "ikiwiki.cgi",
449                 w3mmode => 1,
450         );
451         thoroughly_rebuild();
452         check_cgi_mode_bits();
453         # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
454         check_generated_content(qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
455
456         my %bits = parse_cgi_content(run_cgi(PATH_INFO => '/ikiwiki.cgi', SCRIPT_NAME => '/cgi-bin/ikiwiki-w3m.cgi'));
457         my $pwd = getcwd();
458         like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
459         like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
460         like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
461         like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
462
463         write_setup_file(
464                 html5   => 1,
465                 url     => undef,
466                 cgiurl  => "ikiwiki.cgi",
467                 w3mmode => 1,
468         );
469         thoroughly_rebuild();
470         check_cgi_mode_bits();
471         # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
472         check_generated_content(qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
473
474         %bits = parse_cgi_content(run_cgi(PATH_INFO => '/ikiwiki.cgi', SCRIPT_NAME => '/cgi-bin/ikiwiki-w3m.cgi'));
475         like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
476         like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
477         like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
478         like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
479 }
480
481 sub test_site6_behind_reverse_proxy {
482         write_setup_file(
483                 html5   => 0,
484                 url     => "https://example.com/wiki/",
485                 cgiurl  => "https://example.com/cgi-bin/ikiwiki.cgi",
486                 reverse_proxy => 1,
487         );
488         thoroughly_rebuild();
489         check_cgi_mode_bits();
490         # url and cgiurl are on the same host so the cgiurl is host-relative
491         check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
492
493         # because we are behind a reverse-proxy we must assume that
494         # we're being accessed by the configured cgiurl
495         my %bits = parse_cgi_content(run_cgi(HTTP_HOST => 'localhost'));
496         like($bits{tophref}, qr{^(?:/wiki|\.)/$});
497         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
498         is($bits{basehref}, "https://example.com/wiki/");
499         like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
500
501         # previewing a page
502         %bits = parse_cgi_content(run_cgi(is_preview => 1, HTTP_HOST => 'localhost'));
503         like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
504         like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
505         is($bits{basehref}, "https://example.com/wiki/a/b/c/");
506         like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
507
508         # not testing html5: 1 because it would be the same as site 1 -
509         # the reverse_proxy config option is unnecessary under html5
510 }
511
512 test_startup();
513
514 test_site1_perfectly_ordinary_ikiwiki();
515 test_site2_static_content_and_cgi_on_different_servers();
516 test_site3_we_specifically_want_everything_to_be_secure();
517 test_site4_cgi_is_secure_static_content_doesnt_have_to_be();
518 test_site5_w3mmode();
519 test_site6_behind_reverse_proxy();
520
521 done_testing();