This repository has been archived by the owner on Apr 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(input): fix URL validation being too strict
Background: Prior to ffb6b2f, there was a bug in `URL_REGEXP`, trying to match the hostname as `\S+` (meaning any non-space character). This resulted in never actually validating the structure of the URL (e.g. segments such as port, path, query, fragment). Then ffb6b2f and subsequently e4bb838 fixed that bug, but revealed `URL_REGEXP`'s "strictness" wrt certain parts of the URL. Since browsers are too lenient when it comes to URL validation anyway, it doesn't make sense for Angular to be much stricter, so this commit relaxes the "strictness" of `URL_REGEXP`, focusing more on the general structure, than on the specific characters allowed in each segment. Note 1: `URL_REGEXP` still seems to be stricter than browsers in some cases. Note 2: Browsers don't always agree on what is a valid URL and what isn't. Fixes #13528
- Loading branch information
Showing
2 changed files
with
121 additions
and
17 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2535,22 +2535,115 @@ describe('input', function() { | |
|
||
|
||
describe('URL_REGEXP', function() { | ||
/* global URL_REGEXP: false */ | ||
it('should validate url', function() { | ||
// See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987) | ||
expect(URL_REGEXP.test('http://server:123/path')).toBe(true); | ||
expect(URL_REGEXP.test('https://server:123/path')).toBe(true); | ||
expect(URL_REGEXP.test('file:///home/user')).toBe(true); | ||
expect(URL_REGEXP.test('mailto:[email protected]?subject=Foo')).toBe(true); | ||
expect(URL_REGEXP.test('r2-d2.c3-p0://localhost/foo')).toBe(true); | ||
expect(URL_REGEXP.test('abc:/foo')).toBe(true); | ||
expect(URL_REGEXP.test('http://example.com/path;path')).toBe(true); | ||
expect(URL_REGEXP.test('http://example.com/[]$\'()*,~)')).toBe(true); | ||
expect(URL_REGEXP.test('http:')).toBe(false); | ||
expect(URL_REGEXP.test('[email protected]')).toBe(false); | ||
expect(URL_REGEXP.test('a_B.c')).toBe(false); | ||
expect(URL_REGEXP.test('0scheme://example.com')).toBe(false); | ||
expect(URL_REGEXP.test('http://example.com:9999/``')).toBe(false); | ||
// See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987) | ||
// Note: We are being more lenient, because browsers are too. | ||
var urls = [ | ||
['scheme://hostname', true], | ||
['scheme://username:[email protected]:7678/pa/t.h?q=u&e=r&y#fragment', true], | ||
|
||
// Validating `scheme` | ||
['://example.com', false], | ||
['0scheme://example.com', false], | ||
['.scheme://example.com', false], | ||
['+scheme://example.com', false], | ||
['-scheme://example.com', false], | ||
['_scheme://example.com', false], | ||
['scheme0://example.com', true], | ||
['scheme.://example.com', true], | ||
['scheme+://example.com', true], | ||
['scheme-://example.com', true], | ||
['scheme_://example.com', false], | ||
|
||
// Vaidating `:` and `/` after `scheme` | ||
['scheme//example.com', false], | ||
['scheme:example.com', true], | ||
['scheme:/example.com', true], | ||
['scheme:///example.com', true], | ||
|
||
// Validating `username` and `password` | ||
['scheme://@example.com', true], | ||
['scheme://[email protected]', true], | ||
['scheme://[email protected]', true], | ||
['scheme://u#s$e%r^n&a*m;[email protected]', true], | ||
['scheme://:[email protected]', true], | ||
['scheme://username:[email protected]', true], | ||
['scheme://username:pass:[email protected]', true], | ||
['scheme://username:[email protected]', true], | ||
['scheme://username:p#a$s%s^w&o*r;[email protected]', true], | ||
|
||
// Validating `hostname` | ||
['scheme:', false], // Chrome, FF: true | ||
['scheme://', false], // Chrome, FF: true | ||
['scheme:// example.com:', false], // Chrome, FF: true | ||
['scheme://example com:', false], // Chrome, FF: true | ||
['scheme://:', false], // Chrome, FF: true | ||
['scheme://?', false], // Chrome, FF: true | ||
['scheme://#', false], // Chrome, FF: true | ||
['scheme://username:password@:', false], // Chrome, FF: true | ||
['scheme://username:password@/', false], // Chrome, FF: true | ||
['scheme://username:password@?', false], // Chrome, FF: true | ||
['scheme://username:password@#', false], // Chrome, FF: true | ||
['scheme://host.name', true], | ||
['scheme://123.456.789.10', true], | ||
['scheme://[1234:0000:0000:5678:9abc:0000:0000:def]', true], | ||
['scheme://[1234:0000:0000:5678:9abc:0000:0000:def]:7678', true], | ||
['scheme://[1234:0:0:5678:9abc:0:0:def]', true], | ||
['scheme://[1234::5678:9abc::def]', true], | ||
['scheme://~`!@$%^&*-_=+|\\;\'",.()[]{}<>', true], | ||
|
||
// Validating `port` | ||
['scheme://example.com/no-port', true], | ||
['scheme://example.com:7678', true], | ||
['scheme://example.com:76T8', false], // Chrome, FF: true | ||
['scheme://example.com:port', false], // Chrome, FF: true | ||
|
||
// Validating `path` | ||
['scheme://example.com/', true], | ||
['scheme://example.com/path', true], | ||
['scheme://example.com/path/~`!@$%^&*-_=+|\\;:\'",./()[]{}<>', true], | ||
|
||
// Validating `query` | ||
['scheme://example.com?query', true], | ||
['scheme://example.com/?query', true], | ||
['scheme://example.com/path?query', true], | ||
['scheme://example.com/path?~`!@$%^&*-_=+|\\;:\'",.?/()[]{}<>', true], | ||
|
||
// Validating `fragment` | ||
['scheme://example.com#fragment', true], | ||
['scheme://example.com/#fragment', true], | ||
['scheme://example.com/path#fragment', true], | ||
['scheme://example.com/path/#fragment', true], | ||
['scheme://example.com/path?query#fragment', true], | ||
['scheme://example.com/path?query#~`!@#$%^&*-_=+|\\;:\'",.?/()[]{}<>', true], | ||
|
||
// Validating miscellaneous | ||
['scheme://☺.✪.⌘.➡/䨹', true], | ||
['scheme://مثال.إختبار', true], | ||
['scheme://例子.测试', true], | ||
['scheme://उदाहरण.परीक्षा', true], | ||
|
||
// Legacy tests | ||
['http://server:123/path', true], | ||
['https://server:123/path', true], | ||
['file:///home/user', true], | ||
['mailto:[email protected]?subject=Foo', true], | ||
['r2-d2.c3-p0://localhost/foo', true], | ||
['abc:/foo', true], | ||
['http://example.com/path;path', true], | ||
['http://example.com/[]$\'()*,~)', true], | ||
['http:', false], // FF: true | ||
['[email protected]', false], | ||
['a_B.c', false], | ||
['0scheme://example.com', false], | ||
['http://example.com:9999/``', true] | ||
]; | ||
|
||
they('should validate url: $prop', urls, function(item) { | ||
var url = item[0]; | ||
var valid = item[1]; | ||
|
||
/* global URL_REGEXP: false */ | ||
expect(URL_REGEXP.test(url)).toBe(valid); | ||
}); | ||
}); | ||
}); | ||
|