<!DOCTYPE html> <html> <head> <title>app:URI compliance tests</title> <script src='/resources/testharness.js'></script> <script src='/resources/testharnessreport.js'></script> <link rel="help" href="http://app-uri.sysapps.org/" data-tested-assertations="following::OL[1]/LI[2]" /> <style> div {padding:5px 5px 10px 5px;} </style> </head> <body> <div id="logs"></div> <div id="log"></div> <script> /********************************************************************************************** * This test suite checks your implementation for compliance with the app-URI specification * **********************************************************************************************/ /* Check if protocol is "app" */ if (window.location.protocol === "app:") { /* Logging current domain */ var domain = window.location.protocol + "//" + window.location.host + "/"; document.getElementById("logs").innerHTML = "Current domain: " + domain; /* Function that will change HOST value if it is equal to currect application host */ function ChangeHostIfEqCurrent(URI){ /* Check if URI host is NOT the same as current application host */ if (URI.substring(6, 35) === window.location.host) { if (URI.substring(6, 7) !== 4) URI = URI.replace(URI.substring(6, 7), "4"); else URI = URI.replace(URI.substring(6, 7), "5"); } return URI; } /******************************************************** * 6.1 Synthesizing an app: URI * * link: http://app-uri.sysapps.org/#synthesizing * ********************************************************/ /** * Syntax-Based Normalization * * rules for dereferencing an app: URI => 3. Let URI be the value of the [HTTP] Request URI. */ var TC_name = "Test: Synthesizing an app:URI. Syntax-Based Normalization"; // variable needed to test scheme-based normalization var tmp_domain = window.location.protocol + "//" + window.location.host; var CaseNormalizationXHRtests = [ /* scheme: [ TC name, URI] */ [TC_name + " XHR full path: {} => %7b%7d", domain + 'resources/ExamPLE/%7bmY%7d/z...z/index.html'], [TC_name + " XHR full path: } => %7D", domain + 'resources/ExamPLE/%7bmY%7D/z...z/index.html'], [TC_name + " XHR full path: {} => %7B%7D", domain + 'resources/ExamPLE/%7BmY%7D/z...z/index.html'], [TC_name + " XHR full path: Capital letters in patch", domain + 'resources/ExamPLE/mmY/index.html'], [TC_name + " XHR relative path: {} => %7b%7d", 'resources/ExamPLE/%7bmY%7d/z...z/index.html'], [TC_name + " XHR relative path: } => %7D", 'resources/ExamPLE/%7bmY%7D/z...z/index.html'], [TC_name + " XHR relative path: P. => %50%2e", 'resources/Exam%50LE/%7bmY%7d/z%2e..z/index.html'], [TC_name + " XHR relative path: Capital letters in patch", 'resources/ExamPLE/mmY/index.html'], [TC_name + " XHR relative path: ~ => ~", 'resources/ImaGes/~t/{!a}/~sth.png'], [TC_name + " XHR relative path: ~{} => ~%7b%7d", 'resources/ImaGes/~t/%7b!a%7d/~sth.png'], /* Percent-Encoding Normalization*/ [TC_name + " Percent-Encoding Normalization - XHR full path: c. => %63%2e", domain + 'resources/ExamPLE/%7bmY%7d/z%2e..z/index.html'], [TC_name + " Percent-Encoding Normalization - XHR full path: P. => %50%2e", domain + 'resources/Exam%50LE/%7bmY%7d/z%2e..z/index.html'], [TC_name + " Percent-Encoding Normalization - XHR relative path: {} => %7B%7D", 'resources/ExamPLE/%7BmY%7D/z...z/index.html'], [TC_name + " Percent-Encoding Normalization - XHR relative path: c. => %63%2e", 'resources/ExamPLE/%7bmY%7d/z%2e..z/index.html'], [TC_name + " XHR relative path: ~{} => ~%7b%7d", 'resources/ImaGes/~t/%7b!a%7d/~sth.png'], /* Path Segment Normalization */ [TC_name + " Path Segment Normalization: using '../..' in path ", 'resources/ExamPLE/mmY/../../ImaGes/~t/%7b!a%7d/~sth.png'], /* Scheme-Based Normalization */ [TC_name + " Scheme-Based Normalization: domain:/", tmp_domain + ':/resources/ImaGes/~t/%7b!a%7d/~sth.png'] ]; CaseNormalizationXHRtests.forEach(function (data, i) { var name = data[0]; var URI = data[1]; var xhrTest = async_test(name + " [case " + i + "]"); var xhr; xhrTest.step(function () { xhr = new XMLHttpRequest(); xhr.open("GET", URI, true); xhr.onreadystatechange = xhrTest.step_func(function (ev) { if (xhr.readyState === 4 && xhr.status === 200) { assert_true(true); xhrTest.done(); } if (xhr.readyState !== 4 && xhr.status !== 200 && xhr.status !== 0) { assert_true(false, "[ Error: readyState=" + xhr.readyState + " satus=" + xhr.status + "] "); } }); xhr.send(); }); delete name, URI, xhr, xhrTest; }); delete CaseNormalizationXHRtests; /** * ContentType response * * rules for dereferencing an app: URI => 8. Let potential-file be the result of attempting locate the file at path */ TC_name = "Test: [HTTP] 200 response status (OK),value of content-type as the [HTTP] "; TC_name += "Content-Type header, and the contents of potential-file as the response body"; var ContentTypeResponsetests = [ /* scheme:[ TC name, URI, content-type] */ [TC_name + ' [text/html]', 'resources/ExamPLE/mmY/index.html', 'text/html'], [TC_name + " [image/png]", 'resources/ImaGes/~t/%7b!a%7d/~sth.png', "image/png"], [TC_name + " [text/plain]", 'resources/ExamPLE/mmY/sth.txt', "text/plain"] ]; ContentTypeResponsetests.forEach(function (data, i) { var name = data[0]; var URI = data[1]; var content_type = data[2]; var xhrTest = async_test(name + " [case " + i + "]"); var xhr; xhrTest.step(function () { xhr = new XMLHttpRequest(); xhr.open("GET", URI, true); xhr.onreadystatechange = xhrTest.step_func(function (ev) { if (xhr.readyState === 4 && xhr.status === 200) { assert_true(xhr.getResponseHeader("Content-Type") === content_type, "[Content-Type does not mach with expected, it is: " + xhr.getResponseHeader("Content-Type") + "]"); xhrTest.done(); } if (xhr.readyState !== 4 && xhr.status !== 200 && xhr.status !== 0) { assert_true(false, "[ Error: readyState=" + xhr.readyState + " satus=" + xhr.status + "] "); } }); xhr.send(); }); delete name, URI, xhr, xhrTest, content_type; }); delete ContentTypeResponsetests; /** * Case Normalization in Path * * rules for dereferencing an app: URI => 4. Resolve URI into an absolute URL using the document's origin as the base. * rules for dereferencing an app: URI => 7. Let path be the path component of URI. * * Character Normalization in domain name */ TC_name = "Test: Synthesizing an app:URI. Syntax-Based Normalization: Case Normalization"; var PathCaseNormalizationtests = [ /* scheme: [ TC name, URI] */ [TC_name, "resources/ImaGes/{{a}}/Test_1/$a/sth34!.png", domain + "resources/ImaGes/%7B%7Ba%7D%7D/Test_1/$a/sth34!.png", true], [TC_name, "resources/ImaGes/{{a}}/Test_1/$a/sth34!.png", domain + "resources/ImaGes/%7b%7Ba%7D%7D/Test_1/$a/sth34!.png", false], /* Character Normalization in Domain */ [TC_name, window.location.protocol + "//" + window.location.host.toUpperCase() + "/resources/ImaGes/{{a}}/Test_1/$a/sth34!.png", domain + "resources/ImaGes/%7B%7Ba%7D%7D/Test_1/$a/sth34!.png", true] ]; PathCaseNormalizationtests.forEach(function (data, i) { var name = data[0]; var elem_path = data[1]; var path_expected = data[2]; var expected = data[3]; test(function () { var img = document.createElement("img"); img.src = elem_path; if (expected) assert_true(img.src === path_expected, "[Error, path=" + img.src + " Expected=" + domain + path_expected + "]"); else assert_false(img.src === path_expected, "[Error, path=" + img.src + " Expected=" + domain + path_expected + "]"); delete img; }, name + " [case " + i + "]"); delete elem_path, path_expected, expected, name; }); delete PathCaseNormalizationtests; /******************************************************************************************** * 6.4 Dereferencing and retrieval of files from a container * * link: http://app-uri.sysapps.org/#dereferencing-and-retrieval-of-files-from-a-container * ********************************************************************************************/ /** * 501 Method Not Implemented error - response body MUST be empty * * rules for dereferencing an app: URI => 1. If the request is not a [HTTP] GET request, return a [HTTP] 501 Not Implemented response and terminate this algorithm. */ function Get_501_reponse(name, URI, expected_response) { var xhrTest = async_test(name); xhrTest.step(function () { var xhr = new XMLHttpRequest(); /* on purpose wrong method "gett" instead of "get" was used */ xhr.open("gett", URI, true); xhr.onreadystatechange = xhrTest.step_func(function (ev) { if (xhr.readyState !== 4 && xhr.status === 501) { assert_true(xhr.response === expected_response, "[" + xhr.status + " error, response:[" + xhr.response + "] " + "]"); xhrTest.done(); } if (xhr.readyState === 4 && xhr.status === 200) { assert_true(false, "[Should get 501 but got 200 OK, " +"file found while it should not find it, " +" non existing 'gett' method used"); } }); xhr.send(); }); delete xhrTest; } Get_501_reponse(TC_name + " 501 Method Not Implemented error expected", 'resources/ExamPLE/mmY/index.html', ""); /** * 400 Bad Request error - response body MUST be empty * * rules for dereferencing an app: URI => 5. If the URI does not conform to the appuri ABNF, return a [HTTP] 400 Bad Request response and terminate this algorithm. */ function Get_400_reponse(name, URI, expected_response) { var xhrTest = async_test(name); xhrTest.step(function () { var xhr = new XMLHttpRequest(); //alert(URI); xhr.open("GET", URI, true); xhr.onreadystatechange = xhrTest.step_func(function (ev) { if (xhr.readyState !== 4 && xhr.status === 400) { assert_true(xhr.response === expected_response, "[" + xhr.status + " error, response:[" + xhr.response + "] " + "]"); xhrTest.done(); } if (xhr.readyState === 4 && xhr.status === 200) { assert_true(false, "[Should get 400 but got 200 OK, " +"file found while it should not find it, " +"since no specific file requested]"); } }); xhr.send(); }); delete xhrTest; } Get_400_reponse(TC_name + " 400 Method Not Implemented error expected, no path", tmp_domain, ""); Get_400_reponse(TC_name + " 400 Method Not Implemented error expected, different domain with no path", ChangeHostIfEqCurrent("app://f15a6d20-cefa-13e5-1972-800e20d19a76"), ""); /** * 403 Forbidden error - response body MUST be empty * * rules for dereferencing an app: URI => 6. If the URI uses the scheme 'app', but the authority does not match the one assigned to this document, return a [HTTP] 403 Forbidden response and terminate this algorithm (i.e., prevent inter-application content access). */ function Get_403_reponse(name, URI, expected_response) { var xhrTest = async_test(name); xhrTest.step(function () { /* Change if URI host is the same as current application host */ URI = ChangeHostIfEqCurrent(URI); var xhr = new XMLHttpRequest(); xhr.open("GET", URI, true); xhr.onreadystatechange = xhrTest.step_func(function (ev) { if (xhr.readyState === 4 && xhr.status === 200) { assert_true(false, "[403 error expected, got: 200 OK instead]"); } if (xhr.readyState !== 4 && xhr.status === 403) { assert_true(xhr.response === expected_response, "[" + xhr.status + " error, response:[" + xhr.response + "] " + "]"); xhrTest.done(); } }); xhr.send(); }); } Get_403_reponse(TC_name + " Access to restricted URI - 403 Forbidden error expected", window.location.protocol + "//f15a6d20-cefa-13e5-1972-800e20d19a76/" + 'resources/ExamPLE/mmY/index.html', ""); /** * 404 Not Found error - response body MUST be empty * * rules for dereferencing an app: URI => 9. If potential-file is not found at the given path inside the container, return a [HTTP] 404 Not Found response. */ TC_name = "Test: 6.4 Dereferencing and retrieval of files from a container"; var CompareResponseBodytests = [ /* scheme: [TC name, URI, expected_response]*/ [TC_name + " 404 Not Found error expected", 'resources/ImaGes/~t/%7b!a%7d/~sth11.png', ""] ]; CompareResponseBodytests.forEach(function (data, i) { var name = data[0]; var URI = data[1]; var expected_response = data[2]; var xhrTest = async_test(name); var xhr; xhrTest.step(function () { xhr = new XMLHttpRequest(); xhr.open("GET", URI, true); xhr.onreadystatechange = xhrTest.step_func(function (ev) { if (xhr.readyState !== 4 && xhr.status === 404) { assert_true(xhr.response === expected_response, "[" + xhr.status + " error, response:[" + xhr.response + "] " + "]"); xhrTest.done(); } if (xhr.readyState === 4 && xhr.status === 200) { assert_true(false, "[404 error expected, got: 200 OK instead]"); } }); xhr.send(); }); delete xhrTest, xhr; }); delete CompareResponseBodytests; } else { document.getElementById("logs").innerHTML = "This is a test suite for app protocol only. Test aborted due to current protocol " + window.location.protocol; } </script> </body> </html>