-
-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Spec update: disallow invalid IPv4 in the IPv6 parser
This matches whatwg/url#196.
- Loading branch information
Showing
3 changed files
with
171 additions
and
6 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
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 |
---|---|---|
@@ -0,0 +1,165 @@ | ||
"use strict"; | ||
const URL = require(".").URL; | ||
const punycode = require("punycode"); | ||
const failure = Symbol("failure"); | ||
|
||
|
||
console.log(parseIPv6("::1.")); | ||
|
||
//console.log(new URL("http://[::1.]").href); | ||
|
||
function p(char) { | ||
return char.codePointAt(0); | ||
} | ||
|
||
function at(input, idx) { | ||
const c = input[idx]; | ||
return isNaN(c) ? undefined : String.fromCodePoint(c); | ||
} | ||
|
||
function isASCIIDigit(c) { | ||
return c >= 0x30 && c <= 0x39; | ||
} | ||
|
||
function isASCIIAlpha(c) { | ||
return (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A); | ||
} | ||
|
||
function isASCIIAlphanumeric(c) { | ||
return isASCIIAlpha(c) || isASCIIDigit(c); | ||
} | ||
|
||
function isASCIIHex(c) { | ||
return isASCIIDigit(c) || (c >= 0x41 && c <= 0x46) || (c >= 0x61 && c <= 0x66); | ||
} | ||
|
||
|
||
function parseIPv6(input) { | ||
const ip = [0, 0, 0, 0, 0, 0, 0, 0]; | ||
let piecePtr = 0; | ||
let compressPtr = null; | ||
let pointer = 0; | ||
|
||
input = punycode.ucs2.decode(input); | ||
|
||
if (input[pointer] === p(":")) { | ||
if (input[pointer + 1] !== p(":")) { | ||
return failure; | ||
} | ||
|
||
pointer += 2; | ||
++piecePtr; | ||
compressPtr = piecePtr; | ||
} | ||
|
||
let ipv4 = false; | ||
Main: | ||
while (pointer < input.length) { | ||
if (piecePtr === 8) { | ||
return failure; | ||
} | ||
|
||
if (input[pointer] === p(":")) { | ||
if (compressPtr !== null) { | ||
return failure; | ||
} | ||
++pointer; | ||
++piecePtr; | ||
compressPtr = piecePtr; | ||
continue; | ||
} | ||
|
||
let value = 0; | ||
let length = 0; | ||
|
||
while (length < 4 && isASCIIHex(input[pointer])) { | ||
value = value * 0x10 + parseInt(at(input, pointer), 16); | ||
++pointer; | ||
++length; | ||
} | ||
|
||
switch (at(input, pointer)) { | ||
case ".": | ||
if (length === 0) { | ||
return failure; | ||
} | ||
pointer -= length; | ||
ipv4 = true; | ||
break Main; | ||
case ":": | ||
++pointer; | ||
if (input[pointer] === undefined) { | ||
return failure; | ||
} | ||
break; | ||
case undefined: | ||
break; | ||
default: | ||
return failure; | ||
} | ||
|
||
ip[piecePtr] = value; | ||
++piecePtr; | ||
} | ||
|
||
if (ipv4 && piecePtr > 6) { | ||
return failure; | ||
} else if (input[pointer] !== undefined) { | ||
let dotsSeen = 0; | ||
|
||
while (input[pointer] !== undefined) { | ||
let value = null; | ||
if (!isASCIIDigit(input[pointer])) { | ||
return failure; | ||
} | ||
|
||
while (isASCIIDigit(input[pointer])) { | ||
const number = parseInt(at(input, pointer)); | ||
if (value === null) { | ||
value = number; | ||
} else if (value === 0) { | ||
return failure; | ||
} else { | ||
value = value * 10 + number; | ||
} | ||
++pointer; | ||
if (value > 255) { | ||
return failure; | ||
} | ||
} | ||
|
||
if (dotsSeen < 3 && input[pointer] !== p(".")) { | ||
return failure; | ||
} | ||
ip[piecePtr] = ip[piecePtr] * 0x100 + value; | ||
if (dotsSeen === 1 || dotsSeen === 3) { | ||
++piecePtr; | ||
} | ||
|
||
if (dotsSeen === 3 && input[pointer] !== undefined) { | ||
return failure; | ||
} | ||
|
||
if (input[pointer] === p(".")) { | ||
++pointer; | ||
++dotsSeen; | ||
} | ||
} | ||
} | ||
|
||
if (compressPtr !== null) { | ||
let swaps = piecePtr - compressPtr; | ||
piecePtr = 7; | ||
while (piecePtr !== 0 && swaps > 0) { | ||
const temp = ip[compressPtr + swaps - 1]; // piece | ||
ip[compressPtr + swaps - 1] = ip[piecePtr]; | ||
ip[piecePtr] = temp; | ||
--piecePtr; | ||
--swaps; | ||
} | ||
} else if (piecePtr !== 8) { | ||
return failure; | ||
} | ||
|
||
return ip; | ||
} |