Skip to content

Commit

Permalink
Spec update: disallow invalid IPv4 in the IPv6 parser
Browse files Browse the repository at this point in the history
This matches whatwg/url#196.
  • Loading branch information
domenic committed Jan 9, 2017
1 parent 2556e46 commit 316dc45
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 6 deletions.
2 changes: 1 addition & 1 deletion scripts/get-latest-platform-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const request = require("request");
// 1. Go to https://github.com/w3c/web-platform-tests/tree/master/url
// 2. Press "y" on your keyboard to get a permalink
// 3. Copy the commit hash
const commitHash = "1e1e80441b8d6a60f836de4005dba25698ecfe4a";
const commitHash = "6e9508aab07d0c3e81e2ae60bac32290c02cd8f2";

const sourceURL = `https://raw.githubusercontent.com/w3c/web-platform-tests/${commitHash}/url/urltestdata.json`;
const setterSourceURL = `https://raw.githubusercontent.com/w3c/web-platform-tests/${commitHash}/url/setters_tests.json`;
Expand Down
10 changes: 5 additions & 5 deletions src/url-state-machine.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,14 +309,14 @@ function parseIPv6(input) {
++piecePtr;
}

if (input[pointer] !== undefined) {
++pointer;
}

if (dotsSeen === 3 && input[pointer] !== undefined) {
return failure;
}
++dotsSeen;

if (input[pointer] === p(".")) {
++pointer;
++dotsSeen;
}
}
}

Expand Down
165 changes: 165 additions & 0 deletions test.js
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;
}

0 comments on commit 316dc45

Please sign in to comment.