UNPKG

@fly/edge

Version:
176 lines 26.9 kB
"use strict"; 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=