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 #######################################################################
91 # site 1: a perfectly ordinary ikiwiki
95 url => "http://example.com/wiki/",
96 cgiurl => "http://example.com/cgi-bin/ikiwiki.cgi",
99 ok(unlink("t/tmp/ikiwiki.cgi") || $!{ENOENT});
100 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
102 # CGI wrapper should be exactly the requested mode
103 my (undef, undef, $mode, undef, undef,
104 undef, undef, undef, undef, undef,
105 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
106 is($mode & 07777, 0754);
108 ok(-e "t/tmp/out/a/b/c/index.html");
109 $content = readfile("t/tmp/out/a/b/c/index.html");
110 # no <base> on static HTML
111 unlike($content, qr{<base\W});
112 # url and cgiurl are on the same host so the cgiurl is host-relative
113 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
114 # cross-links between static pages are relative
115 like($content, qr{<li>A: <a href="../../">a</a></li>});
116 like($content, qr{<li>B: <a href="../">b</a></li>});
117 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
119 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
120 $ENV{REQUEST_METHOD} = 'GET';
121 $ENV{SERVER_PORT} = '80';
122 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
123 $ENV{QUERY_STRING} = 'do=prefs';
124 $ENV{HTTP_HOST} = 'example.com';
126 %bits = parse_cgi_content($content);
127 is($bits{basehref}, "http://example.com/wiki/");
128 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
129 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
130 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
132 # when accessed via HTTPS, links are secure
133 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
134 $ENV{REQUEST_METHOD} = 'GET';
135 $ENV{SERVER_PORT} = '443';
136 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
137 $ENV{QUERY_STRING} = 'do=prefs';
138 $ENV{HTTP_HOST} = 'example.com';
141 %bits = parse_cgi_content($content);
142 is($bits{basehref}, "https://example.com/wiki/");
143 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
144 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
145 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
147 # when accessed via a different hostname, links stay on that host
148 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
149 $ENV{REQUEST_METHOD} = 'GET';
150 $ENV{SERVER_PORT} = '80';
151 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
152 $ENV{QUERY_STRING} = 'do=prefs';
153 $ENV{HTTP_HOST} = 'staging.example.net';
155 %bits = parse_cgi_content($content);
156 is($bits{basehref}, "http://staging.example.net/wiki/");
157 like($bits{stylehref}, qr{^(?:(?:http:)?//staging.example.net)?/wiki/style.css$});
158 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
159 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
162 $in = 'do=edit&page=a/b/c&Preview';
163 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
164 $ENV{REQUEST_METHOD} = 'POST';
165 $ENV{SERVER_PORT} = '80';
166 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
167 $ENV{HTTP_HOST} = 'example.com';
168 $ENV{CONTENT_LENGTH} = length $in;
170 %bits = parse_cgi_content($content);
171 is($bits{basehref}, "http://example.com/wiki/a/b/c/");
172 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
173 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
174 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
176 # in html5, the <base> is allowed to be relative, and we take full
180 url => "http://example.com/wiki/",
181 cgiurl => "http://example.com/cgi-bin/ikiwiki.cgi",
184 ok(unlink("t/tmp/ikiwiki.cgi") || $!{ENOENT});
185 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
187 # CGI wrapper should be exactly the requested mode
188 (undef, undef, $mode, undef, undef,
189 undef, undef, undef, undef, undef,
190 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
191 is($mode & 07777, 0754);
193 ok(-e "t/tmp/out/a/b/c/index.html");
194 $content = readfile("t/tmp/out/a/b/c/index.html");
195 # no <base> on static HTML
196 unlike($content, qr{<base\W});
197 # url and cgiurl are on the same host so the cgiurl is host-relative
198 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
199 # cross-links between static pages are relative
200 like($content, qr{<li>A: <a href="../../">a</a></li>});
201 like($content, qr{<li>B: <a href="../">b</a></li>});
202 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
204 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
205 $ENV{REQUEST_METHOD} = 'GET';
206 $ENV{SERVER_PORT} = '80';
207 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
208 $ENV{QUERY_STRING} = 'do=prefs';
209 $ENV{HTTP_HOST} = 'example.com';
211 %bits = parse_cgi_content($content);
212 is($bits{basehref}, "/wiki/");
213 is($bits{stylehref}, "/wiki/style.css");
214 is($bits{tophref}, "/wiki/");
215 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
217 # when accessed via HTTPS, links are secure - this is easy because under
218 # html5 they're independent of the URL at which the CGI was accessed
219 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
220 $ENV{REQUEST_METHOD} = 'GET';
221 $ENV{SERVER_PORT} = '443';
222 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
223 $ENV{QUERY_STRING} = 'do=prefs';
224 $ENV{HTTP_HOST} = 'example.com';
227 %bits = parse_cgi_content($content);
228 is($bits{basehref}, "/wiki/");
229 is($bits{stylehref}, "/wiki/style.css");
230 is($bits{tophref}, "/wiki/");
231 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
233 # when accessed via a different hostname, links stay on that host -
234 # this is really easy in html5 because we can use relative URLs
235 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
236 $ENV{REQUEST_METHOD} = 'GET';
237 $ENV{SERVER_PORT} = '80';
238 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
239 $ENV{QUERY_STRING} = 'do=prefs';
240 $ENV{HTTP_HOST} = 'staging.example.net';
242 %bits = parse_cgi_content($content);
243 is($bits{basehref}, "/wiki/");
244 is($bits{stylehref}, "/wiki/style.css");
245 is($bits{tophref}, "/wiki/");
246 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
249 $in = 'do=edit&page=a/b/c&Preview';
250 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
251 $ENV{REQUEST_METHOD} = 'POST';
252 $ENV{SERVER_PORT} = '80';
253 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
254 $ENV{HTTP_HOST} = 'example.com';
255 $ENV{CONTENT_LENGTH} = length $in;
257 %bits = parse_cgi_content($content);
258 is($bits{basehref}, "/wiki/a/b/c/");
259 is($bits{stylehref}, "/wiki/style.css");
260 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
261 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
263 #######################################################################
264 # site 2: static content and CGI are on different servers
268 url => "http://static.example.com/",
269 cgiurl => "http://cgi.example.com/ikiwiki.cgi",
272 ok(unlink("t/tmp/ikiwiki.cgi"));
273 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
275 # CGI wrapper should be exactly the requested mode
276 (undef, undef, $mode, undef, undef,
277 undef, undef, undef, undef, undef,
278 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
279 is($mode & 07777, 0754);
281 ok(-e "t/tmp/out/a/b/c/index.html");
282 $content = readfile("t/tmp/out/a/b/c/index.html");
283 # no <base> on static HTML
284 unlike($content, qr{<base\W});
285 # url and cgiurl are not on the same host so the cgiurl has to be
286 # protocol-relative or absolute
287 like($content, qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
288 # cross-links between static pages are still relative
289 like($content, qr{<li>A: <a href="../../">a</a></li>});
290 like($content, qr{<li>B: <a href="../">b</a></li>});
291 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
293 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
294 $ENV{REQUEST_METHOD} = 'GET';
295 $ENV{SERVER_PORT} = '80';
296 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
297 $ENV{QUERY_STRING} = 'do=prefs';
298 $ENV{HTTP_HOST} = 'cgi.example.com';
300 %bits = parse_cgi_content($content);
301 like($bits{basehref}, qr{^http://static.example.com/$});
302 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com)?/style.css$});
303 like($bits{tophref}, qr{^(?:http:)?//static.example.com/$});
304 like($bits{cgihref}, qr{^(?:(?:http:)?//cgi.example.com)?/ikiwiki.cgi$});
306 # when accessed via HTTPS, links are secure
307 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
308 $ENV{REQUEST_METHOD} = 'GET';
309 $ENV{SERVER_PORT} = '443';
310 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
311 $ENV{QUERY_STRING} = 'do=prefs';
312 $ENV{HTTP_HOST} = 'cgi.example.com';
315 %bits = parse_cgi_content($content);
316 like($bits{basehref}, qr{^https://static.example.com/$});
317 like($bits{stylehref}, qr{^(?:(?:https:)?//static.example.com)?/style.css$});
318 like($bits{tophref}, qr{^(?:https:)?//static.example.com/$});
319 like($bits{cgihref}, qr{^(?:(?:https:)?//cgi.example.com)?/ikiwiki.cgi$});
321 # when accessed via a different hostname, links to the CGI (only) should
323 $in = 'do=edit&page=a/b/c&Preview';
324 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
325 $ENV{REQUEST_METHOD} = 'POST';
326 $ENV{SERVER_PORT} = '80';
327 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
328 $ENV{HTTP_HOST} = 'staging.example.net';
329 $ENV{CONTENT_LENGTH} = length $in;
331 %bits = parse_cgi_content($content);
332 like($bits{basehref}, qr{^http://static.example.com/a/b/c/$});
333 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/style.css$});
334 like($bits{tophref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/$});
335 like($bits{cgihref}, qr{^(?:(?:http:)?//(?:staging\.example\.net|cgi\.example\.com))?/ikiwiki.cgi$});
337 local $TODO = "use self-referential CGI URL?";
338 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/ikiwiki.cgi$});
343 url => "http://static.example.com/",
344 cgiurl => "http://cgi.example.com/ikiwiki.cgi",
347 ok(unlink("t/tmp/ikiwiki.cgi"));
348 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
350 # CGI wrapper should be exactly the requested mode
351 (undef, undef, $mode, undef, undef,
352 undef, undef, undef, undef, undef,
353 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
354 is($mode & 07777, 0754);
356 ok(-e "t/tmp/out/a/b/c/index.html");
357 $content = readfile("t/tmp/out/a/b/c/index.html");
358 # no <base> on static HTML
359 unlike($content, qr{<base\W});
360 # url and cgiurl are not on the same host so the cgiurl has to be
361 # protocol-relative or absolute
362 like($content, qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
363 # cross-links between static pages are still relative
364 like($content, qr{<li>A: <a href="../../">a</a></li>});
365 like($content, qr{<li>B: <a href="../">b</a></li>});
366 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
368 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
369 $ENV{REQUEST_METHOD} = 'GET';
370 $ENV{SERVER_PORT} = '80';
371 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
372 $ENV{QUERY_STRING} = 'do=prefs';
373 $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 HTTPS, links are secure - in fact they're exactly the
382 # same as when accessed via HTTP
383 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
384 $ENV{REQUEST_METHOD} = 'GET';
385 $ENV{SERVER_PORT} = '443';
386 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
387 $ENV{QUERY_STRING} = 'do=prefs';
388 $ENV{HTTP_HOST} = 'cgi.example.com';
391 %bits = parse_cgi_content($content);
392 is($bits{basehref}, "//static.example.com/");
393 is($bits{stylehref}, "//static.example.com/style.css");
394 is($bits{tophref}, "//static.example.com/");
395 is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
397 # when accessed via a different hostname, links to the CGI (only) should
399 $in = 'do=edit&page=a/b/c&Preview';
400 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
401 $ENV{REQUEST_METHOD} = 'POST';
402 $ENV{SERVER_PORT} = '80';
403 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
404 $ENV{HTTP_HOST} = 'staging.example.net';
405 $ENV{CONTENT_LENGTH} = length $in;
407 %bits = parse_cgi_content($content);
408 is($bits{basehref}, "//static.example.com/a/b/c/");
409 is($bits{stylehref}, "//static.example.com/style.css");
410 is($bits{tophref}, "../../../");
411 like($bits{cgihref}, qr{//(?:staging\.example\.net|cgi\.example\.com)/ikiwiki\.cgi});
413 local $TODO = "use self-referential CGI URL maybe?";
414 is($bits{cgihref}, "//staging.example.net/ikiwiki.cgi");
417 #######################################################################
418 # site 3: we specifically want everything to be secure
422 url => "https://example.com/wiki/",
423 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
426 ok(unlink("t/tmp/ikiwiki.cgi"));
427 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
429 # CGI wrapper should be exactly the requested mode
430 (undef, undef, $mode, undef, undef,
431 undef, undef, undef, undef, undef,
432 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
433 is($mode & 07777, 0754);
435 ok(-e "t/tmp/out/a/b/c/index.html");
436 $content = readfile("t/tmp/out/a/b/c/index.html");
437 # no <base> on static HTML
438 unlike($content, qr{<base\W});
439 # url and cgiurl are on the same host so the cgiurl is host-relative
440 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
441 # cross-links between static pages are relative
442 like($content, qr{<li>A: <a href="../../">a</a></li>});
443 like($content, qr{<li>B: <a href="../">b</a></li>});
444 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
446 # when accessed via HTTPS, links are secure
447 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
448 $ENV{REQUEST_METHOD} = 'GET';
449 $ENV{SERVER_PORT} = '443';
450 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
451 $ENV{QUERY_STRING} = 'do=prefs';
452 $ENV{HTTP_HOST} = 'example.com';
455 %bits = parse_cgi_content($content);
456 is($bits{basehref}, "https://example.com/wiki/");
457 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
458 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
459 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
461 # when not accessed via HTTPS, links should still be secure
462 # (but if this happens, that's a sign of web server misconfiguration)
463 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
464 $ENV{REQUEST_METHOD} = 'GET';
465 $ENV{SERVER_PORT} = '80';
466 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
467 $ENV{QUERY_STRING} = 'do=prefs';
468 $ENV{HTTP_HOST} = 'example.com';
470 %bits = parse_cgi_content($content);
471 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
473 local $TODO = "treat https in configured url, cgiurl as required?";
474 is($bits{basehref}, "https://example.com/wiki/");
475 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
477 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
479 # when accessed via a different hostname, links stay on that host
480 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
481 $ENV{REQUEST_METHOD} = 'GET';
482 $ENV{SERVER_PORT} = '443';
483 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
484 $ENV{QUERY_STRING} = 'do=prefs';
485 $ENV{HTTP_HOST} = 'staging.example.net';
488 %bits = parse_cgi_content($content);
489 is($bits{basehref}, "https://staging.example.net/wiki/");
490 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
491 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
492 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
495 $in = 'do=edit&page=a/b/c&Preview';
496 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
497 $ENV{REQUEST_METHOD} = 'POST';
498 $ENV{SERVER_PORT} = '443';
499 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
500 $ENV{HTTP_HOST} = 'example.com';
501 $ENV{CONTENT_LENGTH} = length $in;
504 %bits = parse_cgi_content($content);
505 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
506 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
507 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
508 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
510 # not testing html5: 0 here because that ends up identical to site 1
512 #######################################################################
513 # site 4 (NetBSD wiki): CGI is secure, static content doesn't have to be
517 url => "http://example.com/wiki/",
518 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
521 ok(unlink("t/tmp/ikiwiki.cgi"));
522 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
524 # CGI wrapper should be exactly the requested mode
525 (undef, undef, $mode, undef, undef,
526 undef, undef, undef, undef, undef,
527 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
528 is($mode & 07777, 0754);
530 ok(-e "t/tmp/out/a/b/c/index.html");
531 $content = readfile("t/tmp/out/a/b/c/index.html");
532 # no <base> on static HTML
533 unlike($content, qr{<base\W});
534 # url and cgiurl are on the same host but different schemes
535 like($content, qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
536 # cross-links between static pages are relative
537 like($content, qr{<li>A: <a href="../../">a</a></li>});
538 like($content, qr{<li>B: <a href="../">b</a></li>});
539 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
541 # when accessed via HTTPS, links are secure (to avoid mixed-content)
542 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
543 $ENV{REQUEST_METHOD} = 'GET';
544 $ENV{SERVER_PORT} = '443';
545 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
546 $ENV{QUERY_STRING} = 'do=prefs';
547 $ENV{HTTP_HOST} = 'example.com';
550 %bits = parse_cgi_content($content);
551 is($bits{basehref}, "https://example.com/wiki/");
552 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
553 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
554 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
556 # when not accessed via HTTPS, ???
557 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
558 $ENV{REQUEST_METHOD} = 'GET';
559 $ENV{SERVER_PORT} = '80';
560 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
561 $ENV{QUERY_STRING} = 'do=prefs';
562 $ENV{HTTP_HOST} = 'example.com';
564 %bits = parse_cgi_content($content);
565 like($bits{basehref}, qr{^https?://example.com/wiki/$});
566 like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
567 like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
568 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
570 # when accessed via a different hostname, links stay on that host
571 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
572 $ENV{REQUEST_METHOD} = 'GET';
573 $ENV{SERVER_PORT} = '443';
574 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
575 $ENV{QUERY_STRING} = 'do=prefs';
576 $ENV{HTTP_HOST} = 'staging.example.net';
579 %bits = parse_cgi_content($content);
580 # because the static and dynamic stuff is on the same server, we assume that
581 # both are also on the staging server
582 like($bits{basehref}, qr{^https://staging.example.net/wiki/$});
583 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
584 like($bits{tophref}, qr{^(?:(?:(?:https:)?//staging.example.net)?/wiki|\.)/$});
585 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:staging\.example\.net|example\.com))?/cgi-bin/ikiwiki.cgi$});
587 local $TODO = "this should really point back to itself but currently points to example.com";
588 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
592 $in = 'do=edit&page=a/b/c&Preview';
593 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
594 $ENV{REQUEST_METHOD} = 'POST';
595 $ENV{SERVER_PORT} = '443';
596 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
597 $ENV{HTTP_HOST} = 'example.com';
598 $ENV{CONTENT_LENGTH} = length $in;
601 %bits = parse_cgi_content($content);
602 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
603 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
604 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
605 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
609 url => "http://example.com/wiki/",
610 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
613 ok(unlink("t/tmp/ikiwiki.cgi"));
614 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
616 # CGI wrapper should be exactly the requested mode
617 (undef, undef, $mode, undef, undef,
618 undef, undef, undef, undef, undef,
619 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
620 is($mode & 07777, 0754);
622 ok(-e "t/tmp/out/a/b/c/index.html");
623 $content = readfile("t/tmp/out/a/b/c/index.html");
624 # no <base> on static HTML
625 unlike($content, qr{<base\W});
626 # url and cgiurl are on the same host but different schemes
627 like($content, qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
628 # cross-links between static pages are relative
629 like($content, qr{<li>A: <a href="../../">a</a></li>});
630 like($content, qr{<li>B: <a href="../">b</a></li>});
631 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
633 # when accessed via HTTPS, links are secure (to avoid mixed-content)
634 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
635 $ENV{REQUEST_METHOD} = 'GET';
636 $ENV{SERVER_PORT} = '443';
637 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
638 $ENV{QUERY_STRING} = 'do=prefs';
639 $ENV{HTTP_HOST} = 'example.com';
642 %bits = parse_cgi_content($content);
643 is($bits{basehref}, "/wiki/");
644 is($bits{stylehref}, "/wiki/style.css");
645 is($bits{tophref}, "/wiki/");
646 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
648 # when not accessed via HTTPS, ???
649 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
650 $ENV{REQUEST_METHOD} = 'GET';
651 $ENV{SERVER_PORT} = '80';
652 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
653 $ENV{QUERY_STRING} = 'do=prefs';
654 $ENV{HTTP_HOST} = 'example.com';
656 %bits = parse_cgi_content($content);
657 like($bits{basehref}, qr{^(?:https?://example.com)?/wiki/$});
658 like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
659 like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
660 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
662 # when accessed via a different hostname, links stay on that host
663 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
664 $ENV{REQUEST_METHOD} = 'GET';
665 $ENV{SERVER_PORT} = '443';
666 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
667 $ENV{QUERY_STRING} = 'do=prefs';
668 $ENV{HTTP_HOST} = 'staging.example.net';
671 %bits = parse_cgi_content($content);
672 # because the static and dynamic stuff is on the same server, we assume that
673 # both are also on the staging server
674 is($bits{basehref}, "/wiki/");
675 is($bits{stylehref}, "/wiki/style.css");
676 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
677 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:example\.com|staging\.example\.net))?/cgi-bin/ikiwiki.cgi$});
679 local $TODO = "this should really point back to itself but currently points to example.com";
680 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
684 $in = 'do=edit&page=a/b/c&Preview';
685 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
686 $ENV{REQUEST_METHOD} = 'POST';
687 $ENV{SERVER_PORT} = '443';
688 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
689 $ENV{HTTP_HOST} = 'example.com';
690 $ENV{CONTENT_LENGTH} = length $in;
693 %bits = parse_cgi_content($content);
694 is($bits{basehref}, "/wiki/a/b/c/");
695 is($bits{stylehref}, "/wiki/style.css");
696 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
697 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
699 # Deliberately not testing https static content with http cgiurl,
700 # because that makes remarkably little sense.
702 #######################################################################
703 # site 5: w3mmode, as documented in [[w3mmode]]
708 cgiurl => "ikiwiki.cgi",
712 ok(unlink("t/tmp/ikiwiki.cgi"));
713 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
715 # CGI wrapper should be exactly the requested mode
716 (undef, undef, $mode, undef, undef,
717 undef, undef, undef, undef, undef,
718 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
719 is($mode & 07777, 0754);
721 ok(-e "t/tmp/out/a/b/c/index.html");
722 $content = readfile("t/tmp/out/a/b/c/index.html");
723 # no <base> on static HTML
724 unlike($content, qr{<base\W});
725 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
726 like($content, qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
727 # cross-links between static pages are still relative
728 like($content, qr{<li>A: <a href="../../">a</a></li>});
729 like($content, qr{<li>B: <a href="../">b</a></li>});
730 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
732 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
733 $ENV{REQUEST_METHOD} = 'GET';
734 $ENV{PATH_INFO} = '/ikiwiki.cgi';
735 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
736 $ENV{QUERY_STRING} = 'do=prefs';
738 %bits = parse_cgi_content($content);
739 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
740 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
741 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
742 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
747 cgiurl => "ikiwiki.cgi",
751 ok(unlink("t/tmp/ikiwiki.cgi"));
752 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
754 # CGI wrapper should be exactly the requested mode
755 (undef, undef, $mode, undef, undef,
756 undef, undef, undef, undef, undef,
757 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
758 is($mode & 07777, 0754);
760 ok(-e "t/tmp/out/a/b/c/index.html");
761 $content = readfile("t/tmp/out/a/b/c/index.html");
762 # no <base> on static HTML
763 unlike($content, qr{<base\W});
764 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
765 like($content, qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
766 # cross-links between static pages are still relative
767 like($content, qr{<li>A: <a href="../../">a</a></li>});
768 like($content, qr{<li>B: <a href="../">b</a></li>});
769 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
771 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
772 $ENV{REQUEST_METHOD} = 'GET';
773 $ENV{PATH_INFO} = '/ikiwiki.cgi';
774 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
775 $ENV{QUERY_STRING} = 'do=prefs';
777 %bits = parse_cgi_content($content);
778 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
779 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
780 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
781 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
783 #######################################################################
784 # site 6: we're behind a reverse-proxy
788 url => "https://example.com/wiki/",
789 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
793 ok(unlink("t/tmp/ikiwiki.cgi"));
794 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
796 # CGI wrapper should be exactly the requested mode
797 (undef, undef, $mode, undef, undef,
798 undef, undef, undef, undef, undef,
799 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
800 is($mode & 07777, 0754);
802 ok(-e "t/tmp/out/a/b/c/index.html");
803 $content = readfile("t/tmp/out/a/b/c/index.html");
804 # no <base> on static HTML
805 unlike($content, qr{<base\W});
806 # url and cgiurl are on the same host so the cgiurl is host-relative
807 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
808 # cross-links between static pages are relative
809 like($content, qr{<li>A: <a href="../../">a</a></li>});
810 like($content, qr{<li>B: <a href="../">b</a></li>});
811 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
813 # because we are behind a reverse-proxy we must assume that
814 # we're being accessed by the configured cgiurl
815 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
816 $ENV{REQUEST_METHOD} = 'GET';
817 $ENV{SERVER_PORT} = '80';
818 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
819 $ENV{QUERY_STRING} = 'do=prefs';
820 $ENV{HTTP_HOST} = 'localhost';
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/");
826 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
829 $in = 'do=edit&page=a/b/c&Preview';
830 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
831 $ENV{REQUEST_METHOD} = 'POST';
832 $ENV{SERVER_PORT} = '80';
833 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
834 $ENV{HTTP_HOST} = 'localhost';
835 $ENV{CONTENT_LENGTH} = length $in;
837 %bits = parse_cgi_content($content);
838 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
839 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
840 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
841 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
843 # not testing html5: 1 because it would be the same as site 1 -
844 # the reverse_proxy config option is unnecessary under html5