13 eval q{use Test::More skip_all => "IPC::Run not available"};
16 eval q{use Test::More};
21 my $PERL5LIB = 'blib/lib:blib/arch';
24 # Black-box (ish) test for relative linking between CGI and static content
27 my ($content, $in, %bits);
29 sub parse_cgi_content {
31 if ($content =~ qr{<base href="([^"]+)" */>}) {
34 if ($content =~ qr{href="([^"]+/style.css)"}) {
35 $bits{stylehref} = $1;
37 if ($content =~ qr{class="parentlinks">\s+<a href="([^"]+)">this is the name of my wiki</a>/}s) {
40 if ($content =~ qr{<a[^>]+href="([^"]+)\?do=prefs"}) {
46 ok(! system("make -s ikiwiki.out"));
47 ok(! system("rm -rf t/tmp"));
48 ok(! system("mkdir t/tmp"));
54 writefile($name, "t/tmp/in", $content);
55 ok(utime(333333333, 333333333, "t/tmp/in/$name"));
58 write_old_file("a.mdwn", "A");
59 write_old_file("a/b.mdwn", "B");
60 write_old_file("a/b/c.mdwn",
64 write_old_file("a/d.mdwn", "D");
65 write_old_file("a/d/e.mdwn", "E");
67 #######################################################################
68 # site 1: a perfectly ordinary ikiwiki
70 writefile("test.setup", "t/tmp", <<EOF
71 # IkiWiki::Setup::Yaml - YAML formatted setup file
72 wikiname: this is the name of my wiki
75 templatedir: templates
76 url: "http://example.com/wiki/"
77 cgiurl: "http://example.com/cgi-bin/ikiwiki.cgi"
78 cgi_wrapper: t/tmp/ikiwiki.cgi
81 # make it easier to test previewing
85 ENV: { 'PERL5LIB': '$PERL5LIB' }
89 ok(unlink("t/tmp/ikiwiki.cgi") || $!{ENOENT});
90 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
92 # CGI wrapper should be exactly the requested mode
93 my (undef, undef, $mode, undef, undef,
94 undef, undef, undef, undef, undef,
95 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
96 is($mode & 07777, 0754);
98 ok(-e "t/tmp/out/a/b/c/index.html");
99 $content = readfile("t/tmp/out/a/b/c/index.html");
100 # no <base> on static HTML
101 unlike($content, qr{<base\W});
102 # url and cgiurl are on the same host so the cgiurl is host-relative
103 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
104 # cross-links between static pages are relative
105 like($content, qr{<li>A: <a href="../../">a</a></li>});
106 like($content, qr{<li>B: <a href="../">b</a></li>});
107 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
109 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
110 $ENV{REQUEST_METHOD} = 'GET';
111 $ENV{SERVER_PORT} = '80';
112 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
113 $ENV{QUERY_STRING} = 'do=prefs';
114 $ENV{HTTP_HOST} = 'example.com';
116 %bits = parse_cgi_content($content);
117 is($bits{basehref}, "http://example.com/wiki/");
118 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
119 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
120 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
122 # when accessed via HTTPS, links are secure
123 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
124 $ENV{REQUEST_METHOD} = 'GET';
125 $ENV{SERVER_PORT} = '443';
126 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
127 $ENV{QUERY_STRING} = 'do=prefs';
128 $ENV{HTTP_HOST} = 'example.com';
131 %bits = parse_cgi_content($content);
132 is($bits{basehref}, "https://example.com/wiki/");
133 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
134 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
135 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
137 # when accessed via a different hostname, links stay on that host
138 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
139 $ENV{REQUEST_METHOD} = 'GET';
140 $ENV{SERVER_PORT} = '80';
141 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
142 $ENV{QUERY_STRING} = 'do=prefs';
143 $ENV{HTTP_HOST} = 'staging.example.net';
145 %bits = parse_cgi_content($content);
146 is($bits{basehref}, "http://staging.example.net/wiki/");
147 like($bits{stylehref}, qr{^(?:(?:http:)?//staging.example.net)?/wiki/style.css$});
148 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
149 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
152 $in = 'do=edit&page=a/b/c&Preview';
153 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
154 $ENV{REQUEST_METHOD} = 'POST';
155 $ENV{SERVER_PORT} = '80';
156 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
157 $ENV{HTTP_HOST} = 'example.com';
158 $ENV{CONTENT_LENGTH} = length $in;
160 %bits = parse_cgi_content($content);
161 is($bits{basehref}, "http://example.com/wiki/a/b/c/");
162 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
163 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
164 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
166 # in html5, the <base> is allowed to be relative, and we take full
168 writefile("test.setup", "t/tmp", <<EOF
169 # IkiWiki::Setup::Yaml - YAML formatted setup file
170 wikiname: this is the name of my wiki
173 templatedir: templates
174 url: "http://example.com/wiki/"
175 cgiurl: "http://example.com/cgi-bin/ikiwiki.cgi"
176 cgi_wrapper: t/tmp/ikiwiki.cgi
177 cgi_wrappermode: 0754
179 # make it easier to test previewing
183 ENV: { 'PERL5LIB': '$PERL5LIB' }
187 ok(unlink("t/tmp/ikiwiki.cgi") || $!{ENOENT});
188 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
190 # CGI wrapper should be exactly the requested mode
191 (undef, undef, $mode, undef, undef,
192 undef, undef, undef, undef, undef,
193 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
194 is($mode & 07777, 0754);
196 ok(-e "t/tmp/out/a/b/c/index.html");
197 $content = readfile("t/tmp/out/a/b/c/index.html");
198 # no <base> on static HTML
199 unlike($content, qr{<base\W});
200 # url and cgiurl are on the same host so the cgiurl is host-relative
201 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
202 # cross-links between static pages are relative
203 like($content, qr{<li>A: <a href="../../">a</a></li>});
204 like($content, qr{<li>B: <a href="../">b</a></li>});
205 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
207 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
208 $ENV{REQUEST_METHOD} = 'GET';
209 $ENV{SERVER_PORT} = '80';
210 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
211 $ENV{QUERY_STRING} = 'do=prefs';
212 $ENV{HTTP_HOST} = 'example.com';
214 %bits = parse_cgi_content($content);
215 is($bits{basehref}, "/wiki/");
216 is($bits{stylehref}, "/wiki/style.css");
217 is($bits{tophref}, "/wiki/");
218 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
220 # when accessed via HTTPS, links are secure - this is easy because under
221 # html5 they're independent of the URL at which the CGI was accessed
222 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
223 $ENV{REQUEST_METHOD} = 'GET';
224 $ENV{SERVER_PORT} = '443';
225 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
226 $ENV{QUERY_STRING} = 'do=prefs';
227 $ENV{HTTP_HOST} = 'example.com';
230 %bits = parse_cgi_content($content);
231 is($bits{basehref}, "/wiki/");
232 is($bits{stylehref}, "/wiki/style.css");
233 is($bits{tophref}, "/wiki/");
234 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
236 # when accessed via a different hostname, links stay on that host -
237 # this is really easy in html5 because we can use relative URLs
238 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
239 $ENV{REQUEST_METHOD} = 'GET';
240 $ENV{SERVER_PORT} = '80';
241 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
242 $ENV{QUERY_STRING} = 'do=prefs';
243 $ENV{HTTP_HOST} = 'staging.example.net';
245 %bits = parse_cgi_content($content);
246 is($bits{basehref}, "/wiki/");
247 is($bits{stylehref}, "/wiki/style.css");
248 is($bits{tophref}, "/wiki/");
249 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
252 $in = 'do=edit&page=a/b/c&Preview';
253 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
254 $ENV{REQUEST_METHOD} = 'POST';
255 $ENV{SERVER_PORT} = '80';
256 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
257 $ENV{HTTP_HOST} = 'example.com';
258 $ENV{CONTENT_LENGTH} = length $in;
260 %bits = parse_cgi_content($content);
261 is($bits{basehref}, "/wiki/a/b/c/");
262 is($bits{stylehref}, "/wiki/style.css");
263 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
264 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
266 #######################################################################
267 # site 2: static content and CGI are on different servers
269 writefile("test.setup", "t/tmp", <<EOF
270 # IkiWiki::Setup::Yaml - YAML formatted setup file
271 wikiname: this is the name of my wiki
274 templatedir: templates
275 url: "http://static.example.com/"
276 cgiurl: "http://cgi.example.com/ikiwiki.cgi"
277 cgi_wrapper: t/tmp/ikiwiki.cgi
278 cgi_wrappermode: 0754
280 # make it easier to test previewing
284 ENV: { 'PERL5LIB': '$PERL5LIB' }
288 ok(unlink("t/tmp/ikiwiki.cgi"));
289 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
291 # CGI wrapper should be exactly the requested mode
292 (undef, undef, $mode, undef, undef,
293 undef, undef, undef, undef, undef,
294 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
295 is($mode & 07777, 0754);
297 ok(-e "t/tmp/out/a/b/c/index.html");
298 $content = readfile("t/tmp/out/a/b/c/index.html");
299 # no <base> on static HTML
300 unlike($content, qr{<base\W});
301 # url and cgiurl are not on the same host so the cgiurl has to be
302 # protocol-relative or absolute
303 like($content, qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
304 # cross-links between static pages are still relative
305 like($content, qr{<li>A: <a href="../../">a</a></li>});
306 like($content, qr{<li>B: <a href="../">b</a></li>});
307 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
309 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
310 $ENV{REQUEST_METHOD} = 'GET';
311 $ENV{SERVER_PORT} = '80';
312 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
313 $ENV{QUERY_STRING} = 'do=prefs';
314 $ENV{HTTP_HOST} = 'cgi.example.com';
316 %bits = parse_cgi_content($content);
317 like($bits{basehref}, qr{^http://static.example.com/$});
318 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com)?/style.css$});
319 like($bits{tophref}, qr{^(?:http:)?//static.example.com/$});
320 like($bits{cgihref}, qr{^(?:(?:http:)?//cgi.example.com)?/ikiwiki.cgi$});
322 # when accessed via HTTPS, links are secure
323 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
324 $ENV{REQUEST_METHOD} = 'GET';
325 $ENV{SERVER_PORT} = '443';
326 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
327 $ENV{QUERY_STRING} = 'do=prefs';
328 $ENV{HTTP_HOST} = 'cgi.example.com';
331 %bits = parse_cgi_content($content);
332 like($bits{basehref}, qr{^https://static.example.com/$});
333 like($bits{stylehref}, qr{^(?:(?:https:)?//static.example.com)?/style.css$});
334 like($bits{tophref}, qr{^(?:https:)?//static.example.com/$});
335 like($bits{cgihref}, qr{^(?:(?:https:)?//cgi.example.com)?/ikiwiki.cgi$});
337 # when accessed via a different hostname, links to the CGI (only) should
339 $in = 'do=edit&page=a/b/c&Preview';
340 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
341 $ENV{REQUEST_METHOD} = 'POST';
342 $ENV{SERVER_PORT} = '80';
343 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
344 $ENV{HTTP_HOST} = 'staging.example.net';
345 $ENV{CONTENT_LENGTH} = length $in;
347 %bits = parse_cgi_content($content);
348 like($bits{basehref}, qr{^http://static.example.com/a/b/c/$});
349 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/style.css$});
350 like($bits{tophref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/$});
351 like($bits{cgihref}, qr{^(?:(?:http:)?//(?:staging\.example\.net|cgi\.example\.com))?/ikiwiki.cgi$});
353 local $TODO = "use self-referential CGI URL?";
354 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/ikiwiki.cgi$});
357 writefile("test.setup", "t/tmp", <<EOF
358 # IkiWiki::Setup::Yaml - YAML formatted setup file
359 wikiname: this is the name of my wiki
362 templatedir: templates
363 url: "http://static.example.com/"
364 cgiurl: "http://cgi.example.com/ikiwiki.cgi"
365 cgi_wrapper: t/tmp/ikiwiki.cgi
366 cgi_wrappermode: 0754
368 # make it easier to test previewing
372 ENV: { 'PERL5LIB': '$PERL5LIB' }
376 ok(unlink("t/tmp/ikiwiki.cgi"));
377 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
379 # CGI wrapper should be exactly the requested mode
380 (undef, undef, $mode, undef, undef,
381 undef, undef, undef, undef, undef,
382 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
383 is($mode & 07777, 0754);
385 ok(-e "t/tmp/out/a/b/c/index.html");
386 $content = readfile("t/tmp/out/a/b/c/index.html");
387 # no <base> on static HTML
388 unlike($content, qr{<base\W});
389 # url and cgiurl are not on the same host so the cgiurl has to be
390 # protocol-relative or absolute
391 like($content, qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
392 # cross-links between static pages are still relative
393 like($content, qr{<li>A: <a href="../../">a</a></li>});
394 like($content, qr{<li>B: <a href="../">b</a></li>});
395 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
397 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
398 $ENV{REQUEST_METHOD} = 'GET';
399 $ENV{SERVER_PORT} = '80';
400 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
401 $ENV{QUERY_STRING} = 'do=prefs';
402 $ENV{HTTP_HOST} = 'cgi.example.com';
404 %bits = parse_cgi_content($content);
405 is($bits{basehref}, "//static.example.com/");
406 is($bits{stylehref}, "//static.example.com/style.css");
407 is($bits{tophref}, "//static.example.com/");
408 is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
410 # when accessed via HTTPS, links are secure - in fact they're exactly the
411 # same as when accessed via HTTP
412 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
413 $ENV{REQUEST_METHOD} = 'GET';
414 $ENV{SERVER_PORT} = '443';
415 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
416 $ENV{QUERY_STRING} = 'do=prefs';
417 $ENV{HTTP_HOST} = 'cgi.example.com';
420 %bits = parse_cgi_content($content);
421 is($bits{basehref}, "//static.example.com/");
422 is($bits{stylehref}, "//static.example.com/style.css");
423 is($bits{tophref}, "//static.example.com/");
424 is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
426 # when accessed via a different hostname, links to the CGI (only) should
428 $in = 'do=edit&page=a/b/c&Preview';
429 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
430 $ENV{REQUEST_METHOD} = 'POST';
431 $ENV{SERVER_PORT} = '80';
432 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
433 $ENV{HTTP_HOST} = 'staging.example.net';
434 $ENV{CONTENT_LENGTH} = length $in;
436 %bits = parse_cgi_content($content);
437 is($bits{basehref}, "//static.example.com/a/b/c/");
438 is($bits{stylehref}, "//static.example.com/style.css");
439 is($bits{tophref}, "../../../");
440 like($bits{cgihref}, qr{//(?:staging\.example\.net|cgi\.example\.com)/ikiwiki\.cgi});
442 local $TODO = "use self-referential CGI URL maybe?";
443 is($bits{cgihref}, "//staging.example.net/ikiwiki.cgi");
446 #######################################################################
447 # site 3: we specifically want everything to be secure
449 writefile("test.setup", "t/tmp", <<EOF
450 # IkiWiki::Setup::Yaml - YAML formatted setup file
451 wikiname: this is the name of my wiki
454 templatedir: templates
455 url: "https://example.com/wiki/"
456 cgiurl: "https://example.com/cgi-bin/ikiwiki.cgi"
457 cgi_wrapper: t/tmp/ikiwiki.cgi
458 cgi_wrappermode: 0754
460 # make it easier to test previewing
464 ENV: { 'PERL5LIB': '$PERL5LIB' }
468 ok(unlink("t/tmp/ikiwiki.cgi"));
469 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
471 # CGI wrapper should be exactly the requested mode
472 (undef, undef, $mode, undef, undef,
473 undef, undef, undef, undef, undef,
474 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
475 is($mode & 07777, 0754);
477 ok(-e "t/tmp/out/a/b/c/index.html");
478 $content = readfile("t/tmp/out/a/b/c/index.html");
479 # no <base> on static HTML
480 unlike($content, qr{<base\W});
481 # url and cgiurl are on the same host so the cgiurl is host-relative
482 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
483 # cross-links between static pages are relative
484 like($content, qr{<li>A: <a href="../../">a</a></li>});
485 like($content, qr{<li>B: <a href="../">b</a></li>});
486 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
488 # when accessed via HTTPS, links are secure
489 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
490 $ENV{REQUEST_METHOD} = 'GET';
491 $ENV{SERVER_PORT} = '443';
492 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
493 $ENV{QUERY_STRING} = 'do=prefs';
494 $ENV{HTTP_HOST} = 'example.com';
497 %bits = parse_cgi_content($content);
498 is($bits{basehref}, "https://example.com/wiki/");
499 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
500 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
501 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
503 # when not accessed via HTTPS, links should still be secure
504 # (but if this happens, that's a sign of web server misconfiguration)
505 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
506 $ENV{REQUEST_METHOD} = 'GET';
507 $ENV{SERVER_PORT} = '80';
508 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
509 $ENV{QUERY_STRING} = 'do=prefs';
510 $ENV{HTTP_HOST} = 'example.com';
512 %bits = parse_cgi_content($content);
513 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
515 local $TODO = "treat https in configured url, cgiurl as required?";
516 is($bits{basehref}, "https://example.com/wiki/");
517 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
519 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
521 # when accessed via a different hostname, links stay on that host
522 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
523 $ENV{REQUEST_METHOD} = 'GET';
524 $ENV{SERVER_PORT} = '443';
525 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
526 $ENV{QUERY_STRING} = 'do=prefs';
527 $ENV{HTTP_HOST} = 'staging.example.net';
530 %bits = parse_cgi_content($content);
531 is($bits{basehref}, "https://staging.example.net/wiki/");
532 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
533 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
534 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
537 $in = 'do=edit&page=a/b/c&Preview';
538 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
539 $ENV{REQUEST_METHOD} = 'POST';
540 $ENV{SERVER_PORT} = '443';
541 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
542 $ENV{HTTP_HOST} = 'example.com';
543 $ENV{CONTENT_LENGTH} = length $in;
546 %bits = parse_cgi_content($content);
547 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
548 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
549 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
550 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
552 # not testing html5: 0 here because that ends up identical to site 1
554 #######################################################################
555 # site 4 (NetBSD wiki): CGI is secure, static content doesn't have to be
557 writefile("test.setup", "t/tmp", <<EOF
558 # IkiWiki::Setup::Yaml - YAML formatted setup file
559 wikiname: this is the name of my wiki
562 templatedir: templates
563 url: "http://example.com/wiki/"
564 cgiurl: "https://example.com/cgi-bin/ikiwiki.cgi"
565 cgi_wrapper: t/tmp/ikiwiki.cgi
566 cgi_wrappermode: 0754
568 # make it easier to test previewing
572 ENV: { 'PERL5LIB': '$PERL5LIB' }
576 ok(unlink("t/tmp/ikiwiki.cgi"));
577 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
579 # CGI wrapper should be exactly the requested mode
580 (undef, undef, $mode, undef, undef,
581 undef, undef, undef, undef, undef,
582 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
583 is($mode & 07777, 0754);
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}, "https://example.com/wiki/");
607 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
608 like($bits{tophref}, qr{^(?:/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 like($bits{basehref}, qr{^https://staging.example.net/wiki/$});
638 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
639 like($bits{tophref}, qr{^(?:(?:(?:https:)?//staging.example.net)?/wiki|\.)/$});
640 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:staging\.example\.net|example\.com))?/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}, "https://example.com/wiki/a/b/c/");
658 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
659 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
660 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
662 writefile("test.setup", "t/tmp", <<EOF
663 # IkiWiki::Setup::Yaml - YAML formatted setup file
664 wikiname: this is the name of my wiki
667 templatedir: templates
668 url: "http://example.com/wiki/"
669 cgiurl: "https://example.com/cgi-bin/ikiwiki.cgi"
670 cgi_wrapper: t/tmp/ikiwiki.cgi
671 cgi_wrappermode: 0754
673 # make it easier to test previewing
677 ENV: { 'PERL5LIB': '$PERL5LIB' }
681 ok(unlink("t/tmp/ikiwiki.cgi"));
682 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
684 # CGI wrapper should be exactly the requested mode
685 (undef, undef, $mode, undef, undef,
686 undef, undef, undef, undef, undef,
687 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
688 is($mode & 07777, 0754);
690 ok(-e "t/tmp/out/a/b/c/index.html");
691 $content = readfile("t/tmp/out/a/b/c/index.html");
692 # no <base> on static HTML
693 unlike($content, qr{<base\W});
694 # url and cgiurl are on the same host but different schemes
695 like($content, qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
696 # cross-links between static pages are relative
697 like($content, qr{<li>A: <a href="../../">a</a></li>});
698 like($content, qr{<li>B: <a href="../">b</a></li>});
699 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
701 # when accessed via HTTPS, links are secure (to avoid mixed-content)
702 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
703 $ENV{REQUEST_METHOD} = 'GET';
704 $ENV{SERVER_PORT} = '443';
705 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
706 $ENV{QUERY_STRING} = 'do=prefs';
707 $ENV{HTTP_HOST} = 'example.com';
710 %bits = parse_cgi_content($content);
711 is($bits{basehref}, "/wiki/");
712 is($bits{stylehref}, "/wiki/style.css");
713 is($bits{tophref}, "/wiki/");
714 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
716 # when not accessed via HTTPS, ???
717 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
718 $ENV{REQUEST_METHOD} = 'GET';
719 $ENV{SERVER_PORT} = '80';
720 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
721 $ENV{QUERY_STRING} = 'do=prefs';
722 $ENV{HTTP_HOST} = 'example.com';
724 %bits = parse_cgi_content($content);
725 like($bits{basehref}, qr{^(?:https?://example.com)?/wiki/$});
726 like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
727 like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
728 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
730 # when accessed via a different hostname, links stay on that host
731 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
732 $ENV{REQUEST_METHOD} = 'GET';
733 $ENV{SERVER_PORT} = '443';
734 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
735 $ENV{QUERY_STRING} = 'do=prefs';
736 $ENV{HTTP_HOST} = 'staging.example.net';
739 %bits = parse_cgi_content($content);
740 # because the static and dynamic stuff is on the same server, we assume that
741 # both are also on the staging server
742 is($bits{basehref}, "/wiki/");
743 is($bits{stylehref}, "/wiki/style.css");
744 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
745 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:example\.com|staging\.example\.net))?/cgi-bin/ikiwiki.cgi$});
747 local $TODO = "this should really point back to itself but currently points to example.com";
748 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
752 $in = 'do=edit&page=a/b/c&Preview';
753 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
754 $ENV{REQUEST_METHOD} = 'POST';
755 $ENV{SERVER_PORT} = '443';
756 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
757 $ENV{HTTP_HOST} = 'example.com';
758 $ENV{CONTENT_LENGTH} = length $in;
761 %bits = parse_cgi_content($content);
762 is($bits{basehref}, "/wiki/a/b/c/");
763 is($bits{stylehref}, "/wiki/style.css");
764 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
765 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
767 # Deliberately not testing https static content with http cgiurl,
768 # because that makes remarkably little sense.
770 #######################################################################
771 # site 5: w3mmode, as documented in [[w3mmode]]
773 writefile("test.setup", "t/tmp", <<EOF
774 # IkiWiki::Setup::Yaml - YAML formatted setup file
775 wikiname: this is the name of my wiki
778 templatedir: templates
781 cgi_wrapper: t/tmp/ikiwiki.cgi
782 cgi_wrappermode: 0754
787 ENV: { 'PERL5LIB': '$PERL5LIB' }
791 ok(unlink("t/tmp/ikiwiki.cgi"));
792 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
794 # CGI wrapper should be exactly the requested mode
795 (undef, undef, $mode, undef, undef,
796 undef, undef, undef, undef, undef,
797 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
798 is($mode & 07777, 0754);
800 ok(-e "t/tmp/out/a/b/c/index.html");
801 $content = readfile("t/tmp/out/a/b/c/index.html");
802 # no <base> on static HTML
803 unlike($content, qr{<base\W});
804 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
805 like($content, qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
806 # cross-links between static pages are still relative
807 like($content, qr{<li>A: <a href="../../">a</a></li>});
808 like($content, qr{<li>B: <a href="../">b</a></li>});
809 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
811 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
812 $ENV{REQUEST_METHOD} = 'GET';
813 $ENV{PATH_INFO} = '/ikiwiki.cgi';
814 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
815 $ENV{QUERY_STRING} = 'do=prefs';
817 %bits = parse_cgi_content($content);
818 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
819 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
820 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
821 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
823 writefile("test.setup", "t/tmp", <<EOF
824 # IkiWiki::Setup::Yaml - YAML formatted setup file
825 wikiname: this is the name of my wiki
828 templatedir: templates
831 cgi_wrapper: t/tmp/ikiwiki.cgi
832 cgi_wrappermode: 0754
837 ENV: { 'PERL5LIB': '$PERL5LIB' }
841 ok(unlink("t/tmp/ikiwiki.cgi"));
842 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
844 # CGI wrapper should be exactly the requested mode
845 (undef, undef, $mode, undef, undef,
846 undef, undef, undef, undef, undef,
847 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
848 is($mode & 07777, 0754);
850 ok(-e "t/tmp/out/a/b/c/index.html");
851 $content = readfile("t/tmp/out/a/b/c/index.html");
852 # no <base> on static HTML
853 unlike($content, qr{<base\W});
854 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
855 like($content, qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
856 # cross-links between static pages are still relative
857 like($content, qr{<li>A: <a href="../../">a</a></li>});
858 like($content, qr{<li>B: <a href="../">b</a></li>});
859 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
861 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
862 $ENV{REQUEST_METHOD} = 'GET';
863 $ENV{PATH_INFO} = '/ikiwiki.cgi';
864 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
865 $ENV{QUERY_STRING} = 'do=prefs';
867 %bits = parse_cgi_content($content);
868 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
869 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
870 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
871 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
873 #######################################################################
874 # site 6: we're behind a reverse-proxy
876 writefile("test.setup", "t/tmp", <<EOF
877 # IkiWiki::Setup::Yaml - YAML formatted setup file
878 wikiname: this is the name of my wiki
881 templatedir: templates
882 url: "https://example.com/wiki/"
883 cgiurl: "https://example.com/cgi-bin/ikiwiki.cgi"
884 cgi_wrapper: t/tmp/ikiwiki.cgi
885 cgi_wrappermode: 0754
887 # make it easier to test previewing
892 ENV: { 'PERL5LIB': '$PERL5LIB' }
896 ok(unlink("t/tmp/ikiwiki.cgi"));
897 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
899 # CGI wrapper should be exactly the requested mode
900 (undef, undef, $mode, undef, undef,
901 undef, undef, undef, undef, undef,
902 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
903 is($mode & 07777, 0754);
905 ok(-e "t/tmp/out/a/b/c/index.html");
906 $content = readfile("t/tmp/out/a/b/c/index.html");
907 # no <base> on static HTML
908 unlike($content, qr{<base\W});
909 # url and cgiurl are on the same host so the cgiurl is host-relative
910 like($content, qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
911 # cross-links between static pages are relative
912 like($content, qr{<li>A: <a href="../../">a</a></li>});
913 like($content, qr{<li>B: <a href="../">b</a></li>});
914 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
916 # because we are behind a reverse-proxy we must assume that
917 # we're being accessed by the configured cgiurl
918 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
919 $ENV{REQUEST_METHOD} = 'GET';
920 $ENV{SERVER_PORT} = '80';
921 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
922 $ENV{QUERY_STRING} = 'do=prefs';
923 $ENV{HTTP_HOST} = 'localhost';
925 %bits = parse_cgi_content($content);
926 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
927 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
928 is($bits{basehref}, "https://example.com/wiki/");
929 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
932 $in = 'do=edit&page=a/b/c&Preview';
933 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
934 $ENV{REQUEST_METHOD} = 'POST';
935 $ENV{SERVER_PORT} = '80';
936 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
937 $ENV{HTTP_HOST} = 'localhost';
938 $ENV{CONTENT_LENGTH} = length $in;
940 %bits = parse_cgi_content($content);
941 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
942 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
943 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
944 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
946 # not testing html5: 1 because it would be the same as site 1 -
947 # the reverse_proxy config option is unnecessary under html5