Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor parse query and percent-encode sets #152

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 27 additions & 33 deletions src/url-state-machine.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,29 @@ function isC0ControlPercentEncode(c) {
return c <= 0x1F || c > 0x7E;
}

const extraUserinfoPercentEncodeSet =
new Set([p("/"), p(":"), p(";"), p("="), p("@"), p("["), p("\\"), p("]"), p("^"), p("|")]);
function isUserinfoPercentEncode(c) {
return isPathPercentEncode(c) || extraUserinfoPercentEncodeSet.has(c);
}

const extraFragmentPercentEncodeSet = new Set([p(" "), p("\""), p("<"), p(">"), p("`")]);
function isFragmentPercentEncode(c) {
return isC0ControlPercentEncode(c) || extraFragmentPercentEncodeSet.has(c);
}

const extraPathPercentEncodeSet = new Set([p("#"), p("?"), p("{"), p("}")]);
const extraQueryPercentEncodeSet = new Set([p(" "), p("\""), p("#"), p("<"), p(">")]);
function isQueryPercentEncode(c) {
return isC0ControlPercentEncode(c) || extraQueryPercentEncodeSet.has(c);
}

function isSpecialQueryPercentEncode(c) {
return isQueryPercentEncode(c) || c === p("'");
}

const extraPathPercentEncodeSet = new Set([p("?"), p("`"), p("{"), p("}")]);
function isPathPercentEncode(c) {
return isFragmentPercentEncode(c) || extraPathPercentEncodeSet.has(c);
return isQueryPercentEncode(c) || extraPathPercentEncodeSet.has(c);
}

const extraUserinfoPercentEncodeSet =
new Set([p("/"), p(":"), p(";"), p("="), p("@"), p("["), p("\\"), p("]"), p("^"), p("|")]);
function isUserinfoPercentEncode(c) {
return isPathPercentEncode(c) || extraUserinfoPercentEncodeSet.has(c);
}

function percentEncodeChar(c, encodeSetPredicate) {
Expand Down Expand Up @@ -1097,38 +1106,23 @@ URLStateMachine.prototype["parse cannot-be-a-base-URL path"] = function parseCan
return true;
};

URLStateMachine.prototype["parse query"] = function parseQuery(c, cStr) {
if (isNaN(c) || (!this.stateOverride && c === p("#"))) {
if (!isSpecial(this.url) || this.url.scheme === "ws" || this.url.scheme === "wss") {
this.encodingOverride = "utf-8";
}

const buffer = Buffer.from(this.buffer); // TODO: Use encoding override instead
for (let i = 0; i < buffer.length; ++i) {
if (buffer[i] < 0x21 ||
buffer[i] > 0x7E ||
buffer[i] === 0x22 || buffer[i] === 0x23 || buffer[i] === 0x3C || buffer[i] === 0x3E ||
(buffer[i] === 0x27 && isSpecial(this.url))) {
this.url.query += percentEncode(buffer[i]);
} else {
this.url.query += String.fromCodePoint(buffer[i]);
}
}
URLStateMachine.prototype["parse query"] = function parseQuery(c) {
if (!isSpecial(this.url) || this.url.scheme === "ws" || this.url.scheme === "wss") {
this.encodingOverride = "utf-8";
}

this.buffer = "";
if (c === p("#")) {
this.url.fragment = "";
this.state = "fragment";
}
} else {
if (!this.stateOverride && c === p("#")) {
this.url.fragment = "";
this.state = "fragment";
} else if (!isNaN(c)) {
// TODO: If c is not a URL code point and not "%", parse error.
if (c === p("%") &&
(!infra.isASCIIHex(this.input[this.pointer + 1]) ||
!infra.isASCIIHex(this.input[this.pointer + 2]))) {
this.parseError = true;
}

this.buffer += cStr;
// TODO: Use encoding override instead
this.url.query += percentEncodeChar(c, isSpecial(this.url) ? isSpecialQueryPercentEncode : isQueryPercentEncode);
}

return true;
Expand Down