From 9feb3f4eb66dada79e5c2034c1bb0c8f4faf47de Mon Sep 17 00:00:00 2001 From: Martin Blom Date: Sat, 10 Oct 2015 19:40:35 +0200 Subject: [PATCH] Rewrite parseUri to handle unusual but valid URI characters. It drops support for the 'directory' and 'file' properties, but should otherwise be equivalent to the original version. --- lib/browser.js | 23 +++++++++++++---------- test/browser.js | 27 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/lib/browser.js b/lib/browser.js index 7ccacf6..17f7a52 100755 --- a/lib/browser.js +++ b/lib/browser.js @@ -584,20 +584,23 @@ hawk.utils = { }, parseUri: function (input) { + // From RFC 3986 (except for some groups being non-capturing and two extra groups for 'resource' and 'relative') + var uriRegex = /^(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?((([^?#]*)(?:\?([^#]*))?)(?:#(.*))?)/; + var uriKeys = ['source', 'protocol', 'authority', 'resource', 'relative', 'pathname', 'query', 'fragment']; + var authRegex = /^(?:(([^:@]*)(?::([^@]*))?)@)?(\[[^\]]*\]|[^:]*)(?::(\d*))?/; + var authKeys = ['authority', 'userInfo', 'user', 'password', 'hostname', 'port']; + var uri = {}, i; - // Based on: parseURI 1.2.2 - // http://blog.stevenlevithan.com/archives/parseuri - // (c) Steven Levithan - // MIT License + var parts = uriRegex.exec(input); - var keys = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'hostname', 'port', 'resource', 'relative', 'pathname', 'directory', 'file', 'query', 'fragment']; + for (i = 0; i < parts.length; ++i) { + uri[uriKeys[i]] = parts[i] || ''; + } - var uriRegex = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?(((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?)(?:#(.*))?)/; - var uriByNumber = input.match(uriRegex); - var uri = {}; + parts = authRegex.exec(uri['authority']); - for (var i = 0, il = keys.length; i < il; ++i) { - uri[keys[i]] = uriByNumber[i] || ''; + for (i = 0; i < parts.length; ++i) { + uri[authKeys[i]] = parts[i] || ''; } if (uri.port === '') { diff --git a/test/browser.js b/test/browser.js index 49dc4ca..8ca6ca3 100755 --- a/test/browser.js +++ b/test/browser.js @@ -1442,6 +1442,33 @@ describe('Browser', function () { expect(uri.port).to.equal('80'); done(); }); + + it('handles unusual characters correctly', function (done) { + var parts = { + protocol: 'http+vnd.my-extension', + user: 'user!$&\'()*+,;=%40my-domain.com', + password: 'pass!$&\'()*+,;=%40:word', + hostname: 'foo-bar.com', + port: '99', + pathname: '/path/%40/!$&\'()*+,;=:@/', + query: 'query%40/!$&\'()*+,;=:@/?', + fragment: 'fragm%40/!$&\'()*+,;=:@/?' + }; + + parts.userInfo = parts.user + ':' + parts.password; + parts.authority = parts.userInfo + '@' + parts.hostname + ':' + parts.port; + parts.relative = parts.pathname + '?' + parts.query; + parts.resource = parts.relative + '#' + parts.fragment; + parts.source = parts.protocol + '://' + parts.authority + parts.resource; + + var uri = Browser.utils.parseUri(parts.source); + + for (var part in parts) { + expect(uri[part]).to.equal(parts[part]); + } + + done(); + }); }); var str = 'https://www.google.ca/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=url';