diff --git a/linphone-desktop/ui/scripts/Utils/uri-tools.js b/linphone-desktop/ui/scripts/Utils/uri-tools.js index 0ae3fad21..f106f8176 100644 --- a/linphone-desktop/ui/scripts/Utils/uri-tools.js +++ b/linphone-desktop/ui/scripts/Utils/uri-tools.js @@ -1,5 +1,6 @@ // ============================================================================= // Library to deal with URI. +// See: https://tools.ietf.org/html/rfc3986#section-1.3 // ============================================================================= .pragma library @@ -12,6 +13,15 @@ var SUPPORTS_URL = true // Level 0. -------------------------------------------------------------------- +var URI_DEC_OCTET = '(?:' + + '25[0-5]' + + '|' + '2[0-4]\\d' + + '|' + '1\\d{2}' + + '|' + '[1-9]\\d' + + '|' + '\\d' + +')' + +var URI_H16 = '[0-9A-Fa-f]{1,4}' var URI_PCT_ENCODED = '%[A-Fa-f\\d]{2}' var URI_PORT = '\\d*' var URI_SCHEME = '[a-zA-Z][\\w+\-\.]*' @@ -20,14 +30,15 @@ var URI_UNRESERVED = '[\\w\-\._~]' // Level 1. -------------------------------------------------------------------- -var URI_HOST = '(?:' + - '(?:' + - URI_UNRESERVED + - '|' + URI_PCT_ENCODED + - '|' + URI_SUB_DELIMS + - ')*' + +var URI_IPV_FUTURE = 'v[0-9A-Fa-f]+\\.' + '(?:' + + URI_UNRESERVED + + URI_SUB_DELIMS + + ':' + ')' +var URI_IPV4_ADDRESS = URI_DEC_OCTET + '\\.' + URI_DEC_OCTET + '\\.' + + URI_DEC_OCTET + '\\.' + URI_DEC_OCTET + var URI_PCHAR = '(?:' + URI_UNRESERVED + '|' + URI_PCT_ENCODED + @@ -35,6 +46,12 @@ var URI_PCHAR = '(?:' + '|' + '[:@]' + ')' +var URI_REG_NAME = '(?:' + + URI_UNRESERVED + + '|' + URI_PCT_ENCODED + + '|' + URI_SUB_DELIMS + +')*' + var URI_USERINFO = '(?:' + URI_UNRESERVED + '|' + URI_PCT_ENCODED + @@ -44,15 +61,16 @@ var URI_USERINFO = '(?:' + // Level 2. -------------------------------------------------------------------- -var URI_AUTHORITY = '(?:' + URI_USERINFO + '@' + ')?' + - URI_HOST + - '(?:' + ':' + URI_PORT + ')?' - var URI_FRAGMENT = '(?:' + URI_PCHAR + '|' + '[/?]' + ')*' +var URI_LS32 = '(?:' + + URI_H16 + ':' + URI_H16 + + '|' + URI_IPV4_ADDRESS + +')' + var URI_QUERY = '(?:' + URI_PCHAR + '|' + '[/?]' + @@ -63,6 +81,18 @@ var URI_SEGMENT_NZ = URI_PCHAR + '+' // Level 3. -------------------------------------------------------------------- +var URI_IPV6_ADDRESS = '(?:' + + '(?:' + URI_H16 + ':){6}' + URI_LS32 + + '|' + '::(?:' + URI_H16 + ':){5}' + URI_LS32 + + '|' + '\\[' + URI_H16 + '\\]::(?:' + URI_H16 + ':){4}' + URI_LS32 + + '|' + '\\[' + '(?:' + URI_H16 + ':)?' + URI_H16 + '\\]::(?:' + URI_H16 + ':){3}' + URI_LS32 + + '|' + '\\[' + '(?:' + URI_H16 + ':){0,2}' + URI_H16 + '\\]::(?:' + URI_H16 + ':){2}' + URI_LS32 + + '|' + '\\[' + '(?:' + URI_H16 + ':){0,3}' + URI_H16 + '\\]::' + URI_H16 + ':' + URI_LS32 + + '|' + '\\[' + '(?:' + URI_H16 + ':){0,4}' + URI_H16 + '\\]::' + URI_LS32 + + '|' + '\\[' + '(?:' + URI_H16 + ':){0,5}' + URI_H16 + '\\]::' + URI_H16 + + '|' + '\\[' + '(?:' + URI_H16 + ':){0,6}' + URI_H16 + '\\]::' + +')' + var URI_PATH_ABEMPTY = '(?:' + '/' + URI_SEGMENT + ')*' var URI_PATH_ABSOLUTE = '/' + @@ -73,6 +103,29 @@ var URI_PATH_ROOTLESS = // Level 4. -------------------------------------------------------------------- +var URI_IP_LITERAL = '\\[' + + '(?:' + + URI_IPV6_ADDRESS + + '|' + URI_IPV_FUTURE + + ')' + +'\\]' + +// Level 5. -------------------------------------------------------------------- + +var URI_HOST = '(?:' + + URI_REG_NAME + + '|' + URI_IPV4_ADDRESS + + '|' + URI_IP_LITERAL + +')' + +// Level 6. -------------------------------------------------------------------- + +var URI_AUTHORITY = '(?:' + URI_USERINFO + '@' + ')?' + + URI_HOST + + '(?:' + ':' + URI_PORT + ')?' + +// Level 7. -------------------------------------------------------------------- + // `path-empty` not used. var URI_HIER_PART = '(?:' + '//' + URI_AUTHORITY + URI_PATH_ABEMPTY + @@ -80,72 +133,13 @@ var URI_HIER_PART = '(?:' + '|' + URI_PATH_ROOTLESS + ')' -// Level 5. -------------------------------------------------------------------- +// Level 8. -------------------------------------------------------------------- // Regex to match URI. It respects the RFC 3986. -// But many features are not supported like IP format. var URI = (SUPPORTS_URL ? '(?:' + URI_SCHEME + ':' + '|' + 'www\\.' + ')' : URI_SCHEME + ':' ) + URI_HIER_PART + '(?:' + '\\?' + URI_QUERY + ')?' + -'(?:' + '#' + URI_FRAGMENT + ')?' + '(?:' + '#' + URI_FRAGMENT + ')?' var URI_REGEX = new RegExp('(' + URI + ')', 'g') - -// ============================================================================= - -/* TODO: Supports: - - URI-reference = URI / relative-ref - - absolute-URI = scheme ":" hier-part [ "?" query ] - - relative-ref = relative-part [ "?" query ] [ "#" fragment ] - - relative-part = "//" authority path-abempty - / path-absolute - / path-noscheme - / path-empty - - host = IP-literal / IPv4address / reg-name - - IP-literal = "[" ( IPv6address / IPvFuture ) "]" - - IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) - - IPv6address = 6( h16 ":" ) ls32 - / "::" 5( h16 ":" ) ls32 - / [ h16 ] "::" 4( h16 ":" ) ls32 - / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 - / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 - / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 - / [ *4( h16 ":" ) h16 ] "::" ls32 - / [ *5( h16 ":" ) h16 ] "::" h16 - / [ *6( h16 ":" ) h16 ] "::" - - h16 = 1*4HEXDIG - ls32 = ( h16 ":" h16 ) / IPv4address - IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet - - dec-octet = DIGIT ; 0-9 - / %x31-39 DIGIT ; 10-99 - / "1" 2DIGIT ; 100-199 - / "2" %x30-34 DIGIT ; 200-249 - / "25" %x30-35 ; 250-255 - - reg-name = *( unreserved / pct-encoded / sub-delims ) - - path = path-abempty ; begins with "/" or is empty - / path-absolute ; begins with "/" but not "//" - / path-noscheme ; begins with a non-colon segment - / path-rootless ; begins with a segment - / path-empty ; zero characters - - path-noscheme = segment-nz-nc *( "/" segment ) - - segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) - ; non-zero-length segment without any colon ":" - - reserved = gen-delims / sub-delims - gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" -*/ diff --git a/linphone-desktop/ui/scripts/Utils/uri-tools.spec.qml b/linphone-desktop/ui/scripts/Utils/uri-tools.spec.qml index 61f82ce2c..5dad5b431 100644 --- a/linphone-desktop/ui/scripts/Utils/uri-tools.spec.qml +++ b/linphone-desktop/ui/scripts/Utils/uri-tools.spec.qml @@ -1,6 +1,6 @@ import QtTest 1.1 -import './uri-tools.js' as UriTools +import 'uri-tools.js' as UriTools // ============================================================================= @@ -23,6 +23,10 @@ TestCase { function test_matchUri_data () { return [ + // ======================================================================= + // Must match. + // ======================================================================= + { input: 'http://www.LaRmInA.com/', output: [ 'http://www.LaRmInA.com/' ] @@ -68,6 +72,42 @@ TestCase { }, { input: 'protocol://U$3r:p@sswd/WwW.L33t.sp3', output: [ 'protocol://U$3r:p@sswd/WwW.L33t.sp3' ] + }, { + input: 'foo://username:password@www.example.com:123/hello/world/there.html?name=ferret#foo', + output: [ 'foo://username:password@www.example.com:123/hello/world/there.html?name=ferret#foo' ] + }, { + input: 'lalala://lololo.titi/tata_(tutu)#riri-0', + output: [ 'lalala://lololo.titi/tata_(tutu)#riri-0' ] + }, { + input: 'dest://007@uk.en:8080/', + output: [ 'dest://007@uk.en:8080/' ] + }, { + input: 'fefe://zef.sfdfzfds.vfs/zrefz/?vsfezzef=afzfefg&zfefezfze=7275&grgr', + output: [ 'fefe://zef.sfdfzfds.vfs/zrefz/?vsfezzef=afzfefg&zfefezfze=7275&grgr' ] + }, { + input: 'fefe://xcv.zefe/(fzfff)?zefezef=fzefzef', + output: [ 'fefe://xcv.zefe/(fzfff)?zefezef=fzefzef' ] + }, { + input: 'feeffsd://vccvx.zzef.dfs/xcvvcx/#&zfe=zfe', + output: [ 'feeffsd://vccvx.zzef.dfs/xcvvcx/#&zfe=zfe' ] + }, { + input: 'http://256.1.1.1', + output: [ 'http://256.1.1.1' ] // Valid URI. Invalid URL. + }, { + input: 'http://0.0.0.0', + output: [ 'http://0.0.0.0' ] // Same idea. + }, { + input: 'http://a.b--c.de/', + output: [ 'http://a.b--c.de/' ] // And again. + }, { + input: 'http://1.0.1.0.1.0', + output: [ 'http://1.0.1.0.1.0' ] // AND AGAIN. + }, { + input: 'http://abc.c.d.', + output: [ 'http://abc.c.d.' ] // AAAAND AAAGAAAIIIIIN. + }, { + input: 'https://a.b-c.de/', + output: [ 'https://a.b-c.de/' ] }, { input: 'http://a/B/c?a&b&c', output: [ 'http://a/B/c?a&b&c' ] @@ -75,6 +115,18 @@ TestCase { input: '1http://www.linphone.org', output: [ 'http://www.linphone.org' ] }, { + input: 'http://255.254.255.254', + output: [ 'http://255.254.255.254' ] + }, { + input: 'http://12.42.1.10/', + output: [ 'http://12.42.1.10/' ] + }, + + // ======================================================================= + // Partial or no match. + // ======================================================================= + + { input: '://www.linphone.org', output: UriTools.SUPPORTS_URL ? [ 'www.linphone.org' ] @@ -85,6 +137,21 @@ TestCase { }, { input: '/path/', output: null + }, { + input: 'http://✪dragooooonnnn✪ball✪z✪z✪z.goku/4', + output: [ 'http://' ] + }, { + input: 'http:// iamafail.fr', + output: [ 'http://' ] + }, { + input: 'isaac://石村.jp', + output: [ 'isaac://' ] + }, { + input: ':// not good', + output: null + }, { + input: 'http://☺.☺.☺', + output: [ 'http://' ] } ] }