referrer_testserver.sjs (18695B)
1 /* 2 * Test server for iframe, anchor, and area referrer attributes. 3 * https://bugzilla.mozilla.org/show_bug.cgi?id=1175736 4 * Also server for further referrer tests such as redirecting tests 5 * bug 1174913, bug 1175736, bug 1184781 6 */ 7 8 const SJS = "referrer_testserver.sjs?"; 9 const SJS_PATH = "/tests/dom/security/test/referrer-policy/"; 10 const BASE_ORIGIN = "example.com"; 11 const BASE_URL = BASE_ORIGIN + SJS_PATH + SJS; 12 const SHARED_KEY = SJS; 13 const SAME_ORIGIN = "mochi.test:8888" + SJS_PATH + SJS; 14 const CROSS_ORIGIN_URL = "test1.example.com" + SJS_PATH + SJS; 15 const HSTS_URL = "includesubdomains.preloaded.test" + SJS_PATH + SJS; 16 17 const IMG_BYTES = atob( 18 "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + 19 "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" 20 ); 21 22 function createTestUrl( 23 aPolicy, 24 aAction, 25 aName, 26 aType, 27 aSchemeFrom, 28 aSchemeTo, 29 crossOrigin, 30 referrerPolicyHeader 31 ) { 32 var schemeTo = aSchemeTo || "http"; 33 var schemeFrom = aSchemeFrom || "http"; 34 var rpHeader = referrerPolicyHeader || ""; 35 var url = schemeTo + "://"; 36 url += crossOrigin ? CROSS_ORIGIN_URL : BASE_URL; 37 url += 38 "ACTION=" + 39 aAction + 40 "&" + 41 "policy=" + 42 aPolicy + 43 "&" + 44 "NAME=" + 45 aName + 46 "&" + 47 "type=" + 48 aType + 49 "&" + 50 "RP_HEADER=" + 51 rpHeader + 52 "&" + 53 "SCHEME_FROM=" + 54 schemeFrom; 55 return url; 56 } 57 58 // test page using iframe referrer attribute 59 // if aParams are set this creates a test where the iframe url is a redirect 60 function createIframeTestPageUsingRefferer( 61 aMetaPolicy, 62 aAttributePolicy, 63 aNewAttributePolicy, 64 aName, 65 aParams, 66 aSchemeFrom, 67 aSchemeTo, 68 aChangingMethod 69 ) { 70 var metaString = ""; 71 if (aMetaPolicy) { 72 metaString = `<meta name="referrer" content="${aMetaPolicy}">`; 73 } 74 var changeString = ""; 75 if (aChangingMethod === "setAttribute") { 76 changeString = `document.getElementById("myframe").setAttribute("referrerpolicy", "${aNewAttributePolicy}")`; 77 } else if (aChangingMethod === "property") { 78 changeString = `document.getElementById("myframe").referrerPolicy = "${aNewAttributePolicy}"`; 79 } 80 var iFrameString = `<iframe src="" id="myframe" ${ 81 aAttributePolicy ? ` referrerpolicy="${aAttributePolicy}"` : "" 82 }>iframe</iframe>`; 83 var iframeUrl = ""; 84 if (aParams) { 85 aParams.delete("ACTION"); 86 aParams.append("ACTION", "redirectIframe"); 87 iframeUrl = "http://" + CROSS_ORIGIN_URL + aParams.toString(); 88 } else { 89 iframeUrl = createTestUrl( 90 aAttributePolicy, 91 "test", 92 aName, 93 "iframe", 94 aSchemeFrom, 95 aSchemeTo 96 ); 97 } 98 99 return `<!DOCTYPE HTML> 100 <html> 101 <head> 102 ${metaString} 103 </head> 104 <body> 105 ${iFrameString} 106 <script> 107 window.addEventListener("load", function() { 108 ${changeString} 109 document.getElementById("myframe").onload = function(){ 110 parent.postMessage("childLoadComplete", "http://mochi.test:8888"); 111 }; 112 document.getElementById("myframe").src = "${iframeUrl}"; 113 }.bind(window), false); 114 </script> 115 </body> 116 </html>`; 117 } 118 119 function buildAnchorString( 120 aMetaPolicy, 121 aReferrerPolicy, 122 aName, 123 aRelString, 124 aSchemeFrom, 125 aSchemeTo 126 ) { 127 if (aReferrerPolicy) { 128 return `<a href="${createTestUrl( 129 aReferrerPolicy, 130 "test", 131 aName, 132 "link", 133 aSchemeFrom, 134 aSchemeTo 135 )}" referrerpolicy="${aReferrerPolicy}" id="link" ${aRelString}>${aReferrerPolicy}</a>`; 136 } 137 return `<a href="${createTestUrl( 138 aMetaPolicy, 139 "test", 140 aName, 141 "link", 142 aSchemeFrom, 143 aSchemeTo 144 )}" id="link" ${aRelString}>link</a>`; 145 } 146 147 function buildAreaString( 148 aMetaPolicy, 149 aReferrerPolicy, 150 aName, 151 aRelString, 152 aSchemeFrom, 153 aSchemeTo 154 ) { 155 var result = `<img src="file_mozfiledataurl_img.jpg" alt="image" usemap="#imageMap">`; 156 result += `<map name="imageMap">`; 157 if (aReferrerPolicy) { 158 result += `<area shape="circle" coords="1,1,1" href="${createTestUrl( 159 aReferrerPolicy, 160 "test", 161 aName, 162 "link", 163 aSchemeFrom, 164 aSchemeTo 165 )}" alt="theArea" referrerpolicy="${aReferrerPolicy}" id="link" ${aRelString}>`; 166 } else { 167 result += `<area shape="circle" coords="1,1,1" href="${createTestUrl( 168 aMetaPolicy, 169 "test", 170 aName, 171 "link", 172 aSchemeFrom, 173 aSchemeTo 174 )}" alt="theArea" id="link" ${aRelString}>`; 175 } 176 result += `</map>`; 177 178 return result; 179 } 180 181 // test page using anchor or area referrer attribute 182 function createAETestPageUsingRefferer( 183 aMetaPolicy, 184 aAttributePolicy, 185 aNewAttributePolicy, 186 aName, 187 aRel, 188 aStringBuilder, 189 aSchemeFrom, 190 aSchemeTo, 191 aChangingMethod 192 ) { 193 var metaString = ""; 194 if (aMetaPolicy) { 195 metaString = `<head><meta name="referrer" content="${aMetaPolicy}"></head>`; 196 } 197 var changeString = ""; 198 if (aChangingMethod === "setAttribute") { 199 changeString = `document.getElementById("link").setAttribute("referrerpolicy", "${aNewAttributePolicy}")`; 200 } else if (aChangingMethod === "property") { 201 changeString = `document.getElementById("link").referrerPolicy = "${aNewAttributePolicy}"`; 202 } 203 var relString = ""; 204 if (aRel) { 205 relString = `rel="noreferrer"`; 206 } 207 var elementString = aStringBuilder( 208 aMetaPolicy, 209 aAttributePolicy, 210 aName, 211 relString, 212 aSchemeFrom, 213 aSchemeTo 214 ); 215 216 return `<!DOCTYPE HTML> 217 <html> 218 ${metaString} 219 <body> 220 ${elementString} 221 <script> 222 window.addEventListener("load", function() { 223 ${changeString} 224 document.getElementById("link").click(); 225 }.bind(window), false); 226 </script> 227 </body> 228 </html>`; 229 } 230 231 // test page using anchor target=_blank rel=noopener 232 function createTargetBlankRefferer( 233 aMetaPolicy, 234 aName, 235 aSchemeFrom, 236 aSchemeTo, 237 aRpHeader 238 ) { 239 var metaString = ""; 240 if (aMetaPolicy) { 241 metaString = `<head><meta name="referrer" content="${aMetaPolicy}"></head>`; 242 } 243 var elementString = `<a href="${createTestUrl( 244 aMetaPolicy, 245 "test", 246 aName, 247 "link", 248 aSchemeFrom, 249 aSchemeTo, 250 aRpHeader 251 )}" target=_blank rel="noopener" id="link">link</a>`; 252 253 return `<!DOCTYPE HTML> 254 <html> 255 ${metaString} 256 <body> 257 ${elementString} 258 <script> 259 window.addEventListener("load", function() { 260 let link = document.getElementById("link"); 261 SpecialPowers.wrap(window).parent.postMessage("childLoadReady", "*"); 262 link.click(); 263 }.bind(window), false); 264 </script> 265 </body> 266 </html>`; 267 } 268 269 // creates test page with img that is a redirect 270 function createImgTestCase(aParams, aAttributePolicy, aRedirect) { 271 var metaString = ""; 272 if (aParams.has("META_POLICY")) { 273 metaString = `<meta name="referrer" content="${aParams.get( 274 "META_POLICY" 275 )}">`; 276 } 277 aParams.delete("ACTION"); 278 if (aRedirect) { 279 aParams.append("ACTION", "redirectImg"); 280 } else { 281 aParams.append("ACTION", "test"); 282 aParams.append("type", "img"); 283 } 284 var imgUrl = 285 "http://" + 286 (aParams.get("HSTS") ? HSTS_URL : CROSS_ORIGIN_URL) + 287 aParams.toString(); 288 289 return `<!DOCTYPE HTML> 290 <html> 291 <head> 292 <meta charset="utf-8"> 293 ${metaString} 294 <title>Test referrer policies on redirect (img)</title> 295 </head> 296 <body> 297 <img id="testImg" src="${imgUrl}" ${ 298 aAttributePolicy ? ` referrerpolicy="${aAttributePolicy}"` : "" 299 }> 300 <script> 301 window.addEventListener("load", function() { 302 parent.postMessage("childLoadComplete", "http://mochi.test:8888"); 303 }.bind(window), false); 304 </script> 305 </body> 306 </html>`; 307 } 308 309 // test page using link referrer attribute 310 function createLinkPageUsingRefferer( 311 aMetaPolicy, 312 aAttributePolicy, 313 aNewAttributePolicy, 314 aName, 315 aRel, 316 aStringBuilder, 317 aSchemeFrom, 318 aSchemeTo, 319 aTestType 320 ) { 321 var metaString = ""; 322 if (aMetaPolicy) { 323 metaString = `<meta name="referrer" content="${aMetaPolicy}">`; 324 } 325 326 var changeString = ""; 327 var policy = aAttributePolicy ? aAttributePolicy : aMetaPolicy; 328 var elementString = aStringBuilder( 329 policy, 330 aName, 331 aRel, 332 aSchemeFrom, 333 aSchemeTo, 334 aTestType 335 ); 336 337 if (aTestType === "setAttribute") { 338 changeString = `var link = document.getElementById("test_link"); 339 link.setAttribute("referrerpolicy", "${aNewAttributePolicy}"); 340 link.href = "${createTestUrl( 341 policy, 342 "test", 343 aName, 344 "link_element_" + aRel, 345 aSchemeFrom, 346 aSchemeTo 347 )}";`; 348 } else if (aTestType === "property") { 349 changeString = `var link = document.getElementById("test_link"); 350 link.referrerPolicy = "${aNewAttributePolicy}"; 351 link.href = "${createTestUrl( 352 policy, 353 "test", 354 aName, 355 "link_element_" + aRel, 356 aSchemeFrom, 357 aSchemeTo 358 )}";`; 359 } 360 361 return `<!DOCTYPE HTML> 362 <html> 363 <head> 364 ${metaString} 365 </head> 366 <body> 367 ${elementString} 368 <script> 369 ${changeString} 370 </script> 371 </body> 372 </html>`; 373 } 374 375 function createFetchUserControlRPTestCase( 376 aName, 377 aSchemeFrom, 378 aSchemeTo, 379 crossOrigin 380 ) { 381 var srcUrl = createTestUrl( 382 "", 383 "test", 384 aName, 385 "fetch", 386 aSchemeFrom, 387 aSchemeTo, 388 crossOrigin 389 ); 390 391 return `<!DOCTYPE HTML> 392 <html> 393 <head> 394 <meta charset="utf-8"> 395 <title>Test user control referrer policies</title> 396 </head> 397 <body> 398 <script> 399 fetch("${srcUrl}", {referrerPolicy: ""}).then(function (response) { 400 window.parent.postMessage("childLoadComplete", "http://mochi.test:8888"); 401 }); 402 </script> 403 </body> 404 </html>`; 405 } 406 407 function buildLinkString( 408 aPolicy, 409 aName, 410 aRel, 411 aSchemeFrom, 412 aSchemeTo, 413 aTestType 414 ) { 415 var href = ""; 416 var onChildComplete = `window.parent.postMessage("childLoadComplete", "http://mochi.test:8888");`; 417 var policy = ""; 418 var asString = ""; 419 var relString = ""; 420 421 if (aRel) { 422 relString = `rel="${aRel}"`; 423 } 424 425 if (aPolicy) { 426 policy = `referrerpolicy=${aPolicy}`; 427 } 428 429 if (aRel == "preload") { 430 asString = 'as="image"'; 431 } 432 433 if (!aTestType) { 434 href = `href=${createTestUrl( 435 aPolicy, 436 "test", 437 aName, 438 "link_element_" + aRel, 439 aSchemeFrom, 440 aSchemeTo 441 )}`; 442 } 443 444 return `<link ${relString} ${href} ${policy} ${asString} id="test_link" onload='${onChildComplete}' onerror='${onChildComplete}'>`; 445 } 446 // eslint-disable-next-line complexity 447 function handleRequest(request, response) { 448 var params = new URLSearchParams(request.queryString); 449 var action = params.get("ACTION"); 450 var schemeFrom = params.get("SCHEME_FROM") || "http"; 451 var schemeTo = params.get("SCHEME_TO") || "http"; 452 var crossOrigin = params.get("CROSS_ORIGIN") || false; 453 var referrerPolicyHeader = params.get("RP_HEADER") || ""; 454 455 response.setHeader("Access-Control-Allow-Origin", "*", false); 456 if (referrerPolicyHeader) { 457 response.setHeader("Referrer-Policy", referrerPolicyHeader, false); 458 } 459 460 if (action === "resetState") { 461 setSharedState(SHARED_KEY, "{}"); 462 response.write(""); 463 return; 464 } 465 if (action === "get-test-results") { 466 // ?action=get-result 467 response.setHeader("Cache-Control", "no-cache", false); 468 response.setHeader("Content-Type", "text/plain", false); 469 response.write(getSharedState(SHARED_KEY)); 470 return; 471 } 472 if (action === "redirect") { 473 response.write( 474 '<script>parent.postMessage("childLoadComplete", "http://mochi.test:8888");</script>' 475 ); 476 return; 477 } 478 if (action === "redirectImg") { 479 params.delete("ACTION"); 480 params.append("ACTION", "test"); 481 params.append("type", "img"); 482 // 302 found, 301 Moved Permanently, 303 See Other, 307 Temporary Redirect 483 response.setStatusLine("1.1", 302, "found"); 484 response.setHeader( 485 "Location", 486 "http://" + CROSS_ORIGIN_URL + params.toString(), 487 false 488 ); 489 return; 490 } 491 if (action === "redirectIframe") { 492 params.delete("ACTION"); 493 params.append("ACTION", "test"); 494 params.append("type", "iframe"); 495 // 302 found, 301 Moved Permanently, 303 See Other, 307 Temporary Redirect 496 response.setStatusLine("1.1", 302, "found"); 497 response.setHeader( 498 "Location", 499 "http://" + CROSS_ORIGIN_URL + params.toString(), 500 false 501 ); 502 return; 503 } 504 if (action === "test") { 505 // ?action=test&policy=origin&name=name 506 let policy = params.get("policy"); 507 let name = params.get("NAME"); 508 let type = params.get("type"); 509 let result = getSharedState(SHARED_KEY); 510 511 result = result ? JSON.parse(result) : {}; 512 513 var referrerLevel = "none"; 514 var test = {}; 515 if (request.hasHeader("Referer")) { 516 var referrer = request.getHeader("Referer"); 517 if (referrer.indexOf("referrer_testserver") > 0) { 518 referrerLevel = "full"; 519 } else if (referrer.indexOf(schemeFrom + "://example.com") == 0) { 520 referrerLevel = "origin"; 521 } else { 522 // this is never supposed to happen 523 referrerLevel = "other-origin"; 524 } 525 test.referrer = referrer; 526 } else { 527 test.referrer = ""; 528 } 529 test.policy = referrerLevel; 530 test.expected = policy; 531 532 result[name] = test; 533 534 setSharedState(SHARED_KEY, JSON.stringify(result)); 535 536 if (type === "img" || type == "link_element_preload") { 537 // return image 538 response.setHeader("Content-Type", "image/png"); 539 response.write(IMG_BYTES); 540 return; 541 } 542 if (type === "iframe") { 543 // return iframe page 544 response.write("<html><body>I am the iframe</body></html>"); 545 return; 546 } 547 if (type === "link") { 548 // forward link click to redirect URL to finish test 549 var loc = "http://" + BASE_URL + "ACTION=redirect"; 550 response.setStatusLine("1.1", 302, "Found"); 551 response.setHeader("Location", loc, false); 552 } 553 return; 554 } 555 556 response.setHeader("Cache-Control", "no-cache", false); 557 response.setHeader("Content-Type", "text/html; charset=utf-8", false); 558 559 // parse test arguments and start test 560 var attributePolicy = params.get("ATTRIBUTE_POLICY") || ""; 561 var newAttributePolicy = params.get("NEW_ATTRIBUTE_POLICY") || ""; 562 var metaPolicy = params.get("META_POLICY") || ""; 563 var rel = params.get("REL") || ""; 564 var name = params.get("NAME"); 565 566 // anchor & area 567 var _getPage = createAETestPageUsingRefferer.bind( 568 null, 569 metaPolicy, 570 attributePolicy, 571 newAttributePolicy, 572 name, 573 rel 574 ); 575 var _getAnchorPage = _getPage.bind( 576 null, 577 buildAnchorString, 578 schemeFrom, 579 schemeTo 580 ); 581 var _getAreaPage = _getPage.bind(null, buildAreaString, schemeFrom, schemeTo); 582 583 // aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod, aStringBuilder 584 if (action === "generate-anchor-policy-test") { 585 response.write(_getAnchorPage()); 586 return; 587 } 588 if (action === "generate-anchor-changing-policy-test-set-attribute") { 589 response.write(_getAnchorPage("setAttribute")); 590 return; 591 } 592 if (action === "generate-anchor-changing-policy-test-property") { 593 response.write(_getAnchorPage("property")); 594 return; 595 } 596 if (action === "generate-area-policy-test") { 597 response.write(_getAreaPage()); 598 return; 599 } 600 if (action === "generate-area-changing-policy-test-set-attribute") { 601 response.write(_getAreaPage("setAttribute")); 602 return; 603 } 604 if (action === "generate-area-changing-policy-test-property") { 605 response.write(_getAreaPage("property")); 606 return; 607 } 608 if (action === "generate-anchor-target-blank-policy-test") { 609 response.write( 610 createTargetBlankRefferer( 611 metaPolicy, 612 name, 613 schemeFrom, 614 schemeTo, 615 referrerPolicyHeader 616 ) 617 ); 618 return; 619 } 620 621 // iframe 622 _getPage = createIframeTestPageUsingRefferer.bind( 623 null, 624 metaPolicy, 625 attributePolicy, 626 newAttributePolicy, 627 name, 628 "", 629 schemeFrom, 630 schemeTo 631 ); 632 633 // aMetaPolicy, aAttributePolicy, aNewAttributePolicy, aName, aChangingMethod 634 if (action === "generate-iframe-policy-test") { 635 response.write(_getPage()); 636 return; 637 } 638 if (action === "generate-iframe-changing-policy-test-set-attribute") { 639 response.write(_getPage("setAttribute")); 640 return; 641 } 642 if (action === "generate-iframe-changing-policy-test-property") { 643 response.write(_getPage("property")); 644 return; 645 } 646 647 // redirect tests with img and iframe 648 if (action === "generate-img-redirect-policy-test") { 649 response.write(createImgTestCase(params, attributePolicy, true)); 650 return; 651 } 652 if (action === "generate-iframe-redirect-policy-test") { 653 response.write( 654 createIframeTestPageUsingRefferer( 655 metaPolicy, 656 attributePolicy, 657 newAttributePolicy, 658 name, 659 params, 660 schemeFrom, 661 schemeTo 662 ) 663 ); 664 return; 665 } 666 667 if (action === "generate-img-policy-test") { 668 response.write(createImgTestCase(params, attributePolicy, false)); 669 return; 670 } 671 672 _getPage = createLinkPageUsingRefferer.bind( 673 null, 674 metaPolicy, 675 attributePolicy, 676 newAttributePolicy, 677 name, 678 rel 679 ); 680 var _getLinkPage = _getPage.bind(null, buildLinkString, schemeFrom, schemeTo); 681 682 // link 683 if (action === "generate-link-policy-test") { 684 response.write(_getLinkPage()); 685 return; 686 } 687 if (action === "generate-link-policy-test-set-attribute") { 688 response.write(_getLinkPage("setAttribute")); 689 return; 690 } 691 if (action === "generate-link-policy-test-property") { 692 response.write(_getLinkPage("property")); 693 return; 694 } 695 696 if (action === "generate-fetch-user-control-policy-test") { 697 response.write( 698 createFetchUserControlRPTestCase(name, schemeFrom, schemeTo, crossOrigin) 699 ); 700 return; 701 } 702 703 response.write("I don't know action " + action); 704 }