6 plan(skip_all => "IPC::Run not available")
19 # Black-box (ish) test for relative linking between CGI and static content
22 my ($content, $in, %bits);
24 sub parse_cgi_content {
26 if ($content =~ qr{<base href="([^"]+)" */>}) {
29 if ($content =~ qr{href="([^"]+/style.css)"}) {
30 $bits{stylehref} = $1;
32 if ($content =~ qr{class="parentlinks">\s+<a href="([^"]+)">this is the name of my wiki</a>/}s) {
35 if ($content =~ qr{<a[^>]+href="([^"]+)\?do=prefs"}) {
41 ok(! system("make -s ikiwiki.out"));
42 ok(! system("rm -rf t/tmp"));
43 ok(! system("mkdir t/tmp"));
49 writefile($name, "t/tmp/in", $content);
50 ok(utime(333333333, 333333333, "t/tmp/in/$name"));
53 write_old_file("a.mdwn", "A");
54 write_old_file("a/b.mdwn", "B");
55 write_old_file("a/b/c.mdwn",
59 write_old_file("a/d.mdwn", "D");
60 write_old_file("a/d/e.mdwn", "E");
62 sub write_setup_file {
64 my $urlline = defined $args{url} ? "url: $args{url}" : "";
65 my $w3mmodeline = defined $args{w3mmode} ? "w3mmode: $args{w3mmode}" : "";
66 my $reverseproxyline = defined $args{reverse_proxy} ? "reverse_proxy: $args{reverse_proxy}" : "";
68 writefile("test.setup", "t/tmp", <<EOF
69 # IkiWiki::Setup::Yaml - YAML formatted setup file
70 wikiname: this is the name of my wiki
73 templatedir: templates
77 cgi_wrapper: t/tmp/ikiwiki.cgi
80 # make it easier to test previewing
85 ENV: { 'PERL5LIB': 'blib/lib:blib/arch' }
90 sub thoroughly_rebuild {
91 ok(unlink("t/tmp/ikiwiki.cgi") || $!{ENOENT});
92 ok(! system("./ikiwiki.out --setup t/tmp/test.setup --rebuild --wrappers"));
95 sub check_cgi_mode_bits {
96 my (undef, undef, $mode, undef, undef,
97 undef, undef, undef, undef, undef,
98 undef, undef, undef) = stat("t/tmp/ikiwiki.cgi");
99 is($mode & 07777, 0754);
102 sub check_generated_content {
103 my $cgiurl_regex = shift;
104 ok(-e "t/tmp/out/a/b/c/index.html");
105 $content = readfile("t/tmp/out/a/b/c/index.html");
106 # no <base> on static HTML
107 unlike($content, qr{<base\W});
108 like($content, $cgiurl_regex);
109 # cross-links between static pages are relative
110 like($content, qr{<li>A: <a href="../../">a</a></li>});
111 like($content, qr{<li>B: <a href="../">b</a></li>});
112 like($content, qr{<li>E: <a href="../../d/e/">e</a></li>});
115 #######################################################################
116 # site 1: a perfectly ordinary ikiwiki
120 url => "http://example.com/wiki/",
121 cgiurl => "http://example.com/cgi-bin/ikiwiki.cgi",
123 thoroughly_rebuild();
124 check_cgi_mode_bits();
125 # url and cgiurl are on the same host so the cgiurl is host-relative
126 check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
128 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
129 $ENV{REQUEST_METHOD} = 'GET';
130 $ENV{SERVER_PORT} = '80';
131 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
132 $ENV{QUERY_STRING} = 'do=prefs';
133 $ENV{HTTP_HOST} = 'example.com';
135 %bits = parse_cgi_content($content);
136 is($bits{basehref}, "http://example.com/wiki/");
137 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
138 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
139 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
141 # when accessed via HTTPS, links are secure
142 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
143 $ENV{REQUEST_METHOD} = 'GET';
144 $ENV{SERVER_PORT} = '443';
145 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
146 $ENV{QUERY_STRING} = 'do=prefs';
147 $ENV{HTTP_HOST} = 'example.com';
150 %bits = parse_cgi_content($content);
151 is($bits{basehref}, "https://example.com/wiki/");
152 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
153 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
154 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
156 # when accessed via a different hostname, links stay on that host
157 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
158 $ENV{REQUEST_METHOD} = 'GET';
159 $ENV{SERVER_PORT} = '80';
160 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
161 $ENV{QUERY_STRING} = 'do=prefs';
162 $ENV{HTTP_HOST} = 'staging.example.net';
164 %bits = parse_cgi_content($content);
165 is($bits{basehref}, "http://staging.example.net/wiki/");
166 like($bits{stylehref}, qr{^(?:(?:http:)?//staging.example.net)?/wiki/style.css$});
167 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
168 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
171 $in = 'do=edit&page=a/b/c&Preview';
172 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
173 $ENV{REQUEST_METHOD} = 'POST';
174 $ENV{SERVER_PORT} = '80';
175 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
176 $ENV{HTTP_HOST} = 'example.com';
177 $ENV{CONTENT_LENGTH} = length $in;
179 %bits = parse_cgi_content($content);
180 is($bits{basehref}, "http://example.com/wiki/a/b/c/");
181 like($bits{stylehref}, qr{^(?:(?:http:)?//example.com)?/wiki/style.css$});
182 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
183 like($bits{cgihref}, qr{^(?:(?:http:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
185 # in html5, the <base> is allowed to be relative, and we take full
189 url => "http://example.com/wiki/",
190 cgiurl => "http://example.com/cgi-bin/ikiwiki.cgi",
192 thoroughly_rebuild();
193 check_cgi_mode_bits();
194 # url and cgiurl are on the same host so the cgiurl is host-relative
195 check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
197 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
198 $ENV{REQUEST_METHOD} = 'GET';
199 $ENV{SERVER_PORT} = '80';
200 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
201 $ENV{QUERY_STRING} = 'do=prefs';
202 $ENV{HTTP_HOST} = 'example.com';
204 %bits = parse_cgi_content($content);
205 is($bits{basehref}, "/wiki/");
206 is($bits{stylehref}, "/wiki/style.css");
207 is($bits{tophref}, "/wiki/");
208 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
210 # when accessed via HTTPS, links are secure - this is easy because under
211 # html5 they're independent of the URL at which the CGI was accessed
212 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
213 $ENV{REQUEST_METHOD} = 'GET';
214 $ENV{SERVER_PORT} = '443';
215 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
216 $ENV{QUERY_STRING} = 'do=prefs';
217 $ENV{HTTP_HOST} = 'example.com';
220 %bits = parse_cgi_content($content);
221 is($bits{basehref}, "/wiki/");
222 is($bits{stylehref}, "/wiki/style.css");
223 is($bits{tophref}, "/wiki/");
224 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
226 # when accessed via a different hostname, links stay on that host -
227 # this is really easy in html5 because we can use relative URLs
228 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
229 $ENV{REQUEST_METHOD} = 'GET';
230 $ENV{SERVER_PORT} = '80';
231 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
232 $ENV{QUERY_STRING} = 'do=prefs';
233 $ENV{HTTP_HOST} = 'staging.example.net';
235 %bits = parse_cgi_content($content);
236 is($bits{basehref}, "/wiki/");
237 is($bits{stylehref}, "/wiki/style.css");
238 is($bits{tophref}, "/wiki/");
239 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
242 $in = 'do=edit&page=a/b/c&Preview';
243 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
244 $ENV{REQUEST_METHOD} = 'POST';
245 $ENV{SERVER_PORT} = '80';
246 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
247 $ENV{HTTP_HOST} = 'example.com';
248 $ENV{CONTENT_LENGTH} = length $in;
250 %bits = parse_cgi_content($content);
251 is($bits{basehref}, "/wiki/a/b/c/");
252 is($bits{stylehref}, "/wiki/style.css");
253 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
254 is($bits{cgihref}, "/cgi-bin/ikiwiki.cgi");
256 #######################################################################
257 # site 2: static content and CGI are on different servers
261 url => "http://static.example.com/",
262 cgiurl => "http://cgi.example.com/ikiwiki.cgi",
264 thoroughly_rebuild();
265 check_cgi_mode_bits();
266 # url and cgiurl are not on the same host so the cgiurl has to be
267 # protocol-relative or absolute
268 check_generated_content(qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
270 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
271 $ENV{REQUEST_METHOD} = 'GET';
272 $ENV{SERVER_PORT} = '80';
273 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
274 $ENV{QUERY_STRING} = 'do=prefs';
275 $ENV{HTTP_HOST} = 'cgi.example.com';
277 %bits = parse_cgi_content($content);
278 like($bits{basehref}, qr{^http://static.example.com/$});
279 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com)?/style.css$});
280 like($bits{tophref}, qr{^(?:http:)?//static.example.com/$});
281 like($bits{cgihref}, qr{^(?:(?:http:)?//cgi.example.com)?/ikiwiki.cgi$});
283 # when accessed via HTTPS, links are secure
284 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
285 $ENV{REQUEST_METHOD} = 'GET';
286 $ENV{SERVER_PORT} = '443';
287 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
288 $ENV{QUERY_STRING} = 'do=prefs';
289 $ENV{HTTP_HOST} = 'cgi.example.com';
292 %bits = parse_cgi_content($content);
293 like($bits{basehref}, qr{^https://static.example.com/$});
294 like($bits{stylehref}, qr{^(?:(?:https:)?//static.example.com)?/style.css$});
295 like($bits{tophref}, qr{^(?:https:)?//static.example.com/$});
296 like($bits{cgihref}, qr{^(?:(?:https:)?//cgi.example.com)?/ikiwiki.cgi$});
298 # when accessed via a different hostname, links to the CGI (only) should
300 $in = 'do=edit&page=a/b/c&Preview';
301 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
302 $ENV{REQUEST_METHOD} = 'POST';
303 $ENV{SERVER_PORT} = '80';
304 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
305 $ENV{HTTP_HOST} = 'staging.example.net';
306 $ENV{CONTENT_LENGTH} = length $in;
308 %bits = parse_cgi_content($content);
309 like($bits{basehref}, qr{^http://static.example.com/a/b/c/$});
310 like($bits{stylehref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/style.css$});
311 like($bits{tophref}, qr{^(?:(?:http:)?//static.example.com|\.\./\.\./\.\.)/$});
312 like($bits{cgihref}, qr{^(?:(?:http:)?//(?:staging\.example\.net|cgi\.example\.com))?/ikiwiki.cgi$});
314 local $TODO = "use self-referential CGI URL?";
315 like($bits{cgihref}, qr{^(?:(?:http:)?//staging.example.net)?/ikiwiki.cgi$});
320 url => "http://static.example.com/",
321 cgiurl => "http://cgi.example.com/ikiwiki.cgi",
323 thoroughly_rebuild();
324 check_cgi_mode_bits();
325 # url and cgiurl are not on the same host so the cgiurl has to be
326 # protocol-relative or absolute
327 check_generated_content(qr{<a[^>]+href="(?:http:)?//cgi.example.com/ikiwiki.cgi\?do=prefs"});
329 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
330 $ENV{REQUEST_METHOD} = 'GET';
331 $ENV{SERVER_PORT} = '80';
332 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
333 $ENV{QUERY_STRING} = 'do=prefs';
334 $ENV{HTTP_HOST} = 'cgi.example.com';
336 %bits = parse_cgi_content($content);
337 is($bits{basehref}, "//static.example.com/");
338 is($bits{stylehref}, "//static.example.com/style.css");
339 is($bits{tophref}, "//static.example.com/");
340 is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
342 # when accessed via HTTPS, links are secure - in fact they're exactly the
343 # same as when accessed via HTTP
344 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
345 $ENV{REQUEST_METHOD} = 'GET';
346 $ENV{SERVER_PORT} = '443';
347 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
348 $ENV{QUERY_STRING} = 'do=prefs';
349 $ENV{HTTP_HOST} = 'cgi.example.com';
352 %bits = parse_cgi_content($content);
353 is($bits{basehref}, "//static.example.com/");
354 is($bits{stylehref}, "//static.example.com/style.css");
355 is($bits{tophref}, "//static.example.com/");
356 is($bits{cgihref}, "//cgi.example.com/ikiwiki.cgi");
358 # when accessed via a different hostname, links to the CGI (only) should
360 $in = 'do=edit&page=a/b/c&Preview';
361 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
362 $ENV{REQUEST_METHOD} = 'POST';
363 $ENV{SERVER_PORT} = '80';
364 $ENV{SCRIPT_NAME} = '/ikiwiki.cgi';
365 $ENV{HTTP_HOST} = 'staging.example.net';
366 $ENV{CONTENT_LENGTH} = length $in;
368 %bits = parse_cgi_content($content);
369 is($bits{basehref}, "//static.example.com/a/b/c/");
370 is($bits{stylehref}, "//static.example.com/style.css");
371 is($bits{tophref}, "../../../");
372 like($bits{cgihref}, qr{//(?:staging\.example\.net|cgi\.example\.com)/ikiwiki\.cgi});
374 local $TODO = "use self-referential CGI URL maybe?";
375 is($bits{cgihref}, "//staging.example.net/ikiwiki.cgi");
378 #######################################################################
379 # site 3: we specifically want everything to be secure
383 url => "https://example.com/wiki/",
384 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
386 thoroughly_rebuild();
387 check_cgi_mode_bits();
388 # url and cgiurl are on the same host so the cgiurl is host-relative
389 check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
391 # when accessed via HTTPS, links are secure
392 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
393 $ENV{REQUEST_METHOD} = 'GET';
394 $ENV{SERVER_PORT} = '443';
395 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
396 $ENV{QUERY_STRING} = 'do=prefs';
397 $ENV{HTTP_HOST} = 'example.com';
400 %bits = parse_cgi_content($content);
401 is($bits{basehref}, "https://example.com/wiki/");
402 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
403 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
404 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
406 # when not accessed via HTTPS, links should still be secure
407 # (but if this happens, that's a sign of web server misconfiguration)
408 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
409 $ENV{REQUEST_METHOD} = 'GET';
410 $ENV{SERVER_PORT} = '80';
411 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
412 $ENV{QUERY_STRING} = 'do=prefs';
413 $ENV{HTTP_HOST} = 'example.com';
415 %bits = parse_cgi_content($content);
416 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
418 local $TODO = "treat https in configured url, cgiurl as required?";
419 is($bits{basehref}, "https://example.com/wiki/");
420 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
422 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
424 # when accessed via a different hostname, links stay on that host
425 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
426 $ENV{REQUEST_METHOD} = 'GET';
427 $ENV{SERVER_PORT} = '443';
428 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
429 $ENV{QUERY_STRING} = 'do=prefs';
430 $ENV{HTTP_HOST} = 'staging.example.net';
433 %bits = parse_cgi_content($content);
434 is($bits{basehref}, "https://staging.example.net/wiki/");
435 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
436 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
437 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
440 $in = 'do=edit&page=a/b/c&Preview';
441 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
442 $ENV{REQUEST_METHOD} = 'POST';
443 $ENV{SERVER_PORT} = '443';
444 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
445 $ENV{HTTP_HOST} = 'example.com';
446 $ENV{CONTENT_LENGTH} = length $in;
449 %bits = parse_cgi_content($content);
450 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
451 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
452 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
453 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
455 # not testing html5: 0 here because that ends up identical to site 1
457 #######################################################################
458 # site 4 (NetBSD wiki): CGI is secure, static content doesn't have to be
462 url => "http://example.com/wiki/",
463 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
465 thoroughly_rebuild();
466 check_cgi_mode_bits();
467 # url and cgiurl are on the same host but different schemes
468 check_generated_content(qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
470 # when accessed via HTTPS, links are secure (to avoid mixed-content)
471 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
472 $ENV{REQUEST_METHOD} = 'GET';
473 $ENV{SERVER_PORT} = '443';
474 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
475 $ENV{QUERY_STRING} = 'do=prefs';
476 $ENV{HTTP_HOST} = 'example.com';
479 %bits = parse_cgi_content($content);
480 is($bits{basehref}, "https://example.com/wiki/");
481 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
482 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
483 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
485 # when not accessed via HTTPS, ???
486 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
487 $ENV{REQUEST_METHOD} = 'GET';
488 $ENV{SERVER_PORT} = '80';
489 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
490 $ENV{QUERY_STRING} = 'do=prefs';
491 $ENV{HTTP_HOST} = 'example.com';
493 %bits = parse_cgi_content($content);
494 like($bits{basehref}, qr{^https?://example.com/wiki/$});
495 like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
496 like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
497 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
499 # when accessed via a different hostname, links stay on that host
500 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
501 $ENV{REQUEST_METHOD} = 'GET';
502 $ENV{SERVER_PORT} = '443';
503 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
504 $ENV{QUERY_STRING} = 'do=prefs';
505 $ENV{HTTP_HOST} = 'staging.example.net';
508 %bits = parse_cgi_content($content);
509 # because the static and dynamic stuff is on the same server, we assume that
510 # both are also on the staging server
511 like($bits{basehref}, qr{^https://staging.example.net/wiki/$});
512 like($bits{stylehref}, qr{^(?:(?:https:)?//staging.example.net)?/wiki/style.css$});
513 like($bits{tophref}, qr{^(?:(?:(?:https:)?//staging.example.net)?/wiki|\.)/$});
514 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:staging\.example\.net|example\.com))?/cgi-bin/ikiwiki.cgi$});
516 local $TODO = "this should really point back to itself but currently points to example.com";
517 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
521 $in = 'do=edit&page=a/b/c&Preview';
522 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
523 $ENV{REQUEST_METHOD} = 'POST';
524 $ENV{SERVER_PORT} = '443';
525 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
526 $ENV{HTTP_HOST} = 'example.com';
527 $ENV{CONTENT_LENGTH} = length $in;
530 %bits = parse_cgi_content($content);
531 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
532 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
533 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
534 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
538 url => "http://example.com/wiki/",
539 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
541 thoroughly_rebuild();
542 check_cgi_mode_bits();
543 # url and cgiurl are on the same host but different schemes
544 check_generated_content(qr{<a[^>]+href="https://example.com/cgi-bin/ikiwiki.cgi\?do=prefs"});
546 # when accessed via HTTPS, links are secure (to avoid mixed-content)
547 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
548 $ENV{REQUEST_METHOD} = 'GET';
549 $ENV{SERVER_PORT} = '443';
550 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
551 $ENV{QUERY_STRING} = 'do=prefs';
552 $ENV{HTTP_HOST} = 'example.com';
555 %bits = parse_cgi_content($content);
556 is($bits{basehref}, "/wiki/");
557 is($bits{stylehref}, "/wiki/style.css");
558 is($bits{tophref}, "/wiki/");
559 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
561 # when not accessed via HTTPS, ???
562 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
563 $ENV{REQUEST_METHOD} = 'GET';
564 $ENV{SERVER_PORT} = '80';
565 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
566 $ENV{QUERY_STRING} = 'do=prefs';
567 $ENV{HTTP_HOST} = 'example.com';
569 %bits = parse_cgi_content($content);
570 like($bits{basehref}, qr{^(?:https?://example.com)?/wiki/$});
571 like($bits{stylehref}, qr{^(?:(?:https?:)?//example.com)?/wiki/style.css$});
572 like($bits{tophref}, qr{^(?:(?:https?://example.com)?/wiki|\.)/$});
573 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
575 # when accessed via a different hostname, links stay on that host
576 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
577 $ENV{REQUEST_METHOD} = 'GET';
578 $ENV{SERVER_PORT} = '443';
579 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
580 $ENV{QUERY_STRING} = 'do=prefs';
581 $ENV{HTTP_HOST} = 'staging.example.net';
584 %bits = parse_cgi_content($content);
585 # because the static and dynamic stuff is on the same server, we assume that
586 # both are also on the staging server
587 is($bits{basehref}, "/wiki/");
588 is($bits{stylehref}, "/wiki/style.css");
589 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
590 like($bits{cgihref}, qr{^(?:(?:https:)?//(?:example\.com|staging\.example\.net))?/cgi-bin/ikiwiki.cgi$});
592 local $TODO = "this should really point back to itself but currently points to example.com";
593 like($bits{cgihref}, qr{^(?:(?:https:)?//staging.example.net)?/cgi-bin/ikiwiki.cgi$});
597 $in = 'do=edit&page=a/b/c&Preview';
598 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
599 $ENV{REQUEST_METHOD} = 'POST';
600 $ENV{SERVER_PORT} = '443';
601 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
602 $ENV{HTTP_HOST} = 'example.com';
603 $ENV{CONTENT_LENGTH} = length $in;
606 %bits = parse_cgi_content($content);
607 is($bits{basehref}, "/wiki/a/b/c/");
608 is($bits{stylehref}, "/wiki/style.css");
609 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
610 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
612 # Deliberately not testing https static content with http cgiurl,
613 # because that makes remarkably little sense.
615 #######################################################################
616 # site 5: w3mmode, as documented in [[w3mmode]]
621 cgiurl => "ikiwiki.cgi",
624 thoroughly_rebuild();
625 check_cgi_mode_bits();
626 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
627 check_generated_content(qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
629 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
630 $ENV{REQUEST_METHOD} = 'GET';
631 $ENV{PATH_INFO} = '/ikiwiki.cgi';
632 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
633 $ENV{QUERY_STRING} = 'do=prefs';
635 %bits = parse_cgi_content($content);
636 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
637 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
638 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
639 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
644 cgiurl => "ikiwiki.cgi",
647 thoroughly_rebuild();
648 check_cgi_mode_bits();
649 # FIXME: does /$LIB/ikiwiki-w3m.cgi work under w3m?
650 check_generated_content(qr{<a[^>]+href="(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi\?do=prefs"});
652 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
653 $ENV{REQUEST_METHOD} = 'GET';
654 $ENV{PATH_INFO} = '/ikiwiki.cgi';
655 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki-w3m.cgi';
656 $ENV{QUERY_STRING} = 'do=prefs';
658 %bits = parse_cgi_content($content);
659 like($bits{tophref}, qr{^(?:\Q$pwd\E/t/tmp/out|\.)/$});
660 like($bits{cgihref}, qr{^(?:file://)?/\$LIB/ikiwiki-w3m.cgi/ikiwiki.cgi$});
661 like($bits{basehref}, qr{^(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out/$});
662 like($bits{stylehref}, qr{^(?:(?:(?:file:)?//)?\Q$pwd\E/t/tmp/out|\.)/style.css$});
664 #######################################################################
665 # site 6: we're behind a reverse-proxy
669 url => "https://example.com/wiki/",
670 cgiurl => "https://example.com/cgi-bin/ikiwiki.cgi",
673 thoroughly_rebuild();
674 check_cgi_mode_bits();
675 # url and cgiurl are on the same host so the cgiurl is host-relative
676 check_generated_content(qr{<a[^>]+href="/cgi-bin/ikiwiki.cgi\?do=prefs"});
678 # because we are behind a reverse-proxy we must assume that
679 # we're being accessed by the configured cgiurl
680 run(["./t/tmp/ikiwiki.cgi"], \undef, \$content, init => sub {
681 $ENV{REQUEST_METHOD} = 'GET';
682 $ENV{SERVER_PORT} = '80';
683 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
684 $ENV{QUERY_STRING} = 'do=prefs';
685 $ENV{HTTP_HOST} = 'localhost';
687 %bits = parse_cgi_content($content);
688 like($bits{tophref}, qr{^(?:/wiki|\.)/$});
689 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
690 is($bits{basehref}, "https://example.com/wiki/");
691 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
694 $in = 'do=edit&page=a/b/c&Preview';
695 run(["./t/tmp/ikiwiki.cgi"], \$in, \$content, init => sub {
696 $ENV{REQUEST_METHOD} = 'POST';
697 $ENV{SERVER_PORT} = '80';
698 $ENV{SCRIPT_NAME} = '/cgi-bin/ikiwiki.cgi';
699 $ENV{HTTP_HOST} = 'localhost';
700 $ENV{CONTENT_LENGTH} = length $in;
702 %bits = parse_cgi_content($content);
703 like($bits{tophref}, qr{^(?:/wiki|\.\./\.\./\.\.)/$});
704 like($bits{cgihref}, qr{^(?:(?:https:)?//example.com)?/cgi-bin/ikiwiki.cgi$});
705 is($bits{basehref}, "https://example.com/wiki/a/b/c/");
706 like($bits{stylehref}, qr{^(?:(?:https:)?//example.com)?/wiki/style.css$});
708 # not testing html5: 1 because it would be the same as site 1 -
709 # the reverse_proxy config option is unnecessary under html5