6 plan(skip_all => "IPC::Run not available")
19 # Black-box (ish) test for relative linking between CGI and static content
22 my ($content, $in, %bits);
24 sub parse_cgi_content {
26 if ($content =~ qr{<base href="([^"]+)" */>}) {
29 if ($content =~ qr{href="([^"]+/style.css)"}) {
30 $bits{stylehref} = $1;
32 if ($content =~ qr{class="parentlinks">\s+<a href="([^"]+)">this is the name of my wiki</a>/}s) {
35 if ($content =~ qr{<a[^>]+href="([^"]+)\?do=prefs"}) {
41 ok(! system("make -s ikiwiki.out"));
42 ok(! system("rm -rf t/tmp"));
43 ok(! system("mkdir t/tmp"));
49 writefile($name, "t/tmp/in", $content);
50 ok(utime(333333333, 333333333, "t/tmp/in/$name"));
53 write_old_file("a.mdwn", "A");
54 write_old_file("a/b.mdwn", "B");
55 write_old_file("a/b/c.mdwn",
59 write_old_file("a/d.mdwn", "D");
60 write_old_file("a/d/e.mdwn", "E");
62 sub write_setup_file {
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}" : "";
68 writefile("test.setup", "t/tmp", <<EOF
69 # IkiWiki::Setup::Yaml - YAML formatted setup file
70 wikiname: this is the name of my wiki
73 templatedir: templates
77 cgi_wrapper: t/tmp/ikiwiki.cgi
80 # make it easier to test previewing
85 ENV: { 'PERL5LIB': 'blib/lib:blib/arch' }
90 sub thoroughly_rebuild {
91 ok(unlink("t/tmp/ikiwiki.cgi") || $!{ENOENT});
92 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
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);
102 #######################################################################
103 # site 1: a perfectly ordinary ikiwiki
107 url => "http://example.com/wiki/",
108 cgiurl => "http://example.com/cgi-bin/ikiwiki.cgi",
110 thoroughly_rebuild();
111 check_cgi_mode_bits();
113 ok(-e "t/tmp/out/a/b/c/index.html");
114 $content = readfile("t/tmp/out/a/b/c/index.html");
115 # no <base> on static HTML
116 unlike($content, qr{<base\W});
117 # url and cgiurl are on the same host so the cgiurl is host-relative
118 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
119 # cross-links between static pages are relative
120 like($content, qr{<li>A: <a href="../../">a</a></li>});
121 like($content, qr{<li>B: <a href="../">b</a></li>});
122 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
124 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
125 $ENV{REQUEST_METHOD} = 'GET';
126 $ENV{SERVER_PORT} = '80';
127 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
128 $ENV{QUERY_STRING} = 'do=prefs';
129 $ENV{HTTP_HOST} = 'example.com';
131 %bits = parse_cgi_content($content);
132 is($bits{basehref}, "http://example.com/wiki/");
133 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
134 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
135 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
137 # when accessed via HTTPS, links are secure
138 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
139 $ENV{REQUEST_METHOD} = 'GET';
140 $ENV{SERVER_PORT} = '443';
141 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
142 $ENV{QUERY_STRING} = 'do=prefs';
143 $ENV{HTTP_HOST} = 'example.com';
146 %bits = parse_cgi_content($content);
147 is($bits{basehref}, "https://example.com/wiki/");
148 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
149 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
150 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
152 # when accessed via a different hostname, links stay on that host
153 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
154 $ENV{REQUEST_METHOD} = 'GET';
155 $ENV{SERVER_PORT} = '80';
156 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
157 $ENV{QUERY_STRING} = 'do=prefs';
158 $ENV{HTTP_HOST} = 'staging.example.net';
160 %bits = parse_cgi_content($content);
161 is($bits{basehref}, "http://staging.example.net/wiki/");
162 like($bits{stylehref}, qr{^(?:(?:http:)?//staging.example.net)?/wiki/style.css$});
163 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
164 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
167 $in = 'do=edit&page=a/b/c&Preview';
168 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
169 $ENV{REQUEST_METHOD} = 'POST';
170 $ENV{SERVER_PORT} = '80';
171 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
172 $ENV{HTTP_HOST} = 'example.com';
173 $ENV{CONTENT_LENGTH} = length $in;
175 %bits = parse_cgi_content($content);
176 is($bits{basehref}, "http://example.com/wiki/a/b/c/");
177 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
178 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
179 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
181 # in html5, the <base> is allowed to be relative, and we take full
185 url => "http://example.com/wiki/",
186 cgiurl => "http://example.com/cgi-bin/ikiwiki.cgi",
188 thoroughly_rebuild();
189 check_cgi_mode_bits();
191 ok(-e "t/tmp/out/a/b/c/index.html");
192 $content = readfile("t/tmp/out/a/b/c/index.html");
193 # no <base> on static HTML
194 unlike($content, qr{<base\W});
195 # url and cgiurl are on the same host so the cgiurl is host-relative
196 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
197 # cross-links between static pages are relative
198 like($content, qr{<li>A: <a href="../../">a</a></li>});
199 like($content, qr{<li>B: <a href="../">b</a></li>});
200 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
202 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
203 $ENV{REQUEST_METHOD} = 'GET';
204 $ENV{SERVER_PORT} = '80';
205 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
206 $ENV{QUERY_STRING} = 'do=prefs';
207 $ENV{HTTP_HOST} = 'example.com';
209 %bits = parse_cgi_content($content);
210 is($bits{basehref}, "/wiki/");
211 is($bits{stylehref}, "/wiki/style.css");
212 is($bits{tophref}, "/wiki/");
213 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
215 # when accessed via HTTPS, links are secure - this is easy because under
216 # html5 they're independent of the URL at which the CGI was accessed
217 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
218 $ENV{REQUEST_METHOD} = 'GET';
219 $ENV{SERVER_PORT} = '443';
220 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
221 $ENV{QUERY_STRING} = 'do=prefs';
222 $ENV{HTTP_HOST} = 'example.com';
225 %bits = parse_cgi_content($content);
226 is($bits{basehref}, "/wiki/");
227 is($bits{stylehref}, "/wiki/style.css");
228 is($bits{tophref}, "/wiki/");
229 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
231 # when accessed via a different hostname, links stay on that host -
232 # this is really easy in html5 because we can use relative URLs
233 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
234 $ENV{REQUEST_METHOD} = 'GET';
235 $ENV{SERVER_PORT} = '80';
236 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
237 $ENV{QUERY_STRING} = 'do=prefs';
238 $ENV{HTTP_HOST} = 'staging.example.net';
240 %bits = parse_cgi_content($content);
241 is($bits{basehref}, "/wiki/");
242 is($bits{stylehref}, "/wiki/style.css");
243 is($bits{tophref}, "/wiki/");
244 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
247 $in = 'do=edit&page=a/b/c&Preview';
248 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
249 $ENV{REQUEST_METHOD} = 'POST';
250 $ENV{SERVER_PORT} = '80';
251 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
252 $ENV{HTTP_HOST} = 'example.com';
253 $ENV{CONTENT_LENGTH} = length $in;
255 %bits = parse_cgi_content($content);
256 is($bits{basehref}, "/wiki/a/b/c/");
257 is($bits{stylehref}, "/wiki/style.css");
258 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
259 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
261 #######################################################################
262 # site 2: static content and CGI are on different servers
266 url => "http://static.example.com/",
267 cgiurl => "http://cgi.example.com/ikiwiki.cgi",
269 thoroughly_rebuild();
270 check_cgi_mode_bits();
272 ok(-e "t/tmp/out/a/b/c/index.html");
273 $content = readfile("t/tmp/out/a/b/c/index.html");
274 # no <base> on static HTML
275 unlike($content, qr{<base\W});
276 # url and cgiurl are not on the same host so the cgiurl has to be
277 # protocol-relative or absolute
278 like($content, qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
279 # cross-links between static pages are still relative
280 like($content, qr{<li>A: <a href="../../">a</a></li>});
281 like($content, qr{<li>B: <a href="../">b</a></li>});
282 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
284 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
285 $ENV{REQUEST_METHOD} = 'GET';
286 $ENV{SERVER_PORT} = '80';
287 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
288 $ENV{QUERY_STRING} = 'do=prefs';
289 $ENV{HTTP_HOST} = 'cgi.example.com';
291 %bits = parse_cgi_content($content);
292 like($bits{basehref}, qr{^http://static.example.com/$});
293 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com)?/style.css$});
294 like($bits{tophref}, qr{^(?:http:)?//static.example.com/$});
295 like($bits{cgihref}, qr{^(?:(?:http:)?//cgi.example.com)?/ikiwiki.cgi$});
297 # when accessed via HTTPS, links are secure
298 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
299 $ENV{REQUEST_METHOD} = 'GET';
300 $ENV{SERVER_PORT} = '443';
301 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
302 $ENV{QUERY_STRING} = 'do=prefs';
303 $ENV{HTTP_HOST} = 'cgi.example.com';
306 %bits = parse_cgi_content($content);
307 like($bits{basehref}, qr{^https://static.example.com/$});
308 like($bits{stylehref}, qr{^(?:(?:https:)?//static.example.com)?/style.css$});
309 like($bits{tophref}, qr{^(?:https:)?//static.example.com/$});
310 like($bits{cgihref}, qr{^(?:(?:https:)?//cgi.example.com)?/ikiwiki.cgi$});
312 # when accessed via a different hostname, links to the CGI (only) should
314 $in = 'do=edit&page=a/b/c&Preview';
315 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
316 $ENV{REQUEST_METHOD} = 'POST';
317 $ENV{SERVER_PORT} = '80';
318 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
319 $ENV{HTTP_HOST} = 'staging.example.net';
320 $ENV{CONTENT_LENGTH} = length $in;
322 %bits = parse_cgi_content($content);
323 like($bits{basehref}, qr{^http://static.example.com/a/b/c/$});
324 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/style.css$});
325 like($bits{tophref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/$});
326 like($bits{cgihref}, qr{^(?:(?:http:)?//(?:staging\.example\.net|cgi\.example\.com))?/ikiwiki.cgi$});
328 local $TODO = "use self-referential CGI URL?";
329 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/ikiwiki.cgi$});
334 url => "http://static.example.com/",
335 cgiurl => "http://cgi.example.com/ikiwiki.cgi",
337 thoroughly_rebuild();
338 check_cgi_mode_bits();
340 ok(-e "t/tmp/out/a/b/c/index.html");
341 $content = readfile("t/tmp/out/a/b/c/index.html");
342 # no <base> on static HTML
343 unlike($content, qr{<base\W});
344 # url and cgiurl are not on the same host so the cgiurl has to be
345 # protocol-relative or absolute
346 like($content, qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
347 # cross-links between static pages are still relative
348 like($content, qr{<li>A: <a href="../../">a</a></li>});
349 like($content, qr{<li>B: <a href="../">b</a></li>});
350 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
352 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
353 $ENV{REQUEST_METHOD} = 'GET';
354 $ENV{SERVER_PORT} = '80';
355 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
356 $ENV{QUERY_STRING} = 'do=prefs';
357 $ENV{HTTP_HOST} = 'cgi.example.com';
359 %bits = parse_cgi_content($content);
360 is($bits{basehref}, "//static.example.com/");
361 is($bits{stylehref}, "//static.example.com/style.css");
362 is($bits{tophref}, "//static.example.com/");
363 is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
365 # when accessed via HTTPS, links are secure - in fact they're exactly the
366 # same as when accessed via HTTP
367 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
368 $ENV{REQUEST_METHOD} = 'GET';
369 $ENV{SERVER_PORT} = '443';
370 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
371 $ENV{QUERY_STRING} = 'do=prefs';
372 $ENV{HTTP_HOST} = 'cgi.example.com';
375 %bits = parse_cgi_content($content);
376 is($bits{basehref}, "//static.example.com/");
377 is($bits{stylehref}, "//static.example.com/style.css");
378 is($bits{tophref}, "//static.example.com/");
379 is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
381 # when accessed via a different hostname, links to the CGI (only) should
383 $in = 'do=edit&page=a/b/c&Preview';
384 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
385 $ENV{REQUEST_METHOD} = 'POST';
386 $ENV{SERVER_PORT} = '80';
387 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
388 $ENV{HTTP_HOST} = 'staging.example.net';
389 $ENV{CONTENT_LENGTH} = length $in;
391 %bits = parse_cgi_content($content);
392 is($bits{basehref}, "//static.example.com/a/b/c/");
393 is($bits{stylehref}, "//static.example.com/style.css");
394 is($bits{tophref}, "../../../");
395 like($bits{cgihref}, qr{//(?:staging\.example\.net|cgi\.example\.com)/ikiwiki\.cgi});
397 local $TODO = "use self-referential CGI URL maybe?";
398 is($bits{cgihref}, "//staging.example.net/ikiwiki.cgi");
401 #######################################################################
402 # site 3: we specifically want everything to be secure
406 url => "https://example.com/wiki/",
407 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
409 thoroughly_rebuild();
410 check_cgi_mode_bits();
412 ok(-e "t/tmp/out/a/b/c/index.html");
413 $content = readfile("t/tmp/out/a/b/c/index.html");
414 # no <base> on static HTML
415 unlike($content, qr{<base\W});
416 # url and cgiurl are on the same host so the cgiurl is host-relative
417 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
418 # cross-links between static pages are relative
419 like($content, qr{<li>A: <a href="../../">a</a></li>});
420 like($content, qr{<li>B: <a href="../">b</a></li>});
421 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
423 # when accessed via HTTPS, links are secure
424 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
425 $ENV{REQUEST_METHOD} = 'GET';
426 $ENV{SERVER_PORT} = '443';
427 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
428 $ENV{QUERY_STRING} = 'do=prefs';
429 $ENV{HTTP_HOST} = 'example.com';
432 %bits = parse_cgi_content($content);
433 is($bits{basehref}, "https://example.com/wiki/");
434 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
435 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
436 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
438 # when not accessed via HTTPS, links should still be secure
439 # (but if this happens, that's a sign of web server misconfiguration)
440 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
441 $ENV{REQUEST_METHOD} = 'GET';
442 $ENV{SERVER_PORT} = '80';
443 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
444 $ENV{QUERY_STRING} = 'do=prefs';
445 $ENV{HTTP_HOST} = 'example.com';
447 %bits = parse_cgi_content($content);
448 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
450 local $TODO = "treat https in configured url, cgiurl as required?";
451 is($bits{basehref}, "https://example.com/wiki/");
452 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
454 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
456 # when accessed via a different hostname, links stay on that host
457 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
458 $ENV{REQUEST_METHOD} = 'GET';
459 $ENV{SERVER_PORT} = '443';
460 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
461 $ENV{QUERY_STRING} = 'do=prefs';
462 $ENV{HTTP_HOST} = 'staging.example.net';
465 %bits = parse_cgi_content($content);
466 is($bits{basehref}, "https://staging.example.net/wiki/");
467 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
468 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
469 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
472 $in = 'do=edit&page=a/b/c&Preview';
473 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
474 $ENV{REQUEST_METHOD} = 'POST';
475 $ENV{SERVER_PORT} = '443';
476 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
477 $ENV{HTTP_HOST} = 'example.com';
478 $ENV{CONTENT_LENGTH} = length $in;
481 %bits = parse_cgi_content($content);
482 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
483 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
484 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
485 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
487 # not testing html5: 0 here because that ends up identical to site 1
489 #######################################################################
490 # site 4 (NetBSD wiki): CGI is secure, static content doesn't have to be
494 url => "http://example.com/wiki/",
495 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
497 thoroughly_rebuild();
498 check_cgi_mode_bits();
500 ok(-e "t/tmp/out/a/b/c/index.html");
501 $content = readfile("t/tmp/out/a/b/c/index.html");
502 # no <base> on static HTML
503 unlike($content, qr{<base\W});
504 # url and cgiurl are on the same host but different schemes
505 like($content, qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
506 # cross-links between static pages are relative
507 like($content, qr{<li>A: <a href="../../">a</a></li>});
508 like($content, qr{<li>B: <a href="../">b</a></li>});
509 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
511 # when accessed via HTTPS, links are secure (to avoid mixed-content)
512 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
513 $ENV{REQUEST_METHOD} = 'GET';
514 $ENV{SERVER_PORT} = '443';
515 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
516 $ENV{QUERY_STRING} = 'do=prefs';
517 $ENV{HTTP_HOST} = 'example.com';
520 %bits = parse_cgi_content($content);
521 is($bits{basehref}, "https://example.com/wiki/");
522 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
523 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
524 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
526 # when not accessed via HTTPS, ???
527 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
528 $ENV{REQUEST_METHOD} = 'GET';
529 $ENV{SERVER_PORT} = '80';
530 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
531 $ENV{QUERY_STRING} = 'do=prefs';
532 $ENV{HTTP_HOST} = 'example.com';
534 %bits = parse_cgi_content($content);
535 like($bits{basehref}, qr{^https?://example.com/wiki/$});
536 like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
537 like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
538 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
540 # when accessed via a different hostname, links stay on that host
541 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
542 $ENV{REQUEST_METHOD} = 'GET';
543 $ENV{SERVER_PORT} = '443';
544 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
545 $ENV{QUERY_STRING} = 'do=prefs';
546 $ENV{HTTP_HOST} = 'staging.example.net';
549 %bits = parse_cgi_content($content);
550 # because the static and dynamic stuff is on the same server, we assume that
551 # both are also on the staging server
552 like($bits{basehref}, qr{^https://staging.example.net/wiki/$});
553 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
554 like($bits{tophref}, qr{^(?:(?:(?:https:)?//staging.example.net)?/wiki|\.)/$});
555 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:staging\.example\.net|example\.com))?/cgi-bin/ikiwiki.cgi$});
557 local $TODO = "this should really point back to itself but currently points to example.com";
558 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
562 $in = 'do=edit&page=a/b/c&Preview';
563 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
564 $ENV{REQUEST_METHOD} = 'POST';
565 $ENV{SERVER_PORT} = '443';
566 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
567 $ENV{HTTP_HOST} = 'example.com';
568 $ENV{CONTENT_LENGTH} = length $in;
571 %bits = parse_cgi_content($content);
572 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
573 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
574 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
575 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
579 url => "http://example.com/wiki/",
580 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
582 thoroughly_rebuild();
583 check_cgi_mode_bits();
585 ok(-e "t/tmp/out/a/b/c/index.html");
586 $content = readfile("t/tmp/out/a/b/c/index.html");
587 # no <base> on static HTML
588 unlike($content, qr{<base\W});
589 # url and cgiurl are on the same host but different schemes
590 like($content, qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
591 # cross-links between static pages are relative
592 like($content, qr{<li>A: <a href="../../">a</a></li>});
593 like($content, qr{<li>B: <a href="../">b</a></li>});
594 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
596 # when accessed via HTTPS, links are secure (to avoid mixed-content)
597 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
598 $ENV{REQUEST_METHOD} = 'GET';
599 $ENV{SERVER_PORT} = '443';
600 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
601 $ENV{QUERY_STRING} = 'do=prefs';
602 $ENV{HTTP_HOST} = 'example.com';
605 %bits = parse_cgi_content($content);
606 is($bits{basehref}, "/wiki/");
607 is($bits{stylehref}, "/wiki/style.css");
608 is($bits{tophref}, "/wiki/");
609 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
611 # when not accessed via HTTPS, ???
612 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
613 $ENV{REQUEST_METHOD} = 'GET';
614 $ENV{SERVER_PORT} = '80';
615 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
616 $ENV{QUERY_STRING} = 'do=prefs';
617 $ENV{HTTP_HOST} = 'example.com';
619 %bits = parse_cgi_content($content);
620 like($bits{basehref}, qr{^(?:https?://example.com)?/wiki/$});
621 like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
622 like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
623 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
625 # when accessed via a different hostname, links stay on that host
626 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
627 $ENV{REQUEST_METHOD} = 'GET';
628 $ENV{SERVER_PORT} = '443';
629 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
630 $ENV{QUERY_STRING} = 'do=prefs';
631 $ENV{HTTP_HOST} = 'staging.example.net';
634 %bits = parse_cgi_content($content);
635 # because the static and dynamic stuff is on the same server, we assume that
636 # both are also on the staging server
637 is($bits{basehref}, "/wiki/");
638 is($bits{stylehref}, "/wiki/style.css");
639 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
640 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:example\.com|staging\.example\.net))?/cgi-bin/ikiwiki.cgi$});
642 local $TODO = "this should really point back to itself but currently points to example.com";
643 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
647 $in = 'do=edit&page=a/b/c&Preview';
648 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
649 $ENV{REQUEST_METHOD} = 'POST';
650 $ENV{SERVER_PORT} = '443';
651 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
652 $ENV{HTTP_HOST} = 'example.com';
653 $ENV{CONTENT_LENGTH} = length $in;
656 %bits = parse_cgi_content($content);
657 is($bits{basehref}, "/wiki/a/b/c/");
658 is($bits{stylehref}, "/wiki/style.css");
659 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
660 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
662 # Deliberately not testing https static content with http cgiurl,
663 # because that makes remarkably little sense.
665 #######################################################################
666 # site 5: w3mmode, as documented in [[w3mmode]]
671 cgiurl => "ikiwiki.cgi",
674 thoroughly_rebuild();
675 check_cgi_mode_bits();
677 ok(-e "t/tmp/out/a/b/c/index.html");
678 $content = readfile("t/tmp/out/a/b/c/index.html");
679 # no <base> on static HTML
680 unlike($content, qr{<base\W});
681 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
682 like($content, qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
683 # cross-links between static pages are still relative
684 like($content, qr{<li>A: <a href="../../">a</a></li>});
685 like($content, qr{<li>B: <a href="../">b</a></li>});
686 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
688 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
689 $ENV{REQUEST_METHOD} = 'GET';
690 $ENV{PATH_INFO} = '/ikiwiki.cgi';
691 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
692 $ENV{QUERY_STRING} = 'do=prefs';
694 %bits = parse_cgi_content($content);
695 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
696 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
697 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
698 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
703 cgiurl => "ikiwiki.cgi",
706 thoroughly_rebuild();
707 check_cgi_mode_bits();
709 ok(-e "t/tmp/out/a/b/c/index.html");
710 $content = readfile("t/tmp/out/a/b/c/index.html");
711 # no <base> on static HTML
712 unlike($content, qr{<base\W});
713 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
714 like($content, qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
715 # cross-links between static pages are still relative
716 like($content, qr{<li>A: <a href="../../">a</a></li>});
717 like($content, qr{<li>B: <a href="../">b</a></li>});
718 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
720 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
721 $ENV{REQUEST_METHOD} = 'GET';
722 $ENV{PATH_INFO} = '/ikiwiki.cgi';
723 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
724 $ENV{QUERY_STRING} = 'do=prefs';
726 %bits = parse_cgi_content($content);
727 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
728 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
729 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
730 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
732 #######################################################################
733 # site 6: we're behind a reverse-proxy
737 url => "https://example.com/wiki/",
738 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
741 thoroughly_rebuild();
742 check_cgi_mode_bits();
744 ok(-e "t/tmp/out/a/b/c/index.html");
745 $content = readfile("t/tmp/out/a/b/c/index.html");
746 # no <base> on static HTML
747 unlike($content, qr{<base\W});
748 # url and cgiurl are on the same host so the cgiurl is host-relative
749 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
750 # cross-links between static pages are relative
751 like($content, qr{<li>A: <a href="../../">a</a></li>});
752 like($content, qr{<li>B: <a href="../">b</a></li>});
753 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
755 # because we are behind a reverse-proxy we must assume that
756 # we're being accessed by the configured cgiurl
757 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
758 $ENV{REQUEST_METHOD} = 'GET';
759 $ENV{SERVER_PORT} = '80';
760 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
761 $ENV{QUERY_STRING} = 'do=prefs';
762 $ENV{HTTP_HOST} = 'localhost';
764 %bits = parse_cgi_content($content);
765 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
766 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
767 is($bits{basehref}, "https://example.com/wiki/");
768 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
771 $in = 'do=edit&page=a/b/c&Preview';
772 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
773 $ENV{REQUEST_METHOD} = 'POST';
774 $ENV{SERVER_PORT} = '80';
775 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
776 $ENV{HTTP_HOST} = 'localhost';
777 $ENV{CONTENT_LENGTH} = length $in;
779 %bits = parse_cgi_content($content);
780 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
781 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
782 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
783 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
785 # not testing html5: 1 because it would be the same as site 1 -
786 # the reverse_proxy config option is unnecessary under html5