Created
May 21, 2017 13:51
-
-
Save kakarukeys/5381f3975674d81ba37d3bee4cd415a1 to your computer and use it in GitHub Desktop.
solution2 - URI comparison
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function parseURI(uri) { | |
| /* parse <uri> into invidual components (loosely, some errors allowed) */ | |
| // see https://regex101.com/r/l96l7F/1 for explanation | |
| var regex = /(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/\/?)?(?:(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?((?:\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?[^?#\/]*)(?:\?([^#]*))?(?:#(.*))?/, | |
| groupNames = [ | |
| "fullMatch", | |
| "scheme", | |
| "username", | |
| "password", | |
| "host", | |
| "port", | |
| "path", | |
| "query", | |
| "fragment" | |
| ], | |
| result = regex.exec(uri), | |
| uriObj = {}; | |
| for (var i = 0; i < result.length; i++) { | |
| uriObj[groupNames[i]] = result[i] || ''; | |
| } | |
| return uriObj; | |
| } | |
| function parsePath(path) { | |
| /* return an array of invidual components in <path> */ | |
| var resolved = [], | |
| pieces = path.split('/'), | |
| token; | |
| for (var i = 0; i < pieces.length; i++) { | |
| token = decodeURIComponent(pieces[i]); | |
| if (token && token !== '.' && token !== "..") { | |
| resolved.push(token); | |
| } else { | |
| if (token === '..') { | |
| resolved.pop(); | |
| } | |
| if (i === pieces.length - 1) { | |
| // last token, push a blank string representing a trailing slash | |
| resolved.push(''); | |
| } | |
| } | |
| } | |
| return resolved; | |
| } | |
| function parseQuery(query) { | |
| /* return an array of name, values pair from <query> ordered by name */ | |
| var resolvedMap = {}, | |
| resolvedArr = [], | |
| pieces = query.split('&'), | |
| token, name, value; | |
| for (var i = 0; i < pieces.length; i++) { | |
| token = pieces[i].split('='); | |
| name = decodeURIComponent(token[0]); | |
| value = decodeURIComponent(token[1] || ''); | |
| if (!resolvedMap[name]) { | |
| resolvedMap[name] = []; | |
| resolvedArr.push([name, resolvedMap[name]]); | |
| } | |
| resolvedMap[name].push(value); | |
| } | |
| return resolvedArr.sort(); | |
| } | |
| function checkURIs(uri1, uri2) { | |
| /* return whether <uri1> and <uri2> are equivalent */ | |
| if (uri1 === uri2) { | |
| return true; | |
| } | |
| var uriObj1 = parseURI(uri1), | |
| uriObj2 = parseURI(uri2), | |
| protocol1 = uriObj1.scheme.toUpperCase() || "HTTP", | |
| protocol2 = uriObj2.scheme.toUpperCase() || "HTTP"; | |
| if (protocol1 != "HTTP" || protocol2 != "HTTP") { | |
| throw new RangeError("Comparison involving non-http URI is not yet supported."); | |
| } | |
| return protocol1 === protocol2 && | |
| decodeURIComponent(uriObj1.username) === decodeURIComponent(uriObj2.username) && | |
| decodeURIComponent(uriObj1.password) === decodeURIComponent(uriObj2.password) && | |
| uriObj1.host.toUpperCase() === uriObj2.host.toUpperCase() && | |
| (uriObj1.port || "80") === (uriObj2.port || "80") && | |
| decodeURIComponent(uriObj1.fragment) === decodeURIComponent(uriObj2.fragment) && | |
| JSON.stringify(parsePath(uriObj1.path)) === JSON.stringify(parsePath(uriObj2.path)) && | |
| JSON.stringify(parseQuery(uriObj1.query)) === JSON.stringify(parseQuery(uriObj2.query)); | |
| } | |
| /* unit tests */ | |
| try { | |
| checkURIs( | |
| "http://username:[email protected]/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "ftp://username:[email protected]/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash") | |
| checkURIs( | |
| "https://username:[email protected]/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash") | |
| console.assert(false, "compare with non-http URI") | |
| } catch (e) { | |
| if (!(e instanceof RangeError)) { | |
| console.assert(false, "compare with non-http URI") | |
| } | |
| } | |
| var testData = [ | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "exactly equal"], | |
| ["hTtP://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "HtTp://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "scheme name case-insensitive"], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "//username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "protocol-relative URI"], | |
| ["http://john:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://John:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "username", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "password", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "host name case-insensitive"], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "host name", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "default port"], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:8000/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "port", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#Hash", "fragment", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1", "fragment", false], | |
| ["http://username:[email protected]:80?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/?a=3&b=4&a=1#hash", "path (root)"], | |
| ["http://username:[email protected]:80/?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/abc?a=3&b=4&a=1#hash", "path", false], | |
| ["http://username:[email protected]:80/abc?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/abc/?a=3&b=4&a=1#hash", "path (trailing slash)", false], | |
| ["http://username:[email protected]:80/abc/?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/abc/def.html?a=3&b=4&a=1#hash", "path", false], | |
| ["http://username:[email protected]:80/abc/def.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/abc/def.html/?a=3&b=4&a=1#hash", "path (trailing slash)", false], | |
| ["http://username:[email protected]:80/users/../../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/temp/%7Esmith/home.html?a=3&b=4&a=1#hash", " path traversal"], | |
| ["http://username:[email protected]:80/abc/def/.?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/abc/def/?a=3&b=4&a=1#hash", " path traversal (trailing dot)"], | |
| ["http://username:[email protected]:80/abc/def/..?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/abc/?a=3&b=4&a=1#hash", " path traversal (trailing dot dot)"], | |
| ["http://username:[email protected]:80//users///..//temp////.//%7Esmith////home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "path (loose matching)"], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&c=4&a=1#hash", "query name diff", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=9&a=1#hash", "query value diff", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1&b=5#hash", "query extra value", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?b=4&a=3&a=1#hash", "query name ordering"], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=1&b=4&a=3#hash", "query value ordering", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b&a=1#hash", "query missing value"], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=null&a=1#hash", "query missing value", false], | |
| ["http://user%[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://user:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "URI encoding (username) (reserved char)", false], | |
| ["http://user%[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "URI encoding (username) (unreserved char)"], | |
| ["http://username:passwd%[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", "URI encoding (password)"], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith%2Fhome.html?a=3&b=4&a=1#hash", "URI encoding (path) (reserved char)", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith%40/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./~smith@/home.html?a=3&b=4&a=1#hash", "URI encoding (path)"], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4%26a=1#hash", "URI encoding (query) (reserved char)", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=foo?bar~#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=foo%3Fbar%7E#hash", "URI encoding (query)"], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#hash", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1%23hash", "URI encoding (fragment) (reserved char)", false], | |
| ["http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#:hash~", | |
| "http://username:[email protected]:80/users/../temp/./%7Esmith/home.html?a=3&b=4&a=1#%3Ahash%7E", "URI encoding (fragment)"], | |
| ["http://www.zendesk.com/product/pricing/", | |
| "http://www.zendesk.com/support/", "common URL without many components", false], | |
| ], d; | |
| for (var i = 0; i < testData.length; i++) { | |
| d = testData[i]; | |
| if (d[3] === false) { | |
| console.assert(!checkURIs(d[0], d[1]), d[2]); | |
| console.assert(!checkURIs(d[1], d[0]), d[2] + " (args reversed)"); | |
| } else { | |
| console.assert(checkURIs(d[0], d[1]), d[2]); | |
| console.assert(checkURIs(d[1], d[0]), d[2] + " (args reversed)"); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment