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 #######################################################################
96 # site 1: a perfectly ordinary ikiwiki
100 url => "http://example.com/wiki/",
101 cgiurl => "http://example.com/cgi-bin/ikiwiki.cgi",
103 thoroughly_rebuild();
105 # CGI wrapper should be exactly the requested mode
106 my (undef, undef, $mode, undef, undef,
107 undef, undef, undef, undef, undef,
108 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
109 is($mode & 07777, 0754);
111 ok(-e "t/tmp/out/a/b/c/index.html");
112 $content = readfile("t/tmp/out/a/b/c/index.html");
113 # no <base> on static HTML
114 unlike($content, qr{<base\W});
115 # url and cgiurl are on the same host so the cgiurl is host-relative
116 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
117 # cross-links between static pages are relative
118 like($content, qr{<li>A: <a href="../../">a</a></li>});
119 like($content, qr{<li>B: <a href="../">b</a></li>});
120 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
122 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
123 $ENV{REQUEST_METHOD} = 'GET';
124 $ENV{SERVER_PORT} = '80';
125 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
126 $ENV{QUERY_STRING} = 'do=prefs';
127 $ENV{HTTP_HOST} = 'example.com';
129 %bits = parse_cgi_content($content);
130 is($bits{basehref}, "http://example.com/wiki/");
131 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
132 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
133 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
135 # when accessed via HTTPS, links are secure
136 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
137 $ENV{REQUEST_METHOD} = 'GET';
138 $ENV{SERVER_PORT} = '443';
139 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
140 $ENV{QUERY_STRING} = 'do=prefs';
141 $ENV{HTTP_HOST} = 'example.com';
144 %bits = parse_cgi_content($content);
145 is($bits{basehref}, "https://example.com/wiki/");
146 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
147 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
148 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
150 # when accessed via a different hostname, links stay on that host
151 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
152 $ENV{REQUEST_METHOD} = 'GET';
153 $ENV{SERVER_PORT} = '80';
154 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
155 $ENV{QUERY_STRING} = 'do=prefs';
156 $ENV{HTTP_HOST} = 'staging.example.net';
158 %bits = parse_cgi_content($content);
159 is($bits{basehref}, "http://staging.example.net/wiki/");
160 like($bits{stylehref}, qr{^(?:(?:http:)?//staging.example.net)?/wiki/style.css$});
161 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
162 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
165 $in = 'do=edit&page=a/b/c&Preview';
166 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
167 $ENV{REQUEST_METHOD} = 'POST';
168 $ENV{SERVER_PORT} = '80';
169 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
170 $ENV{HTTP_HOST} = 'example.com';
171 $ENV{CONTENT_LENGTH} = length $in;
173 %bits = parse_cgi_content($content);
174 is($bits{basehref}, "http://example.com/wiki/a/b/c/");
175 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
176 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
177 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
179 # in html5, the <base> is allowed to be relative, and we take full
183 url => "http://example.com/wiki/",
184 cgiurl => "http://example.com/cgi-bin/ikiwiki.cgi",
186 thoroughly_rebuild();
188 # CGI wrapper should be exactly the requested mode
189 (undef, undef, $mode, undef, undef,
190 undef, undef, undef, undef, undef,
191 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
192 is($mode & 07777, 0754);
194 ok(-e "t/tmp/out/a/b/c/index.html");
195 $content = readfile("t/tmp/out/a/b/c/index.html");
196 # no <base> on static HTML
197 unlike($content, qr{<base\W});
198 # url and cgiurl are on the same host so the cgiurl is host-relative
199 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
200 # cross-links between static pages are relative
201 like($content, qr{<li>A: <a href="../../">a</a></li>});
202 like($content, qr{<li>B: <a href="../">b</a></li>});
203 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
205 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
206 $ENV{REQUEST_METHOD} = 'GET';
207 $ENV{SERVER_PORT} = '80';
208 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
209 $ENV{QUERY_STRING} = 'do=prefs';
210 $ENV{HTTP_HOST} = 'example.com';
212 %bits = parse_cgi_content($content);
213 is($bits{basehref}, "/wiki/");
214 is($bits{stylehref}, "/wiki/style.css");
215 is($bits{tophref}, "/wiki/");
216 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
218 # when accessed via HTTPS, links are secure - this is easy because under
219 # html5 they're independent of the URL at which the CGI was accessed
220 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
221 $ENV{REQUEST_METHOD} = 'GET';
222 $ENV{SERVER_PORT} = '443';
223 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
224 $ENV{QUERY_STRING} = 'do=prefs';
225 $ENV{HTTP_HOST} = 'example.com';
228 %bits = parse_cgi_content($content);
229 is($bits{basehref}, "/wiki/");
230 is($bits{stylehref}, "/wiki/style.css");
231 is($bits{tophref}, "/wiki/");
232 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
234 # when accessed via a different hostname, links stay on that host -
235 # this is really easy in html5 because we can use relative URLs
236 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
237 $ENV{REQUEST_METHOD} = 'GET';
238 $ENV{SERVER_PORT} = '80';
239 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
240 $ENV{QUERY_STRING} = 'do=prefs';
241 $ENV{HTTP_HOST} = 'staging.example.net';
243 %bits = parse_cgi_content($content);
244 is($bits{basehref}, "/wiki/");
245 is($bits{stylehref}, "/wiki/style.css");
246 is($bits{tophref}, "/wiki/");
247 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
250 $in = 'do=edit&page=a/b/c&Preview';
251 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
252 $ENV{REQUEST_METHOD} = 'POST';
253 $ENV{SERVER_PORT} = '80';
254 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
255 $ENV{HTTP_HOST} = 'example.com';
256 $ENV{CONTENT_LENGTH} = length $in;
258 %bits = parse_cgi_content($content);
259 is($bits{basehref}, "/wiki/a/b/c/");
260 is($bits{stylehref}, "/wiki/style.css");
261 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
262 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
264 #######################################################################
265 # site 2: static content and CGI are on different servers
269 url => "http://static.example.com/",
270 cgiurl => "http://cgi.example.com/ikiwiki.cgi",
272 thoroughly_rebuild();
274 # CGI wrapper should be exactly the requested mode
275 (undef, undef, $mode, undef, undef,
276 undef, undef, undef, undef, undef,
277 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
278 is($mode & 07777, 0754);
280 ok(-e "t/tmp/out/a/b/c/index.html");
281 $content = readfile("t/tmp/out/a/b/c/index.html");
282 # no <base> on static HTML
283 unlike($content, qr{<base\W});
284 # url and cgiurl are not on the same host so the cgiurl has to be
285 # protocol-relative or absolute
286 like($content, qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
287 # cross-links between static pages are still relative
288 like($content, qr{<li>A: <a href="../../">a</a></li>});
289 like($content, qr{<li>B: <a href="../">b</a></li>});
290 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
292 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
293 $ENV{REQUEST_METHOD} = 'GET';
294 $ENV{SERVER_PORT} = '80';
295 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
296 $ENV{QUERY_STRING} = 'do=prefs';
297 $ENV{HTTP_HOST} = 'cgi.example.com';
299 %bits = parse_cgi_content($content);
300 like($bits{basehref}, qr{^http://static.example.com/$});
301 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com)?/style.css$});
302 like($bits{tophref}, qr{^(?:http:)?//static.example.com/$});
303 like($bits{cgihref}, qr{^(?:(?:http:)?//cgi.example.com)?/ikiwiki.cgi$});
305 # when accessed via HTTPS, links are secure
306 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
307 $ENV{REQUEST_METHOD} = 'GET';
308 $ENV{SERVER_PORT} = '443';
309 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
310 $ENV{QUERY_STRING} = 'do=prefs';
311 $ENV{HTTP_HOST} = 'cgi.example.com';
314 %bits = parse_cgi_content($content);
315 like($bits{basehref}, qr{^https://static.example.com/$});
316 like($bits{stylehref}, qr{^(?:(?:https:)?//static.example.com)?/style.css$});
317 like($bits{tophref}, qr{^(?:https:)?//static.example.com/$});
318 like($bits{cgihref}, qr{^(?:(?:https:)?//cgi.example.com)?/ikiwiki.cgi$});
320 # when accessed via a different hostname, links to the CGI (only) should
322 $in = 'do=edit&page=a/b/c&Preview';
323 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
324 $ENV{REQUEST_METHOD} = 'POST';
325 $ENV{SERVER_PORT} = '80';
326 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
327 $ENV{HTTP_HOST} = 'staging.example.net';
328 $ENV{CONTENT_LENGTH} = length $in;
330 %bits = parse_cgi_content($content);
331 like($bits{basehref}, qr{^http://static.example.com/a/b/c/$});
332 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/style.css$});
333 like($bits{tophref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/$});
334 like($bits{cgihref}, qr{^(?:(?:http:)?//(?:staging\.example\.net|cgi\.example\.com))?/ikiwiki.cgi$});
336 local $TODO = "use self-referential CGI URL?";
337 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/ikiwiki.cgi$});
342 url => "http://static.example.com/",
343 cgiurl => "http://cgi.example.com/ikiwiki.cgi",
345 thoroughly_rebuild();
347 # CGI wrapper should be exactly the requested mode
348 (undef, undef, $mode, undef, undef,
349 undef, undef, undef, undef, undef,
350 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
351 is($mode & 07777, 0754);
353 ok(-e "t/tmp/out/a/b/c/index.html");
354 $content = readfile("t/tmp/out/a/b/c/index.html");
355 # no <base> on static HTML
356 unlike($content, qr{<base\W});
357 # url and cgiurl are not on the same host so the cgiurl has to be
358 # protocol-relative or absolute
359 like($content, qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
360 # cross-links between static pages are still relative
361 like($content, qr{<li>A: <a href="../../">a</a></li>});
362 like($content, qr{<li>B: <a href="../">b</a></li>});
363 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
365 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
366 $ENV{REQUEST_METHOD} = 'GET';
367 $ENV{SERVER_PORT} = '80';
368 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
369 $ENV{QUERY_STRING} = 'do=prefs';
370 $ENV{HTTP_HOST} = 'cgi.example.com';
372 %bits = parse_cgi_content($content);
373 is($bits{basehref}, "//static.example.com/");
374 is($bits{stylehref}, "//static.example.com/style.css");
375 is($bits{tophref}, "//static.example.com/");
376 is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
378 # when accessed via HTTPS, links are secure - in fact they're exactly the
379 # same as when accessed via HTTP
380 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
381 $ENV{REQUEST_METHOD} = 'GET';
382 $ENV{SERVER_PORT} = '443';
383 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
384 $ENV{QUERY_STRING} = 'do=prefs';
385 $ENV{HTTP_HOST} = 'cgi.example.com';
388 %bits = parse_cgi_content($content);
389 is($bits{basehref}, "//static.example.com/");
390 is($bits{stylehref}, "//static.example.com/style.css");
391 is($bits{tophref}, "//static.example.com/");
392 is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
394 # when accessed via a different hostname, links to the CGI (only) should
396 $in = 'do=edit&page=a/b/c&Preview';
397 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
398 $ENV{REQUEST_METHOD} = 'POST';
399 $ENV{SERVER_PORT} = '80';
400 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
401 $ENV{HTTP_HOST} = 'staging.example.net';
402 $ENV{CONTENT_LENGTH} = length $in;
404 %bits = parse_cgi_content($content);
405 is($bits{basehref}, "//static.example.com/a/b/c/");
406 is($bits{stylehref}, "//static.example.com/style.css");
407 is($bits{tophref}, "../../../");
408 like($bits{cgihref}, qr{//(?:staging\.example\.net|cgi\.example\.com)/ikiwiki\.cgi});
410 local $TODO = "use self-referential CGI URL maybe?";
411 is($bits{cgihref}, "//staging.example.net/ikiwiki.cgi");
414 #######################################################################
415 # site 3: we specifically want everything to be secure
419 url => "https://example.com/wiki/",
420 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
422 thoroughly_rebuild();
424 # CGI wrapper should be exactly the requested mode
425 (undef, undef, $mode, undef, undef,
426 undef, undef, undef, undef, undef,
427 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
428 is($mode & 07777, 0754);
430 ok(-e "t/tmp/out/a/b/c/index.html");
431 $content = readfile("t/tmp/out/a/b/c/index.html");
432 # no <base> on static HTML
433 unlike($content, qr{<base\W});
434 # url and cgiurl are on the same host so the cgiurl is host-relative
435 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
436 # cross-links between static pages are relative
437 like($content, qr{<li>A: <a href="../../">a</a></li>});
438 like($content, qr{<li>B: <a href="../">b</a></li>});
439 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
441 # when accessed via HTTPS, links are secure
442 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
443 $ENV{REQUEST_METHOD} = 'GET';
444 $ENV{SERVER_PORT} = '443';
445 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
446 $ENV{QUERY_STRING} = 'do=prefs';
447 $ENV{HTTP_HOST} = 'example.com';
450 %bits = parse_cgi_content($content);
451 is($bits{basehref}, "https://example.com/wiki/");
452 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
453 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
454 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
456 # when not accessed via HTTPS, links should still be secure
457 # (but if this happens, that's a sign of web server misconfiguration)
458 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
459 $ENV{REQUEST_METHOD} = 'GET';
460 $ENV{SERVER_PORT} = '80';
461 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
462 $ENV{QUERY_STRING} = 'do=prefs';
463 $ENV{HTTP_HOST} = 'example.com';
465 %bits = parse_cgi_content($content);
466 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
468 local $TODO = "treat https in configured url, cgiurl as required?";
469 is($bits{basehref}, "https://example.com/wiki/");
470 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
472 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
474 # when accessed via a different hostname, links stay on that host
475 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
476 $ENV{REQUEST_METHOD} = 'GET';
477 $ENV{SERVER_PORT} = '443';
478 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
479 $ENV{QUERY_STRING} = 'do=prefs';
480 $ENV{HTTP_HOST} = 'staging.example.net';
483 %bits = parse_cgi_content($content);
484 is($bits{basehref}, "https://staging.example.net/wiki/");
485 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
486 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
487 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
490 $in = 'do=edit&page=a/b/c&Preview';
491 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
492 $ENV{REQUEST_METHOD} = 'POST';
493 $ENV{SERVER_PORT} = '443';
494 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
495 $ENV{HTTP_HOST} = 'example.com';
496 $ENV{CONTENT_LENGTH} = length $in;
499 %bits = parse_cgi_content($content);
500 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
501 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
502 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
503 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
505 # not testing html5: 0 here because that ends up identical to site 1
507 #######################################################################
508 # site 4 (NetBSD wiki): CGI is secure, static content doesn't have to be
512 url => "http://example.com/wiki/",
513 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
515 thoroughly_rebuild();
517 # CGI wrapper should be exactly the requested mode
518 (undef, undef, $mode, undef, undef,
519 undef, undef, undef, undef, undef,
520 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
521 is($mode & 07777, 0754);
523 ok(-e "t/tmp/out/a/b/c/index.html");
524 $content = readfile("t/tmp/out/a/b/c/index.html");
525 # no <base> on static HTML
526 unlike($content, qr{<base\W});
527 # url and cgiurl are on the same host but different schemes
528 like($content, qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
529 # cross-links between static pages are relative
530 like($content, qr{<li>A: <a href="../../">a</a></li>});
531 like($content, qr{<li>B: <a href="../">b</a></li>});
532 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
534 # when accessed via HTTPS, links are secure (to avoid mixed-content)
535 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
536 $ENV{REQUEST_METHOD} = 'GET';
537 $ENV{SERVER_PORT} = '443';
538 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
539 $ENV{QUERY_STRING} = 'do=prefs';
540 $ENV{HTTP_HOST} = 'example.com';
543 %bits = parse_cgi_content($content);
544 is($bits{basehref}, "https://example.com/wiki/");
545 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
546 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
547 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
549 # when not accessed via HTTPS, ???
550 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
551 $ENV{REQUEST_METHOD} = 'GET';
552 $ENV{SERVER_PORT} = '80';
553 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
554 $ENV{QUERY_STRING} = 'do=prefs';
555 $ENV{HTTP_HOST} = 'example.com';
557 %bits = parse_cgi_content($content);
558 like($bits{basehref}, qr{^https?://example.com/wiki/$});
559 like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
560 like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
561 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
563 # when accessed via a different hostname, links stay on that host
564 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
565 $ENV{REQUEST_METHOD} = 'GET';
566 $ENV{SERVER_PORT} = '443';
567 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
568 $ENV{QUERY_STRING} = 'do=prefs';
569 $ENV{HTTP_HOST} = 'staging.example.net';
572 %bits = parse_cgi_content($content);
573 # because the static and dynamic stuff is on the same server, we assume that
574 # both are also on the staging server
575 like($bits{basehref}, qr{^https://staging.example.net/wiki/$});
576 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
577 like($bits{tophref}, qr{^(?:(?:(?:https:)?//staging.example.net)?/wiki|\.)/$});
578 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:staging\.example\.net|example\.com))?/cgi-bin/ikiwiki.cgi$});
580 local $TODO = "this should really point back to itself but currently points to example.com";
581 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
585 $in = 'do=edit&page=a/b/c&Preview';
586 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
587 $ENV{REQUEST_METHOD} = 'POST';
588 $ENV{SERVER_PORT} = '443';
589 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
590 $ENV{HTTP_HOST} = 'example.com';
591 $ENV{CONTENT_LENGTH} = length $in;
594 %bits = parse_cgi_content($content);
595 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
596 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
597 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
598 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
602 url => "http://example.com/wiki/",
603 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
605 thoroughly_rebuild();
607 # CGI wrapper should be exactly the requested mode
608 (undef, undef, $mode, undef, undef,
609 undef, undef, undef, undef, undef,
610 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
611 is($mode & 07777, 0754);
613 ok(-e "t/tmp/out/a/b/c/index.html");
614 $content = readfile("t/tmp/out/a/b/c/index.html");
615 # no <base> on static HTML
616 unlike($content, qr{<base\W});
617 # url and cgiurl are on the same host but different schemes
618 like($content, qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
619 # cross-links between static pages are relative
620 like($content, qr{<li>A: <a href="../../">a</a></li>});
621 like($content, qr{<li>B: <a href="../">b</a></li>});
622 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
624 # when accessed via HTTPS, links are secure (to avoid mixed-content)
625 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
626 $ENV{REQUEST_METHOD} = 'GET';
627 $ENV{SERVER_PORT} = '443';
628 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
629 $ENV{QUERY_STRING} = 'do=prefs';
630 $ENV{HTTP_HOST} = 'example.com';
633 %bits = parse_cgi_content($content);
634 is($bits{basehref}, "/wiki/");
635 is($bits{stylehref}, "/wiki/style.css");
636 is($bits{tophref}, "/wiki/");
637 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
639 # when not accessed via HTTPS, ???
640 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
641 $ENV{REQUEST_METHOD} = 'GET';
642 $ENV{SERVER_PORT} = '80';
643 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
644 $ENV{QUERY_STRING} = 'do=prefs';
645 $ENV{HTTP_HOST} = 'example.com';
647 %bits = parse_cgi_content($content);
648 like($bits{basehref}, qr{^(?:https?://example.com)?/wiki/$});
649 like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
650 like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
651 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
653 # when accessed via a different hostname, links stay on that host
654 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
655 $ENV{REQUEST_METHOD} = 'GET';
656 $ENV{SERVER_PORT} = '443';
657 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
658 $ENV{QUERY_STRING} = 'do=prefs';
659 $ENV{HTTP_HOST} = 'staging.example.net';
662 %bits = parse_cgi_content($content);
663 # because the static and dynamic stuff is on the same server, we assume that
664 # both are also on the staging server
665 is($bits{basehref}, "/wiki/");
666 is($bits{stylehref}, "/wiki/style.css");
667 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
668 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:example\.com|staging\.example\.net))?/cgi-bin/ikiwiki.cgi$});
670 local $TODO = "this should really point back to itself but currently points to example.com";
671 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
675 $in = 'do=edit&page=a/b/c&Preview';
676 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
677 $ENV{REQUEST_METHOD} = 'POST';
678 $ENV{SERVER_PORT} = '443';
679 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
680 $ENV{HTTP_HOST} = 'example.com';
681 $ENV{CONTENT_LENGTH} = length $in;
684 %bits = parse_cgi_content($content);
685 is($bits{basehref}, "/wiki/a/b/c/");
686 is($bits{stylehref}, "/wiki/style.css");
687 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
688 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
690 # Deliberately not testing https static content with http cgiurl,
691 # because that makes remarkably little sense.
693 #######################################################################
694 # site 5: w3mmode, as documented in [[w3mmode]]
699 cgiurl => "ikiwiki.cgi",
702 thoroughly_rebuild();
704 # CGI wrapper should be exactly the requested mode
705 (undef, undef, $mode, undef, undef,
706 undef, undef, undef, undef, undef,
707 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
708 is($mode & 07777, 0754);
710 ok(-e "t/tmp/out/a/b/c/index.html");
711 $content = readfile("t/tmp/out/a/b/c/index.html");
712 # no <base> on static HTML
713 unlike($content, qr{<base\W});
714 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
715 like($content, qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
716 # cross-links between static pages are still relative
717 like($content, qr{<li>A: <a href="../../">a</a></li>});
718 like($content, qr{<li>B: <a href="../">b</a></li>});
719 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
721 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
722 $ENV{REQUEST_METHOD} = 'GET';
723 $ENV{PATH_INFO} = '/ikiwiki.cgi';
724 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
725 $ENV{QUERY_STRING} = 'do=prefs';
727 %bits = parse_cgi_content($content);
728 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
729 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
730 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
731 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
736 cgiurl => "ikiwiki.cgi",
739 thoroughly_rebuild();
741 # CGI wrapper should be exactly the requested mode
742 (undef, undef, $mode, undef, undef,
743 undef, undef, undef, undef, undef,
744 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
745 is($mode & 07777, 0754);
747 ok(-e "t/tmp/out/a/b/c/index.html");
748 $content = readfile("t/tmp/out/a/b/c/index.html");
749 # no <base> on static HTML
750 unlike($content, qr{<base\W});
751 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
752 like($content, qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
753 # cross-links between static pages are still relative
754 like($content, qr{<li>A: <a href="../../">a</a></li>});
755 like($content, qr{<li>B: <a href="../">b</a></li>});
756 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
758 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
759 $ENV{REQUEST_METHOD} = 'GET';
760 $ENV{PATH_INFO} = '/ikiwiki.cgi';
761 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
762 $ENV{QUERY_STRING} = 'do=prefs';
764 %bits = parse_cgi_content($content);
765 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
766 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
767 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
768 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
770 #######################################################################
771 # site 6: we're behind a reverse-proxy
775 url => "https://example.com/wiki/",
776 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
779 thoroughly_rebuild();
781 # CGI wrapper should be exactly the requested mode
782 (undef, undef, $mode, undef, undef,
783 undef, undef, undef, undef, undef,
784 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
785 is($mode & 07777, 0754);
787 ok(-e "t/tmp/out/a/b/c/index.html");
788 $content = readfile("t/tmp/out/a/b/c/index.html");
789 # no <base> on static HTML
790 unlike($content, qr{<base\W});
791 # url and cgiurl are on the same host so the cgiurl is host-relative
792 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
793 # cross-links between static pages are relative
794 like($content, qr{<li>A: <a href="../../">a</a></li>});
795 like($content, qr{<li>B: <a href="../">b</a></li>});
796 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
798 # because we are behind a reverse-proxy we must assume that
799 # we're being accessed by the configured cgiurl
800 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
801 $ENV{REQUEST_METHOD} = 'GET';
802 $ENV{SERVER_PORT} = '80';
803 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
804 $ENV{QUERY_STRING} = 'do=prefs';
805 $ENV{HTTP_HOST} = 'localhost';
807 %bits = parse_cgi_content($content);
808 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
809 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
810 is($bits{basehref}, "https://example.com/wiki/");
811 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
814 $in = 'do=edit&page=a/b/c&Preview';
815 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
816 $ENV{REQUEST_METHOD} = 'POST';
817 $ENV{SERVER_PORT} = '80';
818 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
819 $ENV{HTTP_HOST} = 'localhost';
820 $ENV{CONTENT_LENGTH} = length $in;
822 %bits = parse_cgi_content($content);
823 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
824 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
825 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
826 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
828 # not testing html5: 1 because it would be the same as site 1 -
829 # the reverse_proxy config option is unnecessary under html5