mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 504014 - Enforce RFC 3986 syntax for IPv6 literals
This commit is contained in:
parent
4610476ed2
commit
60e90c98b0
@ -37,6 +37,8 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "mozilla/RangedPtr.h"
|
||||
|
||||
#include "nsURLHelper.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsIServiceManager.h"
|
||||
@ -53,6 +55,8 @@
|
||||
#include "prprf.h"
|
||||
#include "prnetdb.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Init/Shutdown
|
||||
//----------------------------------------------------------------------------
|
||||
@ -990,3 +994,94 @@ net_IsValidHostName(const nsCSubstring &host)
|
||||
PRNetAddr addr;
|
||||
return PR_StringToNetAddr(strhost.get(), &addr) == PR_SUCCESS;
|
||||
}
|
||||
|
||||
PRBool
|
||||
net_IsValidIPv4Addr(const char *addr, PRInt32 addrLen)
|
||||
{
|
||||
RangedPtr<const char> p(addr, addrLen);
|
||||
|
||||
PRInt32 octet = -1; // means no digit yet
|
||||
PRInt32 dotCount = 0; // number of dots in the address
|
||||
|
||||
for (; addrLen; ++p, --addrLen) {
|
||||
if (*p == '.') {
|
||||
dotCount++;
|
||||
if (octet == -1) {
|
||||
// invalid octet
|
||||
return PR_FALSE;
|
||||
}
|
||||
octet = -1;
|
||||
} else if (*p >= '0' && *p <='9') {
|
||||
if (octet == 0) {
|
||||
// leading 0 is not allowed
|
||||
return PR_FALSE;
|
||||
} else if (octet == -1) {
|
||||
octet = *p - '0';
|
||||
} else {
|
||||
octet *= 10;
|
||||
octet += *p - '0';
|
||||
if (octet > 255)
|
||||
return PR_FALSE;
|
||||
}
|
||||
} else {
|
||||
// invalid character
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return (dotCount == 3 && octet != -1);
|
||||
}
|
||||
|
||||
PRBool
|
||||
net_IsValidIPv6Addr(const char *addr, PRInt32 addrLen)
|
||||
{
|
||||
RangedPtr<const char> p(addr, addrLen);
|
||||
|
||||
PRInt32 digits = 0; // number of digits in current block
|
||||
PRInt32 colons = 0; // number of colons in a row during parsing
|
||||
PRInt32 blocks = 0; // number of hexadecimal blocks
|
||||
PRBool haveZeros = PR_FALSE; // true if double colon is present in the address
|
||||
|
||||
for (; addrLen; ++p, --addrLen) {
|
||||
if (*p == ':') {
|
||||
if (colons == 0) {
|
||||
if (digits != 0) {
|
||||
digits = 0;
|
||||
blocks++;
|
||||
}
|
||||
} else if (colons == 1) {
|
||||
if (haveZeros)
|
||||
return PR_FALSE; // only one occurrence is allowed
|
||||
haveZeros = PR_TRUE;
|
||||
} else {
|
||||
// too many colons in a row
|
||||
return PR_FALSE;
|
||||
}
|
||||
colons++;
|
||||
} else if ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') ||
|
||||
(*p >= 'A' && *p <= 'F')) {
|
||||
if (colons == 1 && blocks == 0) // starts with a single colon
|
||||
return PR_FALSE;
|
||||
if (digits == 4) // too many digits
|
||||
return PR_FALSE;
|
||||
colons = 0;
|
||||
digits++;
|
||||
} else if (*p == '.') {
|
||||
// check valid IPv4 from the beginning of the last block
|
||||
if (!net_IsValidIPv4Addr(p.get() - digits, addrLen + digits))
|
||||
return PR_FALSE;
|
||||
return (haveZeros && blocks < 6) || (!haveZeros && blocks == 6);
|
||||
} else {
|
||||
// invalid character
|
||||
return PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (colons == 1) // ends with a single colon
|
||||
return PR_FALSE;
|
||||
|
||||
if (digits) // there is a block at the end
|
||||
blocks++;
|
||||
|
||||
return (haveZeros && blocks < 8) || (!haveZeros && blocks == 8);
|
||||
}
|
||||
|
@ -248,4 +248,14 @@ inline char *net_RFindCharNotInSet(const char *str, const char *set)
|
||||
*/
|
||||
NS_HIDDEN_(PRBool) net_IsValidHostName(const nsCSubstring &host);
|
||||
|
||||
/**
|
||||
* Checks whether the IPv4 address is valid according to RFC 3986 section 3.2.2.
|
||||
*/
|
||||
NS_HIDDEN_(PRBool) net_IsValidIPv4Addr(const char *addr, PRInt32 addrLen);
|
||||
|
||||
/**
|
||||
* Checks whether the IPv6 address is valid according to RFC 3986 section 3.2.2.
|
||||
*/
|
||||
NS_HIDDEN_(PRBool) net_IsValidIPv6Addr(const char *addr, PRInt32 addrLen);
|
||||
|
||||
#endif // !nsURLHelper_h__
|
||||
|
@ -641,6 +641,13 @@ nsAuthURLParser::ParseServerInfo(const char *serverinfo, PRInt32 serverinfoLen,
|
||||
if (port)
|
||||
*port = -1;
|
||||
}
|
||||
|
||||
// In case of IPv6 address check its validity
|
||||
if (*hostnameLen > 1 && *(serverinfo + *hostnamePos) == '[' &&
|
||||
*(serverinfo + *hostnamePos + *hostnameLen - 1) == ']' &&
|
||||
!net_IsValidIPv6Addr(serverinfo + *hostnamePos + 1, *hostnameLen - 2))
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
73
netwerk/test/unit/test_bug504014.js
Normal file
73
netwerk/test/unit/test_bug504014.js
Normal file
@ -0,0 +1,73 @@
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
var valid_URIs = [ "http://[::]/",
|
||||
"http://[::1]/",
|
||||
"http://[1::]/",
|
||||
"http://[::]/",
|
||||
"http://[::1]/",
|
||||
"http://[1::]/",
|
||||
"http://[1:2:3:4:5:6:7::]/",
|
||||
"http://[::1:2:3:4:5:6:7]/",
|
||||
"http://[1:2:a:B:c:D:e:F]/",
|
||||
"http://[1::8]/",
|
||||
"http://[1:2::8]/",
|
||||
"http://[0000:0123:4567:89AB:CDEF:abcd:ef00:0000]/",
|
||||
"http://[::192.168.1.1]/",
|
||||
"http://[1::0.0.0.0]/",
|
||||
"http://[1:2::255.255.255.255]/",
|
||||
"http://[1:2:3::255.255.255.255]/",
|
||||
"http://[1:2:3:4::255.255.255.255]/",
|
||||
"http://[1:2:3:4:5::255.255.255.255]/",
|
||||
"http://[1:2:3:4:5:6:255.255.255.255]/"];
|
||||
|
||||
var invalid_URIs = [ "http://[1]/",
|
||||
"http://[192.168.1.1]/",
|
||||
"http://[:::]/",
|
||||
"http://[:::1]/",
|
||||
"http://[1:::]/",
|
||||
"http://[::1::]/",
|
||||
"http://[1:2:3:4:5:6:7:]/",
|
||||
"http://[:2:3:4:5:6:7:8]/",
|
||||
"http://[1:2:3:4:5:6:7:8:]/",
|
||||
"http://[:1:2:3:4:5:6:7:8]/",
|
||||
"http://[1:2:3:4:5:6:7:8::]/",
|
||||
"http://[::1:2:3:4:5:6:7:8]/",
|
||||
"http://[1:2:3:4:5:6:7]/",
|
||||
"http://[1:2:3:4:5:6:7:8:9]/",
|
||||
"http://[00001:2:3:4:5:6:7:8]/",
|
||||
"http://[0001:2:3:4:5:6:7:89abc]/",
|
||||
"http://[A:b:C:d:E:f:G:h]/",
|
||||
"http://[::192.168.1]/",
|
||||
"http://[::192.168.1.]/",
|
||||
"http://[::.168.1.1]/",
|
||||
"http://[::192..1.1]/",
|
||||
"http://[::0192.168.1.1]/",
|
||||
"http://[::256.255.255.255]/",
|
||||
"http://[::1x.255.255.255]/",
|
||||
"http://[::192.4294967464.1.1]/",
|
||||
"http://[1:2:3:4:5:6::255.255.255.255]/",
|
||||
"http://[1:2:3:4:5:6:7:255.255.255.255]/"];
|
||||
|
||||
function run_test() {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
|
||||
for (var i=0 ; i<valid_URIs.length ; i++) {
|
||||
try {
|
||||
var uri = ios.newURI(valid_URIs[i], null, null);
|
||||
} catch (e) {
|
||||
do_throw("cannot create URI:" + valid_URIs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i=0 ; i<invalid_URIs.length ; i++) {
|
||||
try {
|
||||
var uri = ios.newURI(invalid_URIs[i], null, null);
|
||||
do_throw("should throw: " + invalid_URIs[i]);
|
||||
} catch (e) {
|
||||
do_check_eq(e.result, Cr.NS_ERROR_MALFORMED_URI);
|
||||
}
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@ tail =
|
||||
[test_bug482601.js]
|
||||
[test_bug484684.js]
|
||||
[test_bug490095.js]
|
||||
[test_bug504014.js]
|
||||
[test_bug510359.js]
|
||||
[test_bug515583.js]
|
||||
[test_bug528292.js]
|
||||
|
Loading…
Reference in New Issue
Block a user