| <!DOCTYPE html> |
| <html> |
| <head> |
| <title>app:URI compliance tests</title> |
| <script src='resources/testharness.js'></script> |
| <script src='resources/testharnessreport.js'></script> |
| <link rel='stylesheet' href='resource/testharness.css'> |
| <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> |
| |
| |
| |