@fly/edge
Version:
Fly's TypeScript Edge
176 lines • 26.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.rewriteLocationHeader = exports.buildProxyRequest = exports.proxy = void 0;
function sleep(ms) {
return new Promise((resolve, _) => {
setTimeout(resolve, ms);
});
}
/**
* This generates a `fetch` like function for proxying requests to a given origin.
* When this function makes origin requests, it adds standard proxy headers like
* `X-Forwarded-Host` and `X-Forwarded-For`. It also passes headers from the original
* request to the origin.
* @param origin A URL to an origin, can include a path to rebase requests.
* @param options Options and headers to control origin request.
*/
function proxy(origin, options) {
if (!options) {
options = {};
}
if (options.errorTo503 !== false) {
options.errorTo503 = true;
}
options.origin = origin.toString();
const fetchFn = options.fetch || fetch;
async function proxyFetch(req, init) {
if (!(req instanceof Request)) {
req = new Request(req, init);
init = undefined;
}
if (!options) {
options = {};
}
const breq = buildProxyRequest(origin, options, req, init);
const retries = options.retries || 0;
const delayMS = 100;
let tryCount = 0;
do {
if (tryCount > 0) {
console.warn("Retrying request:", tryCount, "in", delayMS * tryCount * tryCount, "ms");
await sleep(Math.min(delayMS * tryCount * tryCount, 5000));
breq.headers.set("Fly-Proxy-Retry", tryCount.toString());
}
tryCount += 1;
try {
let bresp = await fetchFn(breq.clone(), { certificate: options.certificate, tls: options.tls });
if (options.rewriteLocationHeaders !== false) {
bresp = rewriteLocationHeader(req.url, breq.url, bresp);
}
return bresp; // breaks loop on successful response
}
catch (err) {
if (tryCount < retries) {
continue;
}
if (!options.errorTo503)
throw err; // breaks loop
}
} while (tryCount <= retries);
return new Response("origin error", { status: 503 });
}
return Object.assign(proxyFetch, { proxyConfig: options });
}
exports.proxy = proxy;
/**
* @protected
* @hidden
* @param origin
* @param options
* @param req
* @param init
*/
function buildProxyRequest(origin, options, req, init) {
if (typeof req === "string") {
req = new Request(req, init);
init = undefined;
}
if (!(req instanceof Request)) {
throw new Error("req must be either a string or a Request object");
}
const url = new URL(req.url);
let breq = null;
breq = req.clone();
if (typeof origin === "string") {
origin = new URL(origin);
}
const requestedHostname = req.headers.get("host") || url.hostname;
url.hostname = origin.hostname;
url.protocol = origin.protocol;
url.port = origin.port;
if (options.stripPath && typeof options.stripPath === "string") {
// remove basePath so we can serve `onehosthame.com/dir/` from `origin.com/`
url.pathname = url.pathname.substring(options.stripPath.length);
}
if (origin.pathname && origin.pathname.length > 0) {
url.pathname = [origin.pathname.replace(/\/$/, ""), url.pathname.replace(/^\//, "")].join("/");
}
if (url.pathname.startsWith("//")) {
url.pathname = url.pathname.substring(1);
}
if (url.toString() !== breq.url) {
breq = new Request(url.toString(), breq);
}
// we extend req with remoteAddr
if (req.remoteAddr) {
breq.headers.set("x-forwarded-for", req.remoteAddr);
}
breq.headers.set("x-forwarded-host", requestedHostname);
breq.headers.set("x-forwarded-proto", url.protocol.replace(":", ""));
if (!options.forwardHostHeader) {
// set host header to origin.hostnames
breq.headers.set("host", origin.hostname);
}
if (options.headers) {
for (const h of Object.getOwnPropertyNames(options.headers)) {
const v = options.headers[h];
if (v === false) {
breq.headers.delete(h);
}
else if (v && typeof v === "string") {
breq.headers.set(h, v);
}
}
}
return breq;
}
exports.buildProxyRequest = buildProxyRequest;
function rewriteLocationHeader(url, burl, resp) {
const locationHeader = resp.headers.get("location");
if (!locationHeader) {
return resp;
}
if (typeof url === "string") {
url = new URL(url);
}
if (typeof burl === "string") {
burl = new URL(burl);
}
const location = new URL(locationHeader, burl);
if (location.hostname !== burl.hostname || location.protocol !== burl.protocol) {
return resp;
}
let pathname = location.pathname;
if (url.pathname.endsWith(burl.pathname)) {
// url path: /original/path/
// burl path: /path/
// need to prefix base
const prefix = url.pathname.substring(0, url.pathname.length - burl.pathname.length);
pathname = prefix + location.pathname;
}
else if (burl.pathname.endsWith(url.pathname)) {
// url path: /original/path/
// burl path: /path/
// need to remove prefix
const remove = burl.pathname.substring(0, burl.pathname.length - url.pathname.length);
if (location.pathname.startsWith(remove)) {
pathname = location.pathname.substring(remove.length, location.pathname.length);
}
}
if (pathname !== location.pathname) {
// do the rewrite
location.pathname = pathname;
location.protocol = url.protocol;
location.hostname = url.hostname;
resp.headers.set("location", location.toString());
}
return resp;
}
exports.rewriteLocationHeader = rewriteLocationHeader;
/*
Requests with rewrites:
- https://example.com/blog/ -> https://example.blogservice.com/
- strip /blog/ to backend (proxy function does this)
- prepend /blog/ to location headers on response
*/
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcHJveHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBaUNBLFNBQVMsS0FBSyxDQUFDLEVBQVU7SUFDdkIsT0FBTyxJQUFJLE9BQU8sQ0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUN0QyxVQUFVLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFBO0lBQ3pCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUNEOzs7Ozs7O0dBT0c7QUFDSCxTQUFnQixLQUFLLENBQUMsTUFBb0IsRUFBRSxPQUFzQjtJQUNoRSxJQUFJLENBQUMsT0FBTyxFQUFFO1FBQ1osT0FBTyxHQUFHLEVBQUUsQ0FBQTtLQUNiO0lBQ0QsSUFBRyxPQUFPLENBQUMsVUFBVSxLQUFLLEtBQUssRUFBQztRQUM5QixPQUFPLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztLQUMzQjtJQUNELE9BQU8sQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ25DLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxLQUFLLElBQUksS0FBSyxDQUFDO0lBQ3ZDLEtBQUssVUFBVSxVQUFVLENBQUMsR0FBZ0IsRUFBRSxJQUFrQjtRQUM1RCxJQUFHLENBQUMsQ0FBQyxHQUFHLFlBQVksT0FBTyxDQUFDLEVBQUM7WUFDM0IsR0FBRyxHQUFHLElBQUksT0FBTyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQztZQUM3QixJQUFJLEdBQUcsU0FBUyxDQUFDO1NBQ2xCO1FBQ0QsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNaLE9BQU8sR0FBRyxFQUFFLENBQUE7U0FDYjtRQUNELE1BQU0sSUFBSSxHQUFHLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFBO1FBQzFELE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLElB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QVEsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQTtTQUNoRjtLQUNGO0lBQ0QsSUFBRyxRQUFRLEtBQUssUUFBUSxDQUFDLFFBQVEsRUFBQztRQUNoQyxpQkFBaUI7UUFDakIsUUFBUSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUE7UUFDNUIsUUFBUSxDQUFDLFFBQVEsR0FBRyxHQUFHLENBQUMsUUFBUSxDQUFBO1FBQ2hDLFFBQVEsQ0FBQyxRQUFRLEdBQUcsR0FBRyxDQUFDLFFBQVEsQ0FBQTtRQUNoQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsUUFBUSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUE7S0FDbEQ7SUFFRCxPQUFPLElBQUksQ0FBQTtBQUNiLENBQUM7QUE1Q0Qsc0RBNENDO0FBOEZEOzs7OztFQUtFIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBMaWJyYXJ5IGZvciBwcm94eWluZyByZXF1ZXN0cyB0byBvcmlnaW5zLiBVc2UgdGhpcyB0byBjcmVhdGUgYGZldGNoYCBsaWtlIGZ1bmN0aW9uc1xuICogIGZvciBtYWtpbmcgcmVxdWVzdHMgdG8gb3RoZXIgc2VydmljZXMuIEZvciBleGFtcGxlOlxuICpcbiAqIGBgYGphdmFzY3JpcHRcbiAqIC8vIHNlbmRzIGFsbCB0cmFmZmljIHRvIGFuIEFtYXpvbiBFTEIsXG4gKiAvLyBgSG9zdGAgaGVhZGVyIHBhc3NlcyB0aHJvdWdoIGZyb20gdmlzaXRvciByZXF1ZXN0XG4gKiBjb25zdCBvcmlnaW4gPSBwcm94eShcImh0dHBzOi8vZWxiMTI5OC5hbWF6b25hd3MuY29tXCIpXG4gKiBgYGBcbiAqXG4gKiBCeSBkZWZhdWx0LCB0aGlzIGZ1bmN0aW9uIHNlbmRzIHRoZSBgSG9zdGAgaGVhZGVyIGluZmVycmVkIGZyb20gdGhlIG9yaWdpbiBVUkwuIFRvIGZvcndhcmRcbiAqIGhvc3QgaGVhZGVycyBzZW50IGJ5IHZpc2l0b3JzLCBzZXQgYGZvcndhcmRIb3N0SGVhZGVyYCB0byB0cnVlLlxuICpcbiAqIGBgYGphdmFzY3JpcHRcbiAqIC8vIHNlbmRzIGFsbCB0cmFmZmljIHRvIGFuIEFtYXpvbiBFTEIsIGluY2x1ZGUgaG9zdCBoZWFkZXIgZnJvbSBvcmlnaW5hbCByZXF1ZXN0LlxuICogY29uc3Qgb3JpZ2luID0gcHJveHkoXCJodHRwczovL2VsYjEyOTguYW1hem9uYXdzLmNvbVwiLCB7XG4gKiAgZm9yd2FyZEhvc3RIZWFkZXI6IHRydWVcbiAqIH0pXG4gKiBgYGBcbiAqXG4gKiBBbmQgdGhlbiB3YXkgbW9yZSByYXJlLCBubyBob3N0IGhlYWRlciBhdCBhbGwuIFVzdWFsbHkgeW91J2Qgc3RyaXAgb3V0IGB4LWZvcndhcmRlZC1ob3N0YCxcbiAqIHNpbmNlIHNvbWUgb3JpZ2lucyBkb24ndCBsaWtlIHRoYXQ6XG4gKiBgYGBqYXZhc2NyaXB0XG4gKiAvLyBzZW5kcyBhbGwgdHJhZmZpYyB0byBhbiBBbWF6b24gRUxCLCBuZXZlciBzZW5kcyBhIGhvc3QgaGVhZGVyXG4gKiBjb25zdCBvcmlnaW4gPSBwcm94eShcImh0dHBzOi8vZWxiMTI5OC5hbWF6b25hd3MuY29tXCIsIHtcbiAqICBoZWFkZXJzOiB7IGhvc3Q6IGZhbHNlfVxuICogfSlcbiAqIGBgYFxuICpcbiAqIEBwcmVmZXJyZWRcbiAqIEBtb2R1bGUgSFRUUFxuICovXG5pbXBvcnQgeyBub3JtYWxpemVSZXF1ZXN0LCBGZXRjaEZ1bmN0aW9uIH0gZnJvbSBcIi4vZmV0Y2hcIlxuZnVuY3Rpb24gc2xlZXAobXM6IG51bWJlcil7XG4gIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgXykgPT4ge1xuICAgIHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpXG4gIH0pO1xufVxuLyoqXG4gKiBUaGlzIGdlbmVyYXRlcyBhIGBmZXRjaGAgbGlrZSBmdW5jdGlvbiBmb3IgcHJveHlpbmcgcmVxdWVzdHMgdG8gYSBnaXZlbiBvcmlnaW4uXG4gKiBXaGVuIHRoaXMgZnVuY3Rpb24gbWFrZXMgb3JpZ2luIHJlcXVlc3RzLCBpdCBhZGRzIHN0YW5kYXJkIHByb3h5IGhlYWRlcnMgbGlrZVxuICogYFgtRm9yd2FyZGVkLUhvc3RgIGFuZCBgWC1Gb3J3YXJkZWQtRm9yYC4gSXQgYWxzbyBwYXNzZXMgaGVhZGVycyBmcm9tIHRoZSBvcmlnaW5hbFxuICogcmVxdWVzdCB0byB0aGUgb3JpZ2luLlxuICogQHBhcmFtIG9yaWdpbiBBIFVSTCB0byBhbiBvcmlnaW4sIGNhbiBpbmNsdWRlIGEgcGF0aCB0byByZWJhc2UgcmVxdWVzdHMuXG4gKiBAcGFyYW0gb3B0aW9ucyBPcHRpb25zIGFuZCBoZWFkZXJzIHRvIGNvbnRyb2wgb3JpZ2luIHJlcXVlc3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcm94eShvcmlnaW46IHN0cmluZyB8IFVSTCwgb3B0aW9ucz86IFByb3h5T3B0aW9ucyk6IFByb3h5RnVuY3Rpb248UHJveHlPcHRpb25zPiB7XG4gIGlmICghb3B0aW9ucykge1xuICAgIG9wdGlvbnMgPSB7fVxuICB9XG4gIGlmKG9wdGlvbnMuZXJyb3JUbzUwMyAhPT0gZmFsc2Upe1xuICAgIG9wdGlvbnMuZXJyb3JUbzUwMyA9IHRydWU7XG4gIH1cbiAgb3B0aW9ucy5vcmlnaW4gPSBvcmlnaW4udG9TdHJpbmcoKTtcbiAgY29uc3QgZmV0Y2hGbiA9IG9wdGlvbnMuZmV0Y2ggfHwgZmV0Y2g7XG4gIGFzeW5jIGZ1bmN0aW9uIHByb3h5RmV0Y2gocmVxOiBSZXF1ZXN0SW5mbywgaW5pdD86IFJlcXVlc3RJbml0KSB7XG4gICAgaWYoIShyZXEgaW5zdGFuY2VvZiBSZXF1ZXN0KSl7XG4gICAgICByZXEgPSBuZXcgUmVxdWVzdChyZXEsIGluaXQpO1xuICAgICAgaW5pdCA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgaWYgKCFvcHRpb25zKSB7XG4gICAgICBvcHRpb25zID0ge31cbiAgICB9XG4gICAgY29uc3QgYnJlcSA9IGJ1aWxkUHJveHlSZXF1ZXN0KG9yaWdpbiwgb3B0aW9ucywgcmVxLCBpbml0KVxuICAgIGNvbnN0IHJldHJpZXMgPSBvcHRpb25zLnJldHJpZXMgfHwgMDtcbiAgICBjb25zdCBkZWxheU1TID0gMTAwO1xuICAgIGxldCB0cnlDb3VudCA9IDA7XG4gICAgZG8ge1xuICAgICAgaWYodHJ5Q291bnQgPiAwKXtcbiAgICAgICAgY29uc29sZS53YXJuKFwiUmV0cnlpbmcgcmVxdWVzdDpcIiwgdHJ5Q291bnQsIFwiaW5cIiwgZGVsYXlNUyAqIHRyeUNvdW50ICogdHJ5Q291bnQsIFwibXNcIilcbiAgICAgICAgYXdhaXQgc2xlZXAoTWF0aC5taW4oZGVsYXlNUyAqIHRyeUNvdW50ICogdHJ5Q291bnQsIDUwMDApKTtcbiAgICAgICAgYnJlcS5oZWFkZXJzLnNldChcIkZseS1Qcm94eS1SZXRyeVwiLCB0cnlDb3VudC50b1N0cmluZygpKTtcbiAgICAgIH1cbiAgICAgIHRyeUNvdW50ICs9IDE7XG4gICAgICB0cnl7XG4gICAgICAgIGxldCBicmVzcCA9IGF3YWl0IGZldGNoRm4oYnJlcS5jbG9uZSgpLCB7IGNlcnRpZmljYXRlOiBvcHRpb25zLmNlcnRpZmljYXRlLCB0bHM6IG9wdGlvbnMudGxzIH0pXG4gICAgICAgIGlmKG9wdGlvbnMucmV3cml0ZUxvY2F0aW9uSGVhZGVycyAhPT0gZmFsc2Upe1xuICAgICAgICAgIGJyZXNwID0gcmV3cml0ZUxvY2F0aW9uSGVhZGVyKHJlcS51cmwsIGJyZXEudXJsLCBicmVzcClcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYnJlc3AgLy8gYnJlYWtzIGxvb3Agb24gc3VjY2Vzc2Z1bCByZXNwb25zZVxuICAgICAgfWNhdGNoKGVycil7XG4gICAgICAgIGlmKHRyeUNvdW50IDwgcmV0cmllcyl7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgaWYoIW9wdGlvbnMuZXJyb3JUbzUwMykgdGhyb3cgZXJyOyAvLyBicmVha3MgbG9vcFxuICAgICAgfVxuICAgIH0gd2hpbGUodHJ5Q291bnQgPD0gcmV0cmllcyk7XG4gICAgcmV0dXJuIG5ldyBSZXNwb25zZShcIm9yaWdpbiBlcnJvclwiLCB7IHN0YXR1czogNTAzIH0pXG4gIH1cblxuICByZXR1cm4gT2JqZWN0LmFzc2lnbihwcm94eUZldGNoLCB7IHByb3h5Q29uZmlnOiBvcHRpb25zfSlcbn1cblxuLyoqXG4gKiBAcHJvdGVjdGVkXG4gKiBAaGlkZGVuXG4gKiBAcGFyYW0gb3JpZ2luXG4gKiBAcGFyYW0gb3B0aW9uc1xuICogQHBhcmFtIHJlcVxuICogQHBhcmFtIGluaXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkUHJveHlSZXF1ZXN0KG9yaWdpbjogc3RyaW5nIHwgVVJMLCBvcHRpb25zOiBQcm94eU9wdGlvbnMsIHJlcTogUmVxdWVzdEluZm8sIGluaXQ/OiBSZXF1ZXN0SW5pdCkge1xuICBpZiAodHlwZW9mIHJlcSA9PT0gXCJzdHJpbmdcIikge1xuICAgIHJlcSA9IG5ldyBSZXF1ZXN0KHJlcSwgaW5pdClcbiAgICBpbml0ID0gdW5kZWZpbmVkXG4gIH1cblxuICBpZiAoIShyZXEgaW5zdGFuY2VvZiBSZXF1ZXN0KSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcInJlcSBtdXN0IGJlIGVpdGhlciBhIHN0cmluZyBvciBhIFJlcXVlc3Qgb2JqZWN0XCIpXG4gIH1cblxuICBjb25zdCB1cmwgPSBuZXcgVVJMKHJlcS51cmwpXG4gIGxldCBicmVxOiBSZXF1ZXN0IHwgbnVsbCA9IG51bGxcblxuICBicmVxID0gcmVxLmNsb25lKClcblxuICBpZiAodHlwZW9mIG9yaWdpbiA9PT0gXCJzdHJpbmdcIikge1xuICAgIG9yaWdpbiA9IG5ldyBVUkwob3JpZ2luKVxuICB9XG5cbiAgY29uc3QgcmVxdWVzdGVkSG9zdG5hbWUgPSByZXEuaGVhZGVycy5nZXQoXCJob3N0XCIpIHx8IHVybC5ob3N0bmFtZVxuICB1cmwuaG9zdG5hbWUgPSBvcmlnaW4uaG9zdG5hbWVcbiAgdXJsLnByb3RvY29sID0gb3JpZ2luLnByb3RvY29sXG4gIHVybC5wb3J0ID0gb3JpZ2luLnBvcnRcblxuICBpZiAob3B0aW9ucy5zdHJpcFBhdGggJiYgdHlwZW9mIG9wdGlvbnMuc3RyaXBQYXRoID09PSBcInN0cmluZ1wiKSB7XG4gICAgLy8gcmVtb3ZlIGJhc2VQYXRoIHNvIHdlIGNhbiBzZXJ2ZSBgb25laG9zdGhhbWUuY29tL2Rpci9gIGZyb20gYG9yaWdpbi5jb20vYFxuICAgIHVybC5wYXRobmFtZSA9IHVybC5wYXRobmFtZS5zdWJzdHJpbmcob3B0aW9ucy5zdHJpcFBhdGgubGVuZ3RoKVxuICB9XG4gIGlmIChvcmlnaW4ucGF0aG5hbWUgJiYgb3JpZ2luLnBhdGhuYW1lLmxlbmd0aCA+IDApIHtcbiAgICB1cmwucGF0aG5hbWUgPSBbb3JpZ2luLnBhdGhuYW1lLnJlcGxhY2UoL1xcLyQvLCBcIlwiKSwgdXJsLnBhdGhuYW1lLnJlcGxhY2UoL15cXC8vLCBcIlwiKV0uam9pbihcIi9cIilcbiAgfVxuICBpZiAodXJsLnBhdGhuYW1lLnN0YXJ0c1dpdGgoXCIvL1wiKSkge1xuICAgIHVybC5wYXRobmFtZSA9IHVybC5wYXRobmFtZS5zdWJzdHJpbmcoMSlcbiAgfVxuXG4gIGlmICh1cmwudG9TdHJpbmcoKSAhPT0gYnJlcS51cmwpIHtcbiAgICBicmVxID0gbmV3IFJlcXVlc3QodXJsLnRvU3RyaW5nKCksIGJyZXEpXG4gIH1cbiAgLy8gd2UgZXh0ZW5kIHJlcSB3aXRoIHJlbW90ZUFkZHJcbiAgaWYocmVxLnJlbW90ZUFkZHIpe1xuICAgIGJyZXEuaGVhZGVycy5zZXQoXCJ4LWZvcndhcmRlZC1mb3JcIiwgcmVxLnJlbW90ZUFkZHIpXG4gIH1cbiAgYnJlcS5oZWFkZXJzLnNldChcIngtZm9yd2FyZGVkLWhvc3RcIiwgcmVxdWVzdGVkSG9zdG5hbWUpXG4gIGJyZXEuaGVhZGVycy5zZXQoXCJ4LWZvcndhcmRlZC1wcm90b1wiLCB1cmwucHJvdG9jb2wucmVwbGFjZShcIjpcIiwgXCJcIikpXG5cbiAgaWYgKCFvcHRpb25zLmZvcndhcmRIb3N0SGVhZGVyKSB7XG4gICAgLy8gc2V0IGhvc3QgaGVhZGVyIHRvIG9yaWdpbi5ob3N0bmFtZXNcbiAgICBicmVxLmhlYWRlcnMuc2V0KFwiaG9zdFwiLCBvcmlnaW4uaG9zdG5hbWUpXG4gIH1cblxuICBpZiAob3B0aW9ucy5oZWFkZXJzKSB7XG4gICAgZm9yIChjb25zdCBoIG9mIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKG9wdGlvbnMuaGVhZGVycykpIHtcbiAgICAgIGNvbnN0IHYgPSBvcHRpb25zLmhlYWRlcnNbaF1cbiAgICAgIGlmICh2ID09PSBmYWxzZSkge1xuICAgICAgICBicmVxLmhlYWRlcnMuZGVsZXRlKGgpXG4gICAgICB9IGVsc2UgaWYgKHYgJiYgdHlwZW9mIHYgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgYnJlcS5oZWFkZXJzLnNldChoLCB2KVxuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gYnJlcTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJld3JpdGVMb2NhdGlvbkhlYWRlcih1cmw6IFVSTCB8IHN0cmluZywgYnVybDogVVJMIHwgc3RyaW5nLCByZXNwOiBSZXNwb25zZSl7XG4gIGNvbnN0IGxvY2F0aW9uSGVhZGVyID0gcmVzcC5oZWFkZXJzLmdldChcImxvY2F0aW9uXCIpXG4gIGlmKCFsb2NhdGlvbkhlYWRlcil7XG4gICAgcmV0dXJuIHJlc3BcbiAgfVxuICBpZih0eXBlb2YgdXJsID09PSBcInN0cmluZ1wiKXtcbiAgICB1cmwgPSBuZXcgVVJMKHVybClcbiAgfVxuICBpZih0eXBlb2YgYnVybCA9PT0gXCJzdHJpbmdcIil7XG4gICAgYnVybCA9IG5ldyBVUkwoYnVybClcbiAgfVxuICBjb25zdCBsb2NhdGlvbiA9IG5ldyBVUkwobG9jYXRpb25IZWFkZXIsIGJ1cmwpXG5cbiAgaWYobG9jYXRpb24uaG9zdG5hbWUgIT09IGJ1cmwuaG9zdG5hbWUgfHwgbG9jYXRpb24ucHJvdG9jb2wgIT09IGJ1cmwucHJvdG9jb2wpe1xuICAgIHJldHVybiByZXNwXG4gIH1cblxuXG4gIGxldCBwYXRobmFtZSA9IGxvY2F0aW9uLnBhdGhuYW1lXG4gIGlmKHVybC5wYXRobmFtZS5lbmRzV2l0aChidXJsLnBhdGhuYW1lKSl7XG4gICAgLy8gdXJsIHBhdGg6IC9vcmlnaW5hbC9wYXRoL1xuICAgIC8vIGJ1cmwgcGF0aDogL3BhdGgvXG4gICAgLy8gbmVlZCB0byBwcmVmaXggYmFzZVxuICAgIGNvbnN0IHByZWZpeCA9IHVybC5wYXRobmFtZS5zdWJzdHJpbmcoMCwgdXJsLnBhdGhuYW1lLmxlbmd0aCAtIGJ1cmwucGF0aG5hbWUubGVuZ3RoKVxuICAgIHBhdGhuYW1lID0gcHJlZml4ICsgbG9jYXRpb24ucGF0aG5hbWVcblxuICB9IGVsc2UgaWYoYnVybC5wYXRobmFtZS5lbmRzV2l0aCh1cmwucGF0aG5hbWUpKSB7XG4gICAgLy8gdXJsIHBhdGg6IC9vcmlnaW5hbC9wYXRoL1xuICAgIC8vIGJ1cmwgcGF0aDogL3BhdGgvXG4gICAgLy8gbmVlZCB0byByZW1vdmUgcHJlZml4XG4gICAgY29uc3QgcmVtb3ZlID0gYnVybC5wYXRobmFtZS5zdWJzdHJpbmcoMCwgYnVybC5wYXRobmFtZS5sZW5ndGggLSB1cmwucGF0aG5hbWUubGVuZ3RoKVxuICAgIGlmKGxvY2F0aW9uLnBhdGhuYW1lLnN0YXJ0c1dpdGgocmVtb3ZlKSl7XG4gICAgICBwYXRobmFtZSA9IGxvY2F0aW9uLnBhdGhuYW1lLnN1YnN0cmluZyhyZW1vdmUubGVuZ3RoLCBsb2NhdGlvbi5wYXRobmFtZS5sZW5ndGgpXG4gICAgfVxuICB9XG4gIGlmKHBhdGhuYW1lICE9PSBsb2NhdGlvbi5wYXRobmFtZSl7XG4gICAgLy8gZG8gdGhlIHJld3JpdGVcbiAgICBsb2NhdGlvbi5wYXRobmFtZSA9IHBhdGhuYW1lXG4gICAgbG9jYXRpb24ucHJvdG9jb2wgPSB1cmwucHJvdG9jb2xcbiAgICBsb2NhdGlvbi5ob3N0bmFtZSA9IHVybC5ob3N0bmFtZVxuICAgIHJlc3AuaGVhZGVycy5zZXQoXCJsb2NhdGlvblwiLCBsb2NhdGlvbi50b1N0cmluZygpKVxuICB9XG5cbiAgcmV0dXJuIHJlc3Bcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciBgcHJveHlgLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFByb3h5T3B0aW9ucyB7XG4gIC8qKlxuICAgKiBSZXBsYWNlIHRoaXMgcG9ydGlvbiBvZiBVUkwgcGF0aCBiZWZvcmUgbWFraW5nIHJlcXVlc3QgdG8gb3JpZ2luLlxuICAgKlxuICAgKiBGb3IgZXhhbXBsZSwgdGhpcyBtYWtlcyBhIHJlcXVlc3QgdG8gYGh0dHBzOi8vZmx5LmlvL3BhdGgxL3RvL2RvY3VtZW50Lmh0bWxgOlxuICAgKiBgYGBqYXZhc2NyaXB0XG4gICAqIGNvbnN0IG9wdHMgPSB7IHN0cmlwUGF0aDogXCIvcGF0aDIvXCJ9XG4gICAqIGNvbnN0IG9yaWdpbiA9IHByb3h5KFwiaHR0cHM6Ly9mbHkuaW8vcGF0aDEvXCIsIG9wdHMpXG4gICAqIG9yaWdpbihcImh0dHBzOi8vc29tZWhvc3RuYW1lLmNvbS9wYXRoMi90by9kb2N1bWVudC5odG1sXCIpXG4gICAqIGBgYFxuICAgKi9cbiAgc3RyaXBQYXRoPzogc3RyaW5nXG5cbiAgLyoqXG4gICAqIEZvcndhcmQgYEhvc3RgIGhlYWRlciBmcm9tIG9yaWdpbmFsIHJlcXVlc3QuIFdpdGhvdXQgdGhpcyBvcHRpb25zLFxuICAgKiBwcm94eSByZXF1ZXN0cyBpbmZlcnMgYSBob3N0IGhlYWRlciBmcm9tIHRoZSBvcmlnaW4gVVJMLlxuICAgKiBEZWZhdWx0cyB0byBgZmFsc2VgLlxuICAgKi9cbiAgZm9yd2FyZEhvc3RIZWFkZXI/OiBib29sZWFuXG5cbiAgLyoqXG4gICAqIFJld3JpdGUgbG9jYXRpb24gaGVhZGVycyAoZGVmYXVsdHMgdG8gdHJ1ZSkgdG8gbWF0Y2ggaW5jb21pbmcgcmVxdWVzdC5cbiAgICogXG4gICAqIEV4YW1wbGU6XG4gICAqICAtIFJlcXVlc3QgdXJsOiBodHRwOi8vdGVzdC5jb20vYmxvZy9hc2RmXG4gICAqICAtIFByb3h5IHVybDogaHR0cDovL29yaWdpbi5jb20vYXNkZlxuICAgKiAgLSBMb2NhdGlvbiBodHRwOi8vb3JpZ2luLmNvbS9qa2xtIGJjb21lcyBodHRwOi8vdGVzdC5jb20vYmxvZy9qa2xtXG4gICAqL1xuICByZXdyaXRlTG9jYXRpb25IZWFkZXJzPzogYm9vbGVhblxuICAvKipcbiAgICogSGVhZGVycyB0byBzZXQgb24gYmFja2VuZCByZXF1ZXN0LiBFYWNoIGhlYWRlciBhY2NlcHRzIGVpdGhlciBhIGBib29sZWFuYCBvciBgc3RyaW5nYC5cbiAgICogKiBJZiBzZXQgdG8gYGZhbHNlYCwgc3RyaXAgaGVhZGVyIGVudGlyZWx5IGJlZm9yZSBzZW5kaW5nLlxuICAgKiAqIGB0cnVlYCBvciBgdW5kZWZpbmVkYCBzZW5kIHRoZSBoZWFkZXIgdGhyb3VnaCB1bm1vZGlmaWVkIGZyb20gdGhlIG9yaWdpbmFsIHJlcXVlc3QuXG4gICAqICogYHN0cmluZ2AgaGVhZGVyIHZhbHVlcyBhcmUgc2VudCBhcyBpc1xuICAgKi9cbiAgaGVhZGVycz86IHtcbiAgICBba2V5OiBzdHJpbmddOiBzdHJpbmcgfCBib29sZWFuIHwgdW5kZWZpbmVkXG4gICAgLyoqXG4gICAgICogSG9zdCBoZWFkZXIgdG8gc2V0IGJlZm9yZSBzZW5kaW5nIG9yaWdpbiByZXF1ZXN0LiBTb21lIHNpdGVzIG9ubHkgcmVzcG9uZCB0byBzcGVjaWZpY1xuICAgICAqIGhvc3QgaGVhZGVycy5cbiAgICAgKi9cbiAgICBob3N0Pzogc3RyaW5nIHwgYm9vbGVhblxuICB9XG5cbiAgLyoqXG4gICAqIFdoZW4gdW5kZXJseWluZyBmZXRjaCB0aHJvd3MgYW4gZXJyb3IsIHJldHVybiBhIDUwMyByZXNwb25zZS5cbiAgICogXG4gICAqIERlZmF1bHRzIHRvIGB0cnVlYC5cbiAgICovXG4gIGVycm9yVG81MDM/OiBib29sZWFuLFxuXG4gIC8qKlxuICAgKiBXaGVuIHVuZGVybHlpbmcgY29ubmVjdGlvbiB0aHJvdWdocyBhbiBlcnJvciwgcmV0cnkgcmVxdWVzdCA8Tj4gdGltZXMuXG4gICAqL1xuICByZXRyaWVzPzogbnVtYmVyLFxuXG4gIC8qKiBAcHJpdmF0ZSAqL1xuICBvcmlnaW4/OiBzdHJpbmcsXG5cbiAgLyoqIEBwcml2YXRlICovXG4gIGZldGNoPzogRmV0Y2hGdW5jdGlvbixcblxuICBjZXJ0aWZpY2F0ZT86IHtcbiAgICBrZXk/OiBzdHJpbmcgfCBCdWZmZXIgfCBBcnJheTxzdHJpbmcgfCBCdWZmZXI+XG4gICAgY2VydD86IHN0cmluZyB8IEJ1ZmZlciB8IEFycmF5PHN0cmluZyB8IEJ1ZmZlcj5cbiAgICBjYT86IHN0cmluZyB8IEJ1ZmZlciB8IEFycmF5PHN0cmluZyB8IEJ1ZmZlcj5cbiAgICBwZng/OiBzdHJpbmcgfCBCdWZmZXIgfCBBcnJheTxzdHJpbmcgfCBCdWZmZXI+XG4gICAgcGFzc3BocmFzZT86IHN0cmluZ1xuICB9LFxuXG4gIHRscz86e1xuICAgIHNlcnZlcm5hbWU/OiBzdHJpbmdcbiAgfVxufVxuXG5cbi8qKlxuICogQSBwcm94eSBgZmV0Y2hgIGxpa2UgZnVuY3Rpb24uIFRoZXNlIGZ1bmN0aW9ucyBpbmNsdWRlIHRoZWlyIFxuICogb3JpZ2luYWwgY29uZmlndXJhdGlvbiBpbmZvcm1hdGlvbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBQcm94eUZ1bmN0aW9uPFQgPSB1bmtub3duPiBleHRlbmRzIEZldGNoRnVuY3Rpb24ge1xuICBwcm94eUNvbmZpZzogVFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFByb3h5RmFjdG9yeTxUT3B0cyA9IGFueSwgVElucHV0ID0gYW55PiB7XG4gIChvcHRpb25zOiBUSW5wdXQpOiBQcm94eUZ1bmN0aW9uPFRPcHRzPjtcbiAgbm9ybWFsaXplT3B0aW9ucz86IChpbnB1dDogYW55KSA9PiBUT3B0cztcbn1cblxuLypcbiBSZXF1ZXN0cyB3aXRoIHJld3JpdGVzOlxuICAgLSBodHRwczovL2V4YW1wbGUuY29tL2Jsb2cvIC0+IGh0dHBzOi8vZXhhbXBsZS5ibG9nc2VydmljZS5jb20vXG4gICAtIHN0cmlwIC9ibG9nLyB0byBiYWNrZW5kIChwcm94eSBmdW5jdGlvbiBkb2VzIHRoaXMpXG4gICAtIHByZXBlbmQgL2Jsb2cvIHRvIGxvY2F0aW9uIGhlYWRlcnMgb24gcmVzcG9uc2VcbiovXG4iXX0=