Extract check_generated_content(). Same output.
[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 my $pwd = getcwd();
18
19 # Black-box (ish) test for relative linking between CGI and static content
20
21 my $blob;
22 my ($content, $in, %bits);
23
24 sub parse_cgi_content {
25         my %bits;
26         if ($content =~ qr{<base href="([^"]+)" */>}) {
27                 $bits{basehref} = $1;
28         }
29         if ($content =~ qr{href="([^"]+/style.css)"}) {
30                 $bits{stylehref} = $1;
31         }
32         if ($content =~ qr{class="parentlinks">\s+<a href="([^"]+)">this is the name of my wiki</a>/}s) {
33                 $bits{tophref} = $1;
34         }
35         if ($content =~ qr{<a[^>]+href="([^"]+)\?do=prefs"}) {
36                 $bits{cgihref} = $1;
37         }
38         return %bits;
39 }
40
41 ok(! system("make -s ikiwiki.out"));
42 ok(! system("rm -rf t/tmp"));
43 ok(! system("mkdir t/tmp"));
44
45 sub write_old_file {
46         my $name = shift;
47         my $content = shift;
48
49         writefile($name, "t/tmp/in", $content);
50         ok(utime(333333333, 333333333, "t/tmp/in/$name"));
51 }
52
53 write_old_file("a.mdwn", "A");
54 write_old_file("a/b.mdwn", "B");
55 write_old_file("a/b/c.mdwn",
56 "* A: [[a]]\n".
57 "* B: [[b]]\n".
58 "* E: [[a/d/e]]\n");
59 write_old_file("a/d.mdwn", "D");
60 write_old_file("a/d/e.mdwn", "E");
61
62 sub write_setup_file {
63         my (%args) = @_;
64         my $urlline = defined $args{url} ? "url: $args{url}" : "";
65         my $w3mmodeline = defined $args{w3mmode} ? "w3mmode: $args{w3mmode}" : "";
66         my $reverseproxyline = defined $args{reverse_proxy} ? "reverse_proxy: $args{reverse_proxy}" : "";
67
68         writefile("test.setup", "t/tmp", <<EOF
69 # IkiWiki::Setup::Yaml - YAML formatted setup file
70 wikiname: this is the name of my wiki
71 srcdir: t/tmp/in
72 destdir: t/tmp/out
73 templatedir: templates
74 $urlline
75 cgiurl: $args{cgiurl}
76 $w3mmodeline
77 cgi_wrapper: t/tmp/ikiwiki.cgi
78 cgi_wrappermode: 0754
79 html5: $args{html5}
80 # make it easier to test previewing
81 add_plugins:
82 - anonok
83 anonok_pagespec: "*"
84 $reverseproxyline
85 ENV: { 'PERL5LIB': 'blib/lib:blib/arch' }
86 EOF
87         );
88 }
89
90 sub thoroughly_rebuild {
91         ok(unlink("t/tmp/ikiwiki.cgi") || $!{ENOENT});
92         ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
93 }
94
95 sub check_cgi_mode_bits {
96         my (undef, undef, $mode, undef, undef,
97                 undef, undef, undef, undef, undef,
98                 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
99         is($mode & 07777, 0754);
100 }
101
102 sub check_generated_content {
103         my $cgiurl_regex = shift;
104         ok(-e "t/tmp/out/a/b/c/index.html");
105         $content = readfile("t/tmp/out/a/b/c/index.html");
106         # no <base> on static HTML
107         unlike($content, qr{<base\W});
108         like($content, $cgiurl_regex);
109         # cross-links between static pages are relative
110         like($content, qr{<li>A: <a href="../../">a</a></li>});
111         like($content, qr{<li>B: <a href="../">b</a></li>});
112         like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
113 }
114
115 #######################################################################
116 # site 1: a perfectly ordinary ikiwiki
117
118 write_setup_file(
119         html5   => 0,
120         url     => "http://example.com/wiki/",
121         cgiurl  => "http://example.com/cgi-bin/ikiwiki.cgi",
122 );
123 thoroughly_rebuild();
124 check_cgi_mode_bits();
125 # url and cgiurl are on the same host so the cgiurl is host-relative
126 check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
127
128 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
129         $ENV{REQUEST_METHOD} = 'GET';
130         $ENV{SERVER_PORT} = '80';
131         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
132         $ENV{QUERY_STRING} = 'do=prefs';
133         $ENV{HTTP_HOST} = 'example.com';
134 });
135 %bits = parse_cgi_content($content);
136 is($bits{basehref}, "http://example.com/wiki/");
137 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
138 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
139 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
140
141 # when accessed via HTTPS, links are secure
142 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
143         $ENV{REQUEST_METHOD} = 'GET';
144         $ENV{SERVER_PORT} = '443';
145         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
146         $ENV{QUERY_STRING} = 'do=prefs';
147         $ENV{HTTP_HOST} = 'example.com';
148         $ENV{HTTPS} = 'on';
149 });
150 %bits = parse_cgi_content($content);
151 is($bits{basehref}, "https://example.com/wiki/");
152 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
153 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
154 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
155
156 # when accessed via a different hostname, links stay on that host
157 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
158         $ENV{REQUEST_METHOD} = 'GET';
159         $ENV{SERVER_PORT} = '80';
160         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
161         $ENV{QUERY_STRING} = 'do=prefs';
162         $ENV{HTTP_HOST} = 'staging.example.net';
163 });
164 %bits = parse_cgi_content($content);
165 is($bits{basehref}, "http://staging.example.net/wiki/");
166 like($bits{stylehref}, qr{^(?:(?:http:)?//staging.example.net)?/wiki/style.css$});
167 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
168 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
169
170 # previewing a page
171 $in = 'do=edit&page=a/b/c&Preview';
172 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
173         $ENV{REQUEST_METHOD} = 'POST';
174         $ENV{SERVER_PORT} = '80';
175         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
176         $ENV{HTTP_HOST} = 'example.com';
177         $ENV{CONTENT_LENGTH} = length $in;
178 });
179 %bits = parse_cgi_content($content);
180 is($bits{basehref}, "http://example.com/wiki/a/b/c/");
181 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
182 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
183 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
184
185 # in html5, the <base> is allowed to be relative, and we take full
186 # advantage of that
187 write_setup_file(
188         html5   => 1,
189         url     => "http://example.com/wiki/",
190         cgiurl  => "http://example.com/cgi-bin/ikiwiki.cgi",
191 );
192 thoroughly_rebuild();
193 check_cgi_mode_bits();
194 # url and cgiurl are on the same host so the cgiurl is host-relative
195 check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
196
197 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
198         $ENV{REQUEST_METHOD} = 'GET';
199         $ENV{SERVER_PORT} = '80';
200         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
201         $ENV{QUERY_STRING} = 'do=prefs';
202         $ENV{HTTP_HOST} = 'example.com';
203 });
204 %bits = parse_cgi_content($content);
205 is($bits{basehref}, "/wiki/");
206 is($bits{stylehref}, "/wiki/style.css");
207 is($bits{tophref}, "/wiki/");
208 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
209
210 # when accessed via HTTPS, links are secure - this is easy because under
211 # html5 they're independent of the URL at which the CGI was accessed
212 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
213         $ENV{REQUEST_METHOD} = 'GET';
214         $ENV{SERVER_PORT} = '443';
215         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
216         $ENV{QUERY_STRING} = 'do=prefs';
217         $ENV{HTTP_HOST} = 'example.com';
218         $ENV{HTTPS} = 'on';
219 });
220 %bits = parse_cgi_content($content);
221 is($bits{basehref}, "/wiki/");
222 is($bits{stylehref}, "/wiki/style.css");
223 is($bits{tophref}, "/wiki/");
224 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
225
226 # when accessed via a different hostname, links stay on that host -
227 # this is really easy in html5 because we can use relative URLs
228 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
229         $ENV{REQUEST_METHOD} = 'GET';
230         $ENV{SERVER_PORT} = '80';
231         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
232         $ENV{QUERY_STRING} = 'do=prefs';
233         $ENV{HTTP_HOST} = 'staging.example.net';
234 });
235 %bits = parse_cgi_content($content);
236 is($bits{basehref}, "/wiki/");
237 is($bits{stylehref}, "/wiki/style.css");
238 is($bits{tophref}, "/wiki/");
239 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
240
241 # previewing a page
242 $in = 'do=edit&page=a/b/c&Preview';
243 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
244         $ENV{REQUEST_METHOD} = 'POST';
245         $ENV{SERVER_PORT} = '80';
246         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
247         $ENV{HTTP_HOST} = 'example.com';
248         $ENV{CONTENT_LENGTH} = length $in;
249 });
250 %bits = parse_cgi_content($content);
251 is($bits{basehref}, "/wiki/a/b/c/");
252 is($bits{stylehref}, "/wiki/style.css");
253 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
254 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
255
256 #######################################################################
257 # site 2: static content and CGI are on different servers
258
259 write_setup_file(
260         html5   => 0,
261         url     => "http://static.example.com/",
262         cgiurl  => "http://cgi.example.com/ikiwiki.cgi",
263 );
264 thoroughly_rebuild();
265 check_cgi_mode_bits();
266 # url and cgiurl are not on the same host so the cgiurl has to be
267 # protocol-relative or absolute
268 check_generated_content(qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
269
270 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
271         $ENV{REQUEST_METHOD} = 'GET';
272         $ENV{SERVER_PORT} = '80';
273         $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
274         $ENV{QUERY_STRING} = 'do=prefs';
275         $ENV{HTTP_HOST} = 'cgi.example.com';
276 });
277 %bits = parse_cgi_content($content);
278 like($bits{basehref}, qr{^http://static.example.com/$});
279 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com)?/style.css$});
280 like($bits{tophref}, qr{^(?:http:)?//static.example.com/$});
281 like($bits{cgihref}, qr{^(?:(?:http:)?//cgi.example.com)?/ikiwiki.cgi$});
282
283 # when accessed via HTTPS, links are secure
284 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
285         $ENV{REQUEST_METHOD} = 'GET';
286         $ENV{SERVER_PORT} = '443';
287         $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
288         $ENV{QUERY_STRING} = 'do=prefs';
289         $ENV{HTTP_HOST} = 'cgi.example.com';
290         $ENV{HTTPS} = 'on';
291 });
292 %bits = parse_cgi_content($content);
293 like($bits{basehref}, qr{^https://static.example.com/$});
294 like($bits{stylehref}, qr{^(?:(?:https:)?//static.example.com)?/style.css$});
295 like($bits{tophref}, qr{^(?:https:)?//static.example.com/$});
296 like($bits{cgihref}, qr{^(?:(?:https:)?//cgi.example.com)?/ikiwiki.cgi$});
297
298 # when accessed via a different hostname, links to the CGI (only) should
299 # stay on that host?
300 $in = 'do=edit&page=a/b/c&Preview';
301 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
302         $ENV{REQUEST_METHOD} = 'POST';
303         $ENV{SERVER_PORT} = '80';
304         $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
305         $ENV{HTTP_HOST} = 'staging.example.net';
306         $ENV{CONTENT_LENGTH} = length $in;
307 });
308 %bits = parse_cgi_content($content);
309 like($bits{basehref}, qr{^http://static.example.com/a/b/c/$});
310 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/style.css$});
311 like($bits{tophref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/$});
312 like($bits{cgihref}, qr{^(?:(?:http:)?//(?:staging\.example\.net|cgi\.example\.com))?/ikiwiki.cgi$});
313 TODO: {
314 local $TODO = "use self-referential CGI URL?";
315 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/ikiwiki.cgi$});
316 }
317
318 write_setup_file(
319         html5   => 1,
320         url     => "http://static.example.com/",
321         cgiurl  => "http://cgi.example.com/ikiwiki.cgi",
322 );
323 thoroughly_rebuild();
324 check_cgi_mode_bits();
325 # url and cgiurl are not on the same host so the cgiurl has to be
326 # protocol-relative or absolute
327 check_generated_content(qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
328
329 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
330         $ENV{REQUEST_METHOD} = 'GET';
331         $ENV{SERVER_PORT} = '80';
332         $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
333         $ENV{QUERY_STRING} = 'do=prefs';
334         $ENV{HTTP_HOST} = 'cgi.example.com';
335 });
336 %bits = parse_cgi_content($content);
337 is($bits{basehref}, "//static.example.com/");
338 is($bits{stylehref}, "//static.example.com/style.css");
339 is($bits{tophref}, "//static.example.com/");
340 is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
341
342 # when accessed via HTTPS, links are secure - in fact they're exactly the
343 # same as when accessed via HTTP
344 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
345         $ENV{REQUEST_METHOD} = 'GET';
346         $ENV{SERVER_PORT} = '443';
347         $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
348         $ENV{QUERY_STRING} = 'do=prefs';
349         $ENV{HTTP_HOST} = 'cgi.example.com';
350         $ENV{HTTPS} = 'on';
351 });
352 %bits = parse_cgi_content($content);
353 is($bits{basehref}, "//static.example.com/");
354 is($bits{stylehref}, "//static.example.com/style.css");
355 is($bits{tophref}, "//static.example.com/");
356 is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
357
358 # when accessed via a different hostname, links to the CGI (only) should
359 # stay on that host?
360 $in = 'do=edit&page=a/b/c&Preview';
361 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
362         $ENV{REQUEST_METHOD} = 'POST';
363         $ENV{SERVER_PORT} = '80';
364         $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
365         $ENV{HTTP_HOST} = 'staging.example.net';
366         $ENV{CONTENT_LENGTH} = length $in;
367 });
368 %bits = parse_cgi_content($content);
369 is($bits{basehref}, "//static.example.com/a/b/c/");
370 is($bits{stylehref}, "//static.example.com/style.css");
371 is($bits{tophref}, "../../../");
372 like($bits{cgihref}, qr{//(?:staging\.example\.net|cgi\.example\.com)/ikiwiki\.cgi});
373 TODO: {
374 local $TODO = "use self-referential CGI URL maybe?";
375 is($bits{cgihref}, "//staging.example.net/ikiwiki.cgi");
376 }
377
378 #######################################################################
379 # site 3: we specifically want everything to be secure
380
381 write_setup_file(
382         html5   => 0,
383         url     => "https://example.com/wiki/",
384         cgiurl  => "https://example.com/cgi-bin/ikiwiki.cgi",
385 );
386 thoroughly_rebuild();
387 check_cgi_mode_bits();
388 # url and cgiurl are on the same host so the cgiurl is host-relative
389 check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
390
391 # when accessed via HTTPS, links are secure
392 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
393         $ENV{REQUEST_METHOD} = 'GET';
394         $ENV{SERVER_PORT} = '443';
395         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
396         $ENV{QUERY_STRING} = 'do=prefs';
397         $ENV{HTTP_HOST} = 'example.com';
398         $ENV{HTTPS} = 'on';
399 });
400 %bits = parse_cgi_content($content);
401 is($bits{basehref}, "https://example.com/wiki/");
402 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
403 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
404 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
405
406 # when not accessed via HTTPS, links should still be secure
407 # (but if this happens, that's a sign of web server misconfiguration)
408 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
409         $ENV{REQUEST_METHOD} = 'GET';
410         $ENV{SERVER_PORT} = '80';
411         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
412         $ENV{QUERY_STRING} = 'do=prefs';
413         $ENV{HTTP_HOST} = 'example.com';
414 });
415 %bits = parse_cgi_content($content);
416 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
417 TODO: {
418 local $TODO = "treat https in configured url, cgiurl as required?";
419 is($bits{basehref}, "https://example.com/wiki/");
420 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
421 }
422 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
423
424 # when accessed via a different hostname, links stay on that host
425 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
426         $ENV{REQUEST_METHOD} = 'GET';
427         $ENV{SERVER_PORT} = '443';
428         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
429         $ENV{QUERY_STRING} = 'do=prefs';
430         $ENV{HTTP_HOST} = 'staging.example.net';
431         $ENV{HTTPS} = 'on';
432 });
433 %bits = parse_cgi_content($content);
434 is($bits{basehref}, "https://staging.example.net/wiki/");
435 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
436 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
437 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
438
439 # previewing a page
440 $in = 'do=edit&page=a/b/c&Preview';
441 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
442         $ENV{REQUEST_METHOD} = 'POST';
443         $ENV{SERVER_PORT} = '443';
444         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
445         $ENV{HTTP_HOST} = 'example.com';
446         $ENV{CONTENT_LENGTH} = length $in;
447         $ENV{HTTPS} = 'on';
448 });
449 %bits = parse_cgi_content($content);
450 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
451 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
452 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
453 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
454
455 # not testing html5: 0 here because that ends up identical to site 1
456
457 #######################################################################
458 # site 4 (NetBSD wiki): CGI is secure, static content doesn't have to be
459
460 write_setup_file(
461         html5   => 0,
462         url     => "http://example.com/wiki/",
463         cgiurl  => "https://example.com/cgi-bin/ikiwiki.cgi",
464 );
465 thoroughly_rebuild();
466 check_cgi_mode_bits();
467 # url and cgiurl are on the same host but different schemes
468 check_generated_content(qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
469
470 # when accessed via HTTPS, links are secure (to avoid mixed-content)
471 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
472         $ENV{REQUEST_METHOD} = 'GET';
473         $ENV{SERVER_PORT} = '443';
474         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
475         $ENV{QUERY_STRING} = 'do=prefs';
476         $ENV{HTTP_HOST} = 'example.com';
477         $ENV{HTTPS} = 'on';
478 });
479 %bits = parse_cgi_content($content);
480 is($bits{basehref}, "https://example.com/wiki/");
481 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
482 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
483 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
484
485 # when not accessed via HTTPS, ???
486 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
487         $ENV{REQUEST_METHOD} = 'GET';
488         $ENV{SERVER_PORT} = '80';
489         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
490         $ENV{QUERY_STRING} = 'do=prefs';
491         $ENV{HTTP_HOST} = 'example.com';
492 });
493 %bits = parse_cgi_content($content);
494 like($bits{basehref}, qr{^https?://example.com/wiki/$});
495 like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
496 like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
497 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
498
499 # when accessed via a different hostname, links stay on that host
500 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
501         $ENV{REQUEST_METHOD} = 'GET';
502         $ENV{SERVER_PORT} = '443';
503         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
504         $ENV{QUERY_STRING} = 'do=prefs';
505         $ENV{HTTP_HOST} = 'staging.example.net';
506         $ENV{HTTPS} = 'on';
507 });
508 %bits = parse_cgi_content($content);
509 # because the static and dynamic stuff is on the same server, we assume that
510 # both are also on the staging server
511 like($bits{basehref}, qr{^https://staging.example.net/wiki/$});
512 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
513 like($bits{tophref}, qr{^(?:(?:(?:https:)?//staging.example.net)?/wiki|\.)/$});
514 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:staging\.example\.net|example\.com))?/cgi-bin/ikiwiki.cgi$});
515 TODO: {
516 local $TODO = "this should really point back to itself but currently points to example.com";
517 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
518 }
519
520 # previewing a page
521 $in = 'do=edit&page=a/b/c&Preview';
522 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
523         $ENV{REQUEST_METHOD} = 'POST';
524         $ENV{SERVER_PORT} = '443';
525         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
526         $ENV{HTTP_HOST} = 'example.com';
527         $ENV{CONTENT_LENGTH} = length $in;
528         $ENV{HTTPS} = 'on';
529 });
530 %bits = parse_cgi_content($content);
531 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
532 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
533 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
534 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
535
536 write_setup_file(
537         html5   => 1,
538         url     => "http://example.com/wiki/",
539         cgiurl  => "https://example.com/cgi-bin/ikiwiki.cgi",
540 );
541 thoroughly_rebuild();
542 check_cgi_mode_bits();
543 # url and cgiurl are on the same host but different schemes
544 check_generated_content(qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
545
546 # when accessed via HTTPS, links are secure (to avoid mixed-content)
547 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
548         $ENV{REQUEST_METHOD} = 'GET';
549         $ENV{SERVER_PORT} = '443';
550         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
551         $ENV{QUERY_STRING} = 'do=prefs';
552         $ENV{HTTP_HOST} = 'example.com';
553         $ENV{HTTPS} = 'on';
554 });
555 %bits = parse_cgi_content($content);
556 is($bits{basehref}, "/wiki/");
557 is($bits{stylehref}, "/wiki/style.css");
558 is($bits{tophref}, "/wiki/");
559 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
560
561 # when not accessed via HTTPS, ???
562 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
563         $ENV{REQUEST_METHOD} = 'GET';
564         $ENV{SERVER_PORT} = '80';
565         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
566         $ENV{QUERY_STRING} = 'do=prefs';
567         $ENV{HTTP_HOST} = 'example.com';
568 });
569 %bits = parse_cgi_content($content);
570 like($bits{basehref}, qr{^(?:https?://example.com)?/wiki/$});
571 like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
572 like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
573 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
574
575 # when accessed via a different hostname, links stay on that host
576 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
577         $ENV{REQUEST_METHOD} = 'GET';
578         $ENV{SERVER_PORT} = '443';
579         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
580         $ENV{QUERY_STRING} = 'do=prefs';
581         $ENV{HTTP_HOST} = 'staging.example.net';
582         $ENV{HTTPS} = 'on';
583 });
584 %bits = parse_cgi_content($content);
585 # because the static and dynamic stuff is on the same server, we assume that
586 # both are also on the staging server
587 is($bits{basehref}, "/wiki/");
588 is($bits{stylehref}, "/wiki/style.css");
589 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
590 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:example\.com|staging\.example\.net))?/cgi-bin/ikiwiki.cgi$});
591 TODO: {
592 local $TODO = "this should really point back to itself but currently points to example.com";
593 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
594 }
595
596 # previewing a page
597 $in = 'do=edit&page=a/b/c&Preview';
598 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
599         $ENV{REQUEST_METHOD} = 'POST';
600         $ENV{SERVER_PORT} = '443';
601         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
602         $ENV{HTTP_HOST} = 'example.com';
603         $ENV{CONTENT_LENGTH} = length $in;
604         $ENV{HTTPS} = 'on';
605 });
606 %bits = parse_cgi_content($content);
607 is($bits{basehref}, "/wiki/a/b/c/");
608 is($bits{stylehref}, "/wiki/style.css");
609 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
610 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
611
612 # Deliberately not testing https static content with http cgiurl,
613 # because that makes remarkably little sense.
614
615 #######################################################################
616 # site 5: w3mmode, as documented in [[w3mmode]]
617
618 write_setup_file(
619         html5   => 0, 
620         url     => undef,
621         cgiurl  => "ikiwiki.cgi",
622         w3mmode => 1,
623 );
624 thoroughly_rebuild();
625 check_cgi_mode_bits();
626 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
627 check_generated_content(qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
628
629 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
630         $ENV{REQUEST_METHOD} = 'GET';
631         $ENV{PATH_INFO} = '/ikiwiki.cgi';
632         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
633         $ENV{QUERY_STRING} = 'do=prefs';
634 });
635 %bits = parse_cgi_content($content);
636 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
637 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
638 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
639 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
640
641 write_setup_file(
642         html5   => 1,
643         url     => undef,
644         cgiurl  => "ikiwiki.cgi",
645         w3mmode => 1,
646 );
647 thoroughly_rebuild();
648 check_cgi_mode_bits();
649 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
650 check_generated_content(qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
651
652 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
653         $ENV{REQUEST_METHOD} = 'GET';
654         $ENV{PATH_INFO} = '/ikiwiki.cgi';
655         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
656         $ENV{QUERY_STRING} = 'do=prefs';
657 });
658 %bits = parse_cgi_content($content);
659 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
660 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
661 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
662 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
663
664 #######################################################################
665 # site 6: we're behind a reverse-proxy
666
667 write_setup_file(
668         html5   => 0,
669         url     => "https://example.com/wiki/",
670         cgiurl  => "https://example.com/cgi-bin/ikiwiki.cgi",
671         reverse_proxy => 1,
672 );
673 thoroughly_rebuild();
674 check_cgi_mode_bits();
675 # url and cgiurl are on the same host so the cgiurl is host-relative
676 check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
677
678 # because we are behind a reverse-proxy we must assume that
679 # we're being accessed by the configured cgiurl
680 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
681         $ENV{REQUEST_METHOD} = 'GET';
682         $ENV{SERVER_PORT} = '80';
683         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
684         $ENV{QUERY_STRING} = 'do=prefs';
685         $ENV{HTTP_HOST} = 'localhost';
686 });
687 %bits = parse_cgi_content($content);
688 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
689 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
690 is($bits{basehref}, "https://example.com/wiki/");
691 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
692
693 # previewing a page
694 $in = 'do=edit&page=a/b/c&Preview';
695 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
696         $ENV{REQUEST_METHOD} = 'POST';
697         $ENV{SERVER_PORT} = '80';
698         $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
699         $ENV{HTTP_HOST} = 'localhost';
700         $ENV{CONTENT_LENGTH} = length $in;
701 });
702 %bits = parse_cgi_content($content);
703 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
704 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
705 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
706 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
707
708 # not testing html5: 1 because it would be the same as site 1 -
709 # the reverse_proxy config option is unnecessary under html5
710
711 done_testing;