url: performance improvement in URL implementation
Yields about a 25% average performance improvement PR-URL: https://github.com/nodejs/node/pull/10469 Reviewed-By: Michaël Zasso <targos@protonmail.com>
This commit is contained in:
parent
509ff1b9e4
commit
2213f3640a
393
lib/internal/url.js
Normal file → Executable file
393
lib/internal/url.js
Normal file → Executable file
@ -67,50 +67,151 @@ class TupleOrigin {
|
||||
}
|
||||
|
||||
toString(unicode = false) {
|
||||
var result = this.scheme;
|
||||
var result = this[kScheme];
|
||||
result += '://';
|
||||
result += unicode ? URL.domainToUnicode(this.host) : this.host;
|
||||
if (this.port !== undefined && this.port !== null)
|
||||
result += `:${this.port}`;
|
||||
result += unicode ? URL.domainToUnicode(this[kHost]) : this[kHost];
|
||||
if (this[kPort] !== undefined && this[kPort] !== null)
|
||||
result += `:${this[kPort]}`;
|
||||
return result;
|
||||
}
|
||||
|
||||
inspect() {
|
||||
return `TupleOrigin {
|
||||
scheme: ${this.scheme},
|
||||
host: ${this.host},
|
||||
port: ${this.port},
|
||||
domain: ${this.domain}
|
||||
scheme: ${this[kScheme]},
|
||||
host: ${this[kHost]},
|
||||
port: ${this[kPort]},
|
||||
domain: ${this[kDomain]}
|
||||
}`;
|
||||
}
|
||||
}
|
||||
|
||||
function onParseComplete(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
throw new TypeError('Invalid URL');
|
||||
var ctx = this[context];
|
||||
ctx.flags = flags;
|
||||
ctx.scheme = protocol;
|
||||
ctx.username = username;
|
||||
ctx.password = password;
|
||||
ctx.port = port;
|
||||
ctx.path = path;
|
||||
ctx.query = query;
|
||||
ctx.fragment = fragment;
|
||||
ctx.host = host;
|
||||
if (this[searchParams]) { // invoked from href setter
|
||||
initSearchParams(this[searchParams], query);
|
||||
} else {
|
||||
this[searchParams] = new URLSearchParams(query);
|
||||
}
|
||||
this[searchParams][context] = this;
|
||||
}
|
||||
|
||||
// Reused by URL constructor and URL#href setter.
|
||||
function parse(url, input, base) {
|
||||
input = String(input);
|
||||
const base_context = base ? base[context] : undefined;
|
||||
url[context] = new StorageObject();
|
||||
binding.parse(input.trim(), -1, base_context, undefined,
|
||||
(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) => {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
throw new TypeError('Invalid URL');
|
||||
url[context].flags = flags;
|
||||
url[context].scheme = protocol;
|
||||
url[context].username = username;
|
||||
url[context].password = password;
|
||||
url[context].port = port;
|
||||
url[context].path = path;
|
||||
url[context].query = query;
|
||||
url[context].fragment = fragment;
|
||||
url[context].host = host;
|
||||
if (url[searchParams]) { // invoked from href setter
|
||||
initSearchParams(url[searchParams], query);
|
||||
} else {
|
||||
url[searchParams] = new URLSearchParams(query);
|
||||
}
|
||||
url[searchParams][context] = url;
|
||||
});
|
||||
binding.parse(input.trim(), -1,
|
||||
base_context, undefined,
|
||||
onParseComplete.bind(url));
|
||||
}
|
||||
|
||||
function onParseProtocolComplete(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
const newIsSpecial = (flags & binding.URL_FLAGS_SPECIAL) !== 0;
|
||||
const s = this[special];
|
||||
const ctx = this[context];
|
||||
if ((s && !newIsSpecial) || (!s && newIsSpecial)) {
|
||||
return;
|
||||
}
|
||||
if (newIsSpecial) {
|
||||
ctx.flags |= binding.URL_FLAGS_SPECIAL;
|
||||
} else {
|
||||
ctx.flags &= ~binding.URL_FLAGS_SPECIAL;
|
||||
}
|
||||
if (protocol) {
|
||||
ctx.scheme = protocol;
|
||||
ctx.flags |= binding.URL_FLAGS_HAS_SCHEME;
|
||||
} else {
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_SCHEME;
|
||||
}
|
||||
}
|
||||
|
||||
function onParseHostComplete(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
const ctx = this[context];
|
||||
if (host) {
|
||||
ctx.host = host;
|
||||
ctx.flags |= binding.URL_FLAGS_HAS_HOST;
|
||||
} else {
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_HOST;
|
||||
}
|
||||
if (port !== undefined)
|
||||
ctx.port = port;
|
||||
}
|
||||
|
||||
function onParseHostnameComplete(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
const ctx = this[context];
|
||||
if (host) {
|
||||
ctx.host = host;
|
||||
ctx.flags |= binding.URL_FLAGS_HAS_HOST;
|
||||
} else {
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_HOST;
|
||||
}
|
||||
}
|
||||
|
||||
function onParsePortComplete(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
this[context].port = port;
|
||||
}
|
||||
|
||||
function onParsePathComplete(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
const ctx = this[context];
|
||||
if (path) {
|
||||
ctx.path = path;
|
||||
ctx.flags |= binding.URL_FLAGS_HAS_PATH;
|
||||
} else {
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_PATH;
|
||||
}
|
||||
}
|
||||
|
||||
function onParseSearchComplete(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
const ctx = this[context];
|
||||
if (query) {
|
||||
ctx.query = query;
|
||||
ctx.flags |= binding.URL_FLAGS_HAS_QUERY;
|
||||
} else {
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_QUERY;
|
||||
}
|
||||
}
|
||||
|
||||
function onParseHashComplete(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
const ctx = this[context];
|
||||
if (fragment) {
|
||||
ctx.fragment = fragment;
|
||||
ctx.flags |= binding.URL_FLAGS_HAS_FRAGMENT;
|
||||
} else {
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_FRAGMENT;
|
||||
}
|
||||
}
|
||||
|
||||
class URL {
|
||||
@ -121,33 +222,34 @@ class URL {
|
||||
}
|
||||
|
||||
get [special]() {
|
||||
return (this[context].flags & binding.URL_FLAGS_SPECIAL) != 0;
|
||||
return (this[context].flags & binding.URL_FLAGS_SPECIAL) !== 0;
|
||||
}
|
||||
|
||||
get [cannotBeBase]() {
|
||||
return (this[context].flags & binding.URL_FLAGS_CANNOT_BE_BASE) != 0;
|
||||
return (this[context].flags & binding.URL_FLAGS_CANNOT_BE_BASE) !== 0;
|
||||
}
|
||||
|
||||
inspect(depth, opts) {
|
||||
const ctx = this[context];
|
||||
var ret = 'URL {\n';
|
||||
ret += ` href: ${this.href}\n`;
|
||||
if (this[context].scheme !== undefined)
|
||||
if (ctx.scheme !== undefined)
|
||||
ret += ` protocol: ${this.protocol}\n`;
|
||||
if (this[context].username !== undefined)
|
||||
if (ctx.username !== undefined)
|
||||
ret += ` username: ${this.username}\n`;
|
||||
if (this[context].password !== undefined) {
|
||||
const pwd = opts.showHidden ? this[context].password : '--------';
|
||||
if (ctx.password !== undefined) {
|
||||
const pwd = opts.showHidden ? ctx.password : '--------';
|
||||
ret += ` password: ${pwd}\n`;
|
||||
}
|
||||
if (this[context].host !== undefined)
|
||||
if (ctx.host !== undefined)
|
||||
ret += ` hostname: ${this.hostname}\n`;
|
||||
if (this[context].port !== undefined)
|
||||
if (ctx.port !== undefined)
|
||||
ret += ` port: ${this.port}\n`;
|
||||
if (this[context].path !== undefined)
|
||||
if (ctx.path !== undefined)
|
||||
ret += ` pathname: ${this.pathname}\n`;
|
||||
if (this[context].query !== undefined)
|
||||
if (ctx.query !== undefined)
|
||||
ret += ` search: ${this.search}\n`;
|
||||
if (this[context].fragment !== undefined)
|
||||
if (ctx.fragment !== undefined)
|
||||
ret += ` hash: ${this.hash}\n`;
|
||||
if (opts.showHidden) {
|
||||
ret += ` cannot-be-base: ${this[cannotBeBase]}\n`;
|
||||
@ -171,18 +273,19 @@ Object.defineProperties(URL.prototype, {
|
||||
options.fragment !== undefined ?
|
||||
!!options.fragment : true;
|
||||
const unicode = !!options.unicode;
|
||||
const ctx = this[context];
|
||||
var ret;
|
||||
if (this.protocol)
|
||||
ret = this.protocol;
|
||||
if (this[context].host !== undefined) {
|
||||
if (ctx.host !== undefined) {
|
||||
ret += '//';
|
||||
const has_username = typeof this[context].username === 'string';
|
||||
const has_password = typeof this[context].password === 'string';
|
||||
const has_username = typeof ctx.username === 'string';
|
||||
const has_password = typeof ctx.password === 'string';
|
||||
if (has_username || has_password) {
|
||||
if (has_username)
|
||||
ret += this[context].username;
|
||||
ret += ctx.username;
|
||||
if (has_password)
|
||||
ret += `:${this[context].password}`;
|
||||
ret += `:${ctx.password}`;
|
||||
ret += '@';
|
||||
}
|
||||
if (unicode) {
|
||||
@ -192,15 +295,15 @@ Object.defineProperties(URL.prototype, {
|
||||
} else {
|
||||
ret += this.host;
|
||||
}
|
||||
} else if (this[context].scheme === 'file:') {
|
||||
} else if (ctx.scheme === 'file:') {
|
||||
ret += '//';
|
||||
}
|
||||
if (this.pathname)
|
||||
ret += this.pathname;
|
||||
if (typeof this[context].query === 'string')
|
||||
ret += `?${this[context].query}`;
|
||||
if (fragment & typeof this[context].fragment === 'string')
|
||||
ret += `#${this[context].fragment}`;
|
||||
if (typeof ctx.query === 'string')
|
||||
ret += `?${ctx.query}`;
|
||||
if (fragment & typeof ctx.fragment === 'string')
|
||||
ret += `#${ctx.fragment}`;
|
||||
return ret;
|
||||
}
|
||||
},
|
||||
@ -231,33 +334,8 @@ Object.defineProperties(URL.prototype, {
|
||||
scheme = String(scheme);
|
||||
if (scheme.length === 0)
|
||||
return;
|
||||
binding.parse(scheme,
|
||||
binding.kSchemeStart,
|
||||
null,
|
||||
this[context],
|
||||
(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) => {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
const newIsSpecial = (flags & binding.URL_FLAGS_SPECIAL) != 0;
|
||||
if ((this[special] && !newIsSpecial) ||
|
||||
(!this[special] && newIsSpecial) ||
|
||||
(newIsSpecial && !this[special] &&
|
||||
this[context].host === undefined)) {
|
||||
return;
|
||||
}
|
||||
if (newIsSpecial) {
|
||||
this[context].flags |= binding.URL_FLAGS_SPECIAL;
|
||||
} else {
|
||||
this[context].flags &= ~binding.URL_FLAGS_SPECIAL;
|
||||
}
|
||||
if (protocol) {
|
||||
this[context].scheme = protocol;
|
||||
this[context].flags |= binding.URL_FLAGS_HAS_SCHEME;
|
||||
} else {
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_SCHEME;
|
||||
}
|
||||
});
|
||||
binding.parse(scheme, binding.kSchemeStart, null, this[context],
|
||||
onParseProtocolComplete.bind(this));
|
||||
}
|
||||
},
|
||||
username: {
|
||||
@ -270,13 +348,14 @@ Object.defineProperties(URL.prototype, {
|
||||
username = String(username);
|
||||
if (!this.hostname)
|
||||
return;
|
||||
const ctx = this[context];
|
||||
if (!username) {
|
||||
this[context].username = null;
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_USERNAME;
|
||||
ctx.username = null;
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_USERNAME;
|
||||
return;
|
||||
}
|
||||
this[context].username = binding.encodeAuth(username);
|
||||
this[context].flags |= binding.URL_FLAGS_HAS_USERNAME;
|
||||
ctx.username = binding.encodeAuth(username);
|
||||
ctx.flags |= binding.URL_FLAGS_HAS_USERNAME;
|
||||
}
|
||||
},
|
||||
password: {
|
||||
@ -289,25 +368,28 @@ Object.defineProperties(URL.prototype, {
|
||||
password = String(password);
|
||||
if (!this.hostname)
|
||||
return;
|
||||
const ctx = this[context];
|
||||
if (!password) {
|
||||
this[context].password = null;
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_PASSWORD;
|
||||
ctx.password = null;
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_PASSWORD;
|
||||
return;
|
||||
}
|
||||
this[context].password = binding.encodeAuth(password);
|
||||
this[context].flags |= binding.URL_FLAGS_HAS_PASSWORD;
|
||||
ctx.password = binding.encodeAuth(password);
|
||||
ctx.flags |= binding.URL_FLAGS_HAS_PASSWORD;
|
||||
}
|
||||
},
|
||||
host: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get() {
|
||||
var ret = this[context].host || '';
|
||||
if (this[context].port !== undefined)
|
||||
ret += `:${this[context].port}`;
|
||||
const ctx = this[context];
|
||||
var ret = ctx.host || '';
|
||||
if (ctx.port !== undefined)
|
||||
ret += `:${ctx.port}`;
|
||||
return ret;
|
||||
},
|
||||
set(host) {
|
||||
const ctx = this[context];
|
||||
host = String(host);
|
||||
if (this[cannotBeBase] ||
|
||||
(this[special] && host.length === 0)) {
|
||||
@ -316,24 +398,12 @@ Object.defineProperties(URL.prototype, {
|
||||
return;
|
||||
}
|
||||
if (!host) {
|
||||
this[context].host = null;
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_HOST;
|
||||
ctx.host = null;
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_HOST;
|
||||
return;
|
||||
}
|
||||
binding.parse(host, binding.kHost, null, this[context],
|
||||
(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) => {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
if (host) {
|
||||
this[context].host = host;
|
||||
this[context].flags |= binding.URL_FLAGS_HAS_HOST;
|
||||
} else {
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_HOST;
|
||||
}
|
||||
if (port !== undefined)
|
||||
this[context].port = port;
|
||||
});
|
||||
binding.parse(host, binding.kHost, null, ctx,
|
||||
onParseHostComplete.bind(this));
|
||||
}
|
||||
},
|
||||
hostname: {
|
||||
@ -343,6 +413,7 @@ Object.defineProperties(URL.prototype, {
|
||||
return this[context].host || '';
|
||||
},
|
||||
set(host) {
|
||||
const ctx = this[context];
|
||||
host = String(host);
|
||||
if (this[cannotBeBase] ||
|
||||
(this[special] && host.length === 0)) {
|
||||
@ -351,25 +422,12 @@ Object.defineProperties(URL.prototype, {
|
||||
return;
|
||||
}
|
||||
if (!host) {
|
||||
this[context].host = null;
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_HOST;
|
||||
ctx.host = null;
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_HOST;
|
||||
return;
|
||||
}
|
||||
binding.parse(host,
|
||||
binding.kHostname,
|
||||
null,
|
||||
this[context],
|
||||
(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) => {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
if (host) {
|
||||
this[context].host = host;
|
||||
this[context].flags |= binding.URL_FLAGS_HAS_HOST;
|
||||
} else {
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_HOST;
|
||||
}
|
||||
});
|
||||
binding.parse(host, binding.kHostname, null, ctx,
|
||||
onParseHostnameComplete.bind(this));
|
||||
}
|
||||
},
|
||||
port: {
|
||||
@ -380,7 +438,8 @@ Object.defineProperties(URL.prototype, {
|
||||
return port === undefined ? '' : String(port);
|
||||
},
|
||||
set(port) {
|
||||
if (!this[context].host || this[cannotBeBase] ||
|
||||
const ctx = this[context];
|
||||
if (!ctx.host || this[cannotBeBase] ||
|
||||
this.protocol === 'file:')
|
||||
return;
|
||||
port = String(port);
|
||||
@ -389,76 +448,46 @@ Object.defineProperties(URL.prototype, {
|
||||
// TODO(jasnell): This might be changing in the spec
|
||||
return;
|
||||
}
|
||||
binding.parse(port, binding.kPort, null, this[context],
|
||||
(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) => {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
this[context].port = port;
|
||||
});
|
||||
binding.parse(port, binding.kPort, null, ctx,
|
||||
onParsePortComplete.bind(this));
|
||||
}
|
||||
},
|
||||
pathname: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get() {
|
||||
const ctx = this[context];
|
||||
if (this[cannotBeBase])
|
||||
return this[context].path[0];
|
||||
return this[context].path !== undefined ?
|
||||
`/${this[context].path.join('/')}` : '';
|
||||
return ctx.path[0];
|
||||
return ctx.path !== undefined ? `/${ctx.path.join('/')}` : '';
|
||||
},
|
||||
set(path) {
|
||||
if (this[cannotBeBase])
|
||||
return;
|
||||
path = String(path);
|
||||
binding.parse(path,
|
||||
binding.kPathStart,
|
||||
null,
|
||||
this[context],
|
||||
(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) => {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
if (path) {
|
||||
this[context].path = path;
|
||||
this[context].flags |= binding.URL_FLAGS_HAS_PATH;
|
||||
} else {
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_PATH;
|
||||
}
|
||||
});
|
||||
binding.parse(String(path), binding.kPathStart, null, this[context],
|
||||
onParsePathComplete.bind(this));
|
||||
}
|
||||
},
|
||||
search: {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get() {
|
||||
return !this[context].query ? '' : `?${this[context].query}`;
|
||||
const ctx = this[context];
|
||||
return !ctx.query ? '' : `?${ctx.query}`;
|
||||
},
|
||||
set(search) {
|
||||
const ctx = this[context];
|
||||
search = String(search);
|
||||
if (search[0] === '?') search = search.slice(1);
|
||||
if (!search) {
|
||||
this[context].query = null;
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_QUERY;
|
||||
ctx.query = null;
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_QUERY;
|
||||
this[searchParams][searchParams] = {};
|
||||
return;
|
||||
}
|
||||
this[context].query = '';
|
||||
binding.parse(search,
|
||||
binding.kQuery,
|
||||
null,
|
||||
this[context],
|
||||
(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) => {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
if (query) {
|
||||
this[context].query = query;
|
||||
this[context].flags |= binding.URL_FLAGS_HAS_QUERY;
|
||||
} else {
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_QUERY;
|
||||
}
|
||||
});
|
||||
ctx.query = '';
|
||||
binding.parse(search, binding.kQuery, null, ctx,
|
||||
onParseSearchComplete.bind(this));
|
||||
this[searchParams][searchParams] = querystring.parse(search);
|
||||
}
|
||||
},
|
||||
@ -473,39 +502,29 @@ Object.defineProperties(URL.prototype, {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get() {
|
||||
return !this[context].fragment ? '' : `#${this[context].fragment}`;
|
||||
const ctx = this[context];
|
||||
return !ctx.fragment ? '' : `#${ctx.fragment}`;
|
||||
},
|
||||
set(hash) {
|
||||
const ctx = this[context];
|
||||
hash = String(hash);
|
||||
if (this.protocol === 'javascript:')
|
||||
return;
|
||||
if (!hash) {
|
||||
this[context].fragment = null;
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_FRAGMENT;
|
||||
ctx.fragment = null;
|
||||
ctx.flags &= ~binding.URL_FLAGS_HAS_FRAGMENT;
|
||||
return;
|
||||
}
|
||||
if (hash[0] === '#') hash = hash.slice(1);
|
||||
this[context].fragment = '';
|
||||
binding.parse(hash,
|
||||
binding.kFragment,
|
||||
null,
|
||||
this[context],
|
||||
(flags, protocol, username, password,
|
||||
host, port, path, query, fragment) => {
|
||||
if (flags & binding.URL_FLAGS_FAILED)
|
||||
return;
|
||||
if (fragment) {
|
||||
this[context].fragment = fragment;
|
||||
this[context].flags |= binding.URL_FLAGS_HAS_FRAGMENT;
|
||||
} else {
|
||||
this[context].flags &= ~binding.URL_FLAGS_HAS_FRAGMENT;
|
||||
}
|
||||
});
|
||||
ctx.fragment = '';
|
||||
binding.parse(hash, binding.kFragment, null, ctx,
|
||||
onParseHashComplete.bind(this));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var hexTable = new Array(256);
|
||||
const hexTable = new Array(256);
|
||||
|
||||
for (var i = 0; i < 256; ++i)
|
||||
hexTable[i] = '%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase();
|
||||
function encodeAuth(str) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user