@fly/cdn
Version:
Fly's TypeScript CDN
167 lines • 22.4 kB
JavaScript
/**
* Library for proxying requests to origins. Use this to create `fetch` like functions
* for making requests to other services. For example:
*
* ```javascript
* // sends all traffic to an Amazon ELB,
* // `Host` header passes through from visitor request
* const origin = proxy("https://elb1298.amazonaws.com")
* ```
*
* By default, this function sends the `Host` header inferred from the origin URL. To forward
* host headers sent by visitors, set `forwardHostHeader` to true.
*
* ```javascript
* // sends all traffic to an Amazon ELB, include host header from original request.
* const origin = proxy("https://elb1298.amazonaws.com", {
* forwardHostHeader: true
* })
* ```
*
* And then way more rare, no host header at all. Usually you'd strip out `x-forwarded-host`,
* since some origins don't like that:
* ```javascript
* // sends all traffic to an Amazon ELB, never sends a host header
* const origin = proxy("https://elb1298.amazonaws.com", {
* headers: { host: false}
* })
* ```
*
* @preferred
* @module HTTP
*/
import { normalizeRequest } from "./fetch";
/**
* 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.
*/
export function proxy(origin, options) {
if (!options) {
options = {};
}
options.origin = origin.toString();
async function proxyFetch(req, init) {
if (!(req instanceof Request)) {
req = normalizeRequest(req, init);
init = undefined;
}
if (!options) {
options = {};
}
const breq = buildProxyRequest(origin, options, req, init);
let bresp = await fetch(breq);
if (options.rewriteLocationHeaders !== false) {
bresp = rewriteLocationHeader(req.url, breq.url, bresp);
}
return bresp;
}
return Object.assign(proxyFetch, { proxyConfig: options });
}
/**
* @protected
* @hidden
* @param origin
* @param options
* @param req
* @param init
*/
export function buildProxyRequest(origin, options, r, init) {
const req = normalizeRequest(r);
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;
}
export 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;
}
/*
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcHJveHkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0ErQkc7QUFDSCxPQUFPLEVBQUUsZ0JBQWdCLEVBQWlCLE1BQU0sU0FBUyxDQUFBO0FBRXpEOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLFVBQVUsS0FBSyxDQUFDLE1BQW9CLEVBQUUsT0FBc0I7SUFDaEUsSUFBSSxDQUFDLE9BQU8sRUFBRTtRQUNaLE9BQU8sR0FBRyxFQUFFLENBQUE7S0FDYjtJQUNELE9BQU8sQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ25DLEtBQUssVUFBVSxVQUFVLENBQUMsR0FBZ0IsRUFBRSxJQUFrQjtRQUM1RCxJQUFHLENBQUMsQ0FBQyxHQUFHLFlBQVksT0FBTyxDQUFDLEVBQUM7WUFDM0IsR0FBRyxHQUFHLGdCQUFnQixDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQztZQUNsQyxJQUFJLEdBQUcsU0FBUyxDQUFDO1NBQ2xCO1FBQ0QsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNaLE9BQU8sR0FBRyxFQUFFLENBQUE7U0FDYjtRQUNELE1BQU0sSUFBSSxHQUFHLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxPQUFPLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFBO1FBQzFELElBQUksS0FBSyxHQUFHLE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQzdCLElBQUcsT0FBTyxDQUFDLHNCQUFzQixLQUFLLEtBQUssRUFBQztZQUMxQyxLQUFLLEdBQUcscUJBQXFCLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFBO1NBQ3hEO1FBQ0QsT0FBTyxLQUFLLENBQUE7SUFDZCxDQUFDO0lBRUQsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLFVB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LFVBQVUsRUFBRSxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQTtLQUNsRDtJQUVELE9BQU8sSUFBSSxDQUFBO0FBQ2IsQ0FBQztBQW1FRDs7Ozs7RUFLRSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTGlicmFyeSBmb3IgcHJveHlpbmcgcmVxdWVzdHMgdG8gb3JpZ2lucy4gVXNlIHRoaXMgdG8gY3JlYXRlIGBmZXRjaGAgbGlrZSBmdW5jdGlvbnNcbiAqICBmb3IgbWFraW5nIHJlcXVlc3RzIHRvIG90aGVyIHNlcnZpY2VzLiBGb3IgZXhhbXBsZTpcbiAqXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiAvLyBzZW5kcyBhbGwgdHJhZmZpYyB0byBhbiBBbWF6b24gRUxCLFxuICogLy8gYEhvc3RgIGhlYWRlciBwYXNzZXMgdGhyb3VnaCBmcm9tIHZpc2l0b3IgcmVxdWVzdFxuICogY29uc3Qgb3JpZ2luID0gcHJveHkoXCJodHRwczovL2VsYjEyOTguYW1hem9uYXdzLmNvbVwiKVxuICogYGBgXG4gKlxuICogQnkgZGVmYXVsdCwgdGhpcyBmdW5jdGlvbiBzZW5kcyB0aGUgYEhvc3RgIGhlYWRlciBpbmZlcnJlZCBmcm9tIHRoZSBvcmlnaW4gVVJMLiBUbyBmb3J3YXJkXG4gKiBob3N0IGhlYWRlcnMgc2VudCBieSB2aXNpdG9ycywgc2V0IGBmb3J3YXJkSG9zdEhlYWRlcmAgdG8gdHJ1ZS5cbiAqXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiAvLyBzZW5kcyBhbGwgdHJhZmZpYyB0byBhbiBBbWF6b24gRUxCLCBpbmNsdWRlIGhvc3QgaGVhZGVyIGZyb20gb3JpZ2luYWwgcmVxdWVzdC5cbiAqIGNvbnN0IG9yaWdpbiA9IHByb3h5KFwiaHR0cHM6Ly9lbGIxMjk4LmFtYXpvbmF3cy5jb21cIiwge1xuICogIGZvcndhcmRIb3N0SGVhZGVyOiB0cnVlXG4gKiB9KVxuICogYGBgXG4gKlxuICogQW5kIHRoZW4gd2F5IG1vcmUgcmFyZSwgbm8gaG9zdCBoZWFkZXIgYXQgYWxsLiBVc3VhbGx5IHlvdSdkIHN0cmlwIG91dCBgeC1mb3J3YXJkZWQtaG9zdGAsXG4gKiBzaW5jZSBzb21lIG9yaWdpbnMgZG9uJ3QgbGlrZSB0aGF0OlxuICogYGBgamF2YXNjcmlwdFxuICogLy8gc2VuZHMgYWxsIHRyYWZmaWMgdG8gYW4gQW1hem9uIEVMQiwgbmV2ZXIgc2VuZHMgYSBob3N0IGhlYWRlclxuICogY29uc3Qgb3JpZ2luID0gcHJveHkoXCJodHRwczovL2VsYjEyOTguYW1hem9uYXdzLmNvbVwiLCB7XG4gKiAgaGVhZGVyczogeyBob3N0OiBmYWxzZX1cbiAqIH0pXG4gKiBgYGBcbiAqXG4gKiBAcHJlZmVycmVkXG4gKiBAbW9kdWxlIEhUVFBcbiAqL1xuaW1wb3J0IHsgbm9ybWFsaXplUmVxdWVzdCwgRmV0Y2hGdW5jdGlvbiB9IGZyb20gXCIuL2ZldGNoXCJcblxuLyoqXG4gKiBUaGlzIGdlbmVyYXRlcyBhIGBmZXRjaGAgbGlrZSBmdW5jdGlvbiBmb3IgcHJveHlpbmcgcmVxdWVzdHMgdG8gYSBnaXZlbiBvcmlnaW4uXG4gKiBXaGVuIHRoaXMgZnVuY3Rpb24gbWFrZXMgb3JpZ2luIHJlcXVlc3RzLCBpdCBhZGRzIHN0YW5kYXJkIHByb3h5IGhlYWRlcnMgbGlrZVxuICogYFgtRm9yd2FyZGVkLUhvc3RgIGFuZCBgWC1Gb3J3YXJkZWQtRm9yYC4gSXQgYWxzbyBwYXNzZXMgaGVhZGVycyBmcm9tIHRoZSBvcmlnaW5hbFxuICogcmVxdWVzdCB0byB0aGUgb3JpZ2luLlxuICogQHBhcmFtIG9yaWdpbiBBIFVSTCB0byBhbiBvcmlnaW4sIGNhbiBpbmNsdWRlIGEgcGF0aCB0byByZWJhc2UgcmVxdWVzdHMuXG4gKiBAcGFyYW0gb3B0aW9ucyBPcHRpb25zIGFuZCBoZWFkZXJzIHRvIGNvbnRyb2wgb3JpZ2luIHJlcXVlc3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcm94eShvcmlnaW46IHN0cmluZyB8IFVSTCwgb3B0aW9ucz86IFByb3h5T3B0aW9ucyk6IFByb3h5RnVuY3Rpb248UHJveHlPcHRpb25zPiB7XG4gIGlmICghb3B0aW9ucykge1xuICAgIG9wdGlvbnMgPSB7fVxuICB9XG4gIG9wdGlvbnMub3JpZ2luID0gb3JpZ2luLnRvU3RyaW5nKCk7XG4gIGFzeW5jIGZ1bmN0aW9uIHByb3h5RmV0Y2gocmVxOiBSZXF1ZXN0SW5mbywgaW5pdD86IFJlcXVlc3RJbml0KSB7XG4gICAgaWYoIShyZXEgaW5zdGFuY2VvZiBSZXF1ZXN0KSl7XG4gICAgICByZXEgPSBub3JtYWxpemVSZXF1ZXN0KHJlcSwgaW5pdCk7XG4gICAgICBpbml0ID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBpZiAoIW9wdGlvbnMpIHtcbiAgICAgIG9wdGlvbnMgPSB7fVxuICAgIH1cbiAgICBjb25zdCBicmVxID0gYnVpbGRQcm94eVJlcXVlc3Qob3JpZ2luLCBvcHRpb25zLCByZXEsIGluaXQpXG4gICAgbGV0IGJyZXNwID0gYXdhaXQgZmV0Y2goYnJlcSlcbiAgICBpZihvcHRpb25zLnJld3JpdGVMb2NhdGlvbkhlYWRlcnMgIT09IGZhbHNlKXtcbiAgICAgIGJyZXNwID0gcmV3cml0ZUxvY2F0aW9uSGVhZGVyKHJlcS51cmwsIGJyZXEudXJsLCBicmVzcClcbiAgICB9XG4gICAgcmV0dXJuIGJyZXNwXG4gIH1cblxuICByZXR1cm4gT2JqZWN0LmFzc2lnbihwcm94eUZldGNoLCB7IHByb3h5Q29uZmlnOiBvcHRpb25zfSlcbn1cblxuLyoqXG4gKiBAcHJvdGVjdGVkXG4gKiBAaGlkZGVuXG4gKiBAcGFyYW0gb3JpZ2luXG4gKiBAcGFyYW0gb3B0aW9uc1xuICogQHBhcmFtIHJlcVxuICogQHBhcmFtIGluaXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkUHJveHlSZXF1ZXN0KG9yaWdpbjogc3RyaW5nIHwgVVJMLCBvcHRpb25zOiBQcm94eU9wdGlvbnMsIHI6IFJlcXVlc3RJbmZvLCBpbml0PzogUmVxdWVzdEluaXQpIHtcbiAgY29uc3QgcmVxID0gbm9ybWFsaXplUmVxdWVzdChyKVxuXG4gIGNvbnN0IHVybCA9IG5ldyBVUkwocmVxLnVybClcbiAgbGV0IGJyZXE6IFJlcXVlc3QgfCBudWxsID0gbnVsbFxuXG4gIGJyZXEgPSByZXEuY2xvbmUoKVxuXG4gIGlmICh0eXBlb2Ygb3JpZ2luID09PSBcInN0cmluZ1wiKSB7XG4gICAgb3JpZ2luID0gbmV3IFVSTChvcmlnaW4pXG4gIH1cblxuICBjb25zdCByZXF1ZXN0ZWRIb3N0bmFtZSA9IHJlcS5oZWFkZXJzLmdldChcImhvc3RcIikgfHwgdXJsLmhvc3RuYW1lXG4gIHVybC5ob3N0bmFtZSA9IG9yaWdpbi5ob3N0bmFtZVxuICB1cmwucHJvdG9jb2wgPSBvcmlnaW4ucHJvdG9jb2xcbiAgdXJsLnBvcnQgPSBvcmlnaW4ucG9ydFxuXG4gIGlmIChvcHRpb25zLnN0cmlwUGF0aCAmJiB0eXBlb2Ygb3B0aW9ucy5zdHJpcFBhdGggPT09IFwic3RyaW5nXCIpIHtcbiAgICAvLyByZW1vdmUgYmFzZVBhdGggc28gd2UgY2FuIHNlcnZlIGBvbmVob3N0aGFtZS5jb20vZGlyL2AgZnJvbSBgb3JpZ2luLmNvbS9gXG4gICAgdXJsLnBhdGhuYW1lID0gdXJsLnBhdGhuYW1lLnN1YnN0cmluZyhvcHRpb25zLnN0cmlwUGF0aC5sZW5ndGgpXG4gIH1cbiAgaWYgKG9yaWdpbi5wYXRobmFtZSAmJiBvcmlnaW4ucGF0aG5hbWUubGVuZ3RoID4gMCkge1xuICAgIHVybC5wYXRobmFtZSA9IFtvcmlnaW4ucGF0aG5hbWUucmVwbGFjZSgvXFwvJC8sIFwiXCIpLCB1cmwucGF0aG5hbWUucmVwbGFjZSgvXlxcLy8sIFwiXCIpXS5qb2luKFwiL1wiKVxuICB9XG4gIGlmICh1cmwucGF0aG5hbWUuc3RhcnRzV2l0aChcIi8vXCIpKSB7XG4gICAgdXJsLnBhdGhuYW1lID0gdXJsLnBhdGhuYW1lLnN1YnN0cmluZygxKVxuICB9XG5cbiAgaWYgKHVybC50b1N0cmluZygpICE9PSBicmVxLnVybCkge1xuICAgIGJyZXEgPSBuZXcgUmVxdWVzdCh1cmwudG9TdHJpbmcoKSwgYnJlcSlcbiAgfVxuICAvLyB3ZSBleHRlbmQgcmVxIHdpdGggcmVtb3RlQWRkclxuICBpZihyZXEucmVtb3RlQWRkcil7XG4gICAgYnJlcS5oZWFkZXJzLnNldChcIngtZm9yd2FyZGVkLWZvclwiLCByZXEucmVtb3RlQWRkcilcbiAgfVxuICBicmVxLmhlYWRlcnMuc2V0KFwieC1mb3J3YXJkZWQtaG9zdFwiLCByZXF1ZXN0ZWRIb3N0bmFtZSlcbiAgYnJlcS5oZWFkZXJzLnNldChcIngtZm9yd2FyZGVkLXByb3RvXCIsIHVybC5wcm90b2NvbC5yZXBsYWNlKFwiOlwiLCBcIlwiKSlcblxuICBpZiAoIW9wdGlvbnMuZm9yd2FyZEhvc3RIZWFkZXIpIHtcbiAgICAvLyBzZXQgaG9zdCBoZWFkZXIgdG8gb3JpZ2luLmhvc3RuYW1lc1xuICAgIGJyZXEuaGVhZGVycy5zZXQoXCJob3N0XCIsIG9yaWdpbi5ob3N0bmFtZSlcbiAgfVxuXG4gIGlmIChvcHRpb25zLmhlYWRlcnMpIHtcbiAgICBmb3IgKGNvbnN0IGggb2YgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMob3B0aW9ucy5oZWFkZXJzKSkge1xuICAgICAgY29uc3QgdiA9IG9wdGlvbnMuaGVhZGVyc1toXVxuICAgICAgaWYgKHYgPT09IGZhbHNlKSB7XG4gICAgICAgIGJyZXEuaGVhZGVycy5kZWxldGUoaClcbiAgICAgIH0gZWxzZSBpZiAodiAmJiB0eXBlb2YgdiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICBicmVxLmhlYWRlcnMuc2V0KGgsIHYpXG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBicmVxO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmV3cml0ZUxvY2F0aW9uSGVhZGVyKHVybDogVVJMIHwgc3RyaW5nLCBidXJsOiBVUkwgfCBzdHJpbmcsIHJlc3A6IFJlc3BvbnNlKXtcbiAgY29uc3QgbG9jYXRpb25IZWFkZXIgPSByZXNwLmhlYWRlcnMuZ2V0KFwibG9jYXRpb25cIilcbiAgaWYoIWxvY2F0aW9uSGVhZGVyKXtcbiAgICByZXR1cm4gcmVzcFxuICB9XG4gIGlmKHR5cGVvZiB1cmwgPT09IFwic3RyaW5nXCIpe1xuICAgIHVybCA9IG5ldyBVUkwodXJsKVxuICB9XG4gIGlmKHR5cGVvZiBidXJsID09PSBcInN0cmluZ1wiKXtcbiAgICBidXJsID0gbmV3IFVSTChidXJsKVxuICB9XG4gIGNvbnN0IGxvY2F0aW9uID0gbmV3IFVSTChsb2NhdGlvbkhlYWRlciwgYnVybClcblxuICBpZihsb2NhdGlvbi5ob3N0bmFtZSAhPT0gYnVybC5ob3N0bmFtZSB8fCBsb2NhdGlvbi5wcm90b2NvbCAhPT0gYnVybC5wcm90b2NvbCl7XG4gICAgcmV0dXJuIHJlc3BcbiAgfVxuXG5cbiAgbGV0IHBhdGhuYW1lID0gbG9jYXRpb24ucGF0aG5hbWVcbiAgaWYodXJsLnBhdGhuYW1lLmVuZHNXaXRoKGJ1cmwucGF0aG5hbWUpKXtcbiAgICAvLyB1cmwgcGF0aDogL29yaWdpbmFsL3BhdGgvXG4gICAgLy8gYnVybCBwYXRoOiAvcGF0aC9cbiAgICAvLyBuZWVkIHRvIHByZWZpeCBiYXNlXG4gICAgY29uc3QgcHJlZml4ID0gdXJsLnBhdGhuYW1lLnN1YnN0cmluZygwLCB1cmwucGF0aG5hbWUubGVuZ3RoIC0gYnVybC5wYXRobmFtZS5sZW5ndGgpXG4gICAgcGF0aG5hbWUgPSBwcmVmaXggKyBsb2NhdGlvbi5wYXRobmFtZVxuXG4gIH0gZWxzZSBpZihidXJsLnBhdGhuYW1lLmVuZHNXaXRoKHVybC5wYXRobmFtZSkpIHtcbiAgICAvLyB1cmwgcGF0aDogL29yaWdpbmFsL3BhdGgvXG4gICAgLy8gYnVybCBwYXRoOiAvcGF0aC9cbiAgICAvLyBuZWVkIHRvIHJlbW92ZSBwcmVmaXhcbiAgICBjb25zdCByZW1vdmUgPSBidXJsLnBhdGhuYW1lLnN1YnN0cmluZygwLCBidXJsLnBhdGhuYW1lLmxlbmd0aCAtIHVybC5wYXRobmFtZS5sZW5ndGgpXG4gICAgaWYobG9jYXRpb24ucGF0aG5hbWUuc3RhcnRzV2l0aChyZW1vdmUpKXtcbiAgICAgIHBhdGhuYW1lID0gbG9jYXRpb24ucGF0aG5hbWUuc3Vic3RyaW5nKHJlbW92ZS5sZW5ndGgsIGxvY2F0aW9uLnBhdGhuYW1lLmxlbmd0aClcbiAgICB9XG4gIH1cbiAgaWYocGF0aG5hbWUgIT09IGxvY2F0aW9uLnBhdGhuYW1lKXtcbiAgICAvLyBkbyB0aGUgcmV3cml0ZVxuICAgIGxvY2F0aW9uLnBhdGhuYW1lID0gcGF0aG5hbWVcbiAgICBsb2NhdGlvbi5wcm90b2NvbCA9IHVybC5wcm90b2NvbFxuICAgIGxvY2F0aW9uLmhvc3RuYW1lID0gdXJsLmhvc3RuYW1lXG4gICAgcmVzcC5oZWFkZXJzLnNldChcImxvY2F0aW9uXCIsIGxvY2F0aW9uLnRvU3RyaW5nKCkpXG4gIH1cblxuICByZXR1cm4gcmVzcFxufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGBwcm94eWAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUHJveHlPcHRpb25zIHtcbiAgLyoqXG4gICAqIFJlcGxhY2UgdGhpcyBwb3J0aW9uIG9mIFVSTCBwYXRoIGJlZm9yZSBtYWtpbmcgcmVxdWVzdCB0byBvcmlnaW4uXG4gICAqXG4gICAqIEZvciBleGFtcGxlLCB0aGlzIG1ha2VzIGEgcmVxdWVzdCB0byBgaHR0cHM6Ly9mbHkuaW8vcGF0aDEvdG8vZG9jdW1lbnQuaHRtbGA6XG4gICAqIGBgYGphdmFzY3JpcHRcbiAgICogY29uc3Qgb3B0cyA9IHsgc3RyaXBQYXRoOiBcIi9wYXRoMi9cIn1cbiAgICogY29uc3Qgb3JpZ2luID0gcHJveHkoXCJodHRwczovL2ZseS5pby9wYXRoMS9cIiwgb3B0cylcbiAgICogb3JpZ2luKFwiaHR0cHM6Ly9zb21laG9zdG5hbWUuY29tL3BhdGgyL3RvL2RvY3VtZW50Lmh0bWxcIilcbiAgICogYGBgXG4gICAqL1xuICBzdHJpcFBhdGg/OiBzdHJpbmdcblxuICAvKipcbiAgICogRm9yd2FyZCBgSG9zdGAgaGVhZGVyIGZyb20gb3JpZ2luYWwgcmVxdWVzdC4gV2l0aG91dCB0aGlzIG9wdGlvbnMsXG4gICAqIHByb3h5IHJlcXVlc3RzIGluZmVycyBhIGhvc3QgaGVhZGVyIGZyb20gdGhlIG9yaWdpbiBVUkwuXG4gICAqIERlZmF1bHRzIHRvIGBmYWxzZWAuXG4gICAqL1xuICBmb3J3YXJkSG9zdEhlYWRlcj86IGJvb2xlYW5cblxuICAvKipcbiAgICogUmV3cml0ZSBsb2NhdGlvbiBoZWFkZXJzIChkZWZhdWx0cyB0byB0cnVlKSB0byBtYXRjaCBpbmNvbWluZyByZXF1ZXN0LlxuICAgKiBcbiAgICogRXhhbXBsZTpcbiAgICogIC0gUmVxdWVzdCB1cmw6IGh0dHA6Ly90ZXN0LmNvbS9ibG9nL2FzZGZcbiAgICogIC0gUHJveHkgdXJsOiBodHRwOi8vb3JpZ2luLmNvbS9hc2RmXG4gICAqICAtIExvY2F0aW9uIGh0dHA6Ly9vcmlnaW4uY29tL2prbG0gYmNvbWVzIGh0dHA6Ly90ZXN0LmNvbS9ibG9nL2prbG1cbiAgICovXG4gIHJld3JpdGVMb2NhdGlvbkhlYWRlcnM/OiBib29sZWFuXG4gIC8qKlxuICAgKiBIZWFkZXJzIHRvIHNldCBvbiBiYWNrZW5kIHJlcXVlc3QuIEVhY2ggaGVhZGVyIGFjY2VwdHMgZWl0aGVyIGEgYGJvb2xlYW5gIG9yIGBzdHJpbmdgLlxuICAgKiAqIElmIHNldCB0byBgZmFsc2VgLCBzdHJpcCBoZWFkZXIgZW50aXJlbHkgYmVmb3JlIHNlbmRpbmcuXG4gICAqICogYHRydWVgIG9yIGB1bmRlZmluZWRgIHNlbmQgdGhlIGhlYWRlciB0aHJvdWdoIHVubW9kaWZpZWQgZnJvbSB0aGUgb3JpZ2luYWwgcmVxdWVzdC5cbiAgICogKiBgc3RyaW5nYCBoZWFkZXIgdmFsdWVzIGFyZSBzZW50IGFzIGlzXG4gICAqL1xuICBoZWFkZXJzPzoge1xuICAgIFtrZXk6IHN0cmluZ106IHN0cmluZyB8IGJvb2xlYW4gfCB1bmRlZmluZWRcbiAgICAvKipcbiAgICAgKiBIb3N0IGhlYWRlciB0byBzZXQgYmVmb3JlIHNlbmRpbmcgb3JpZ2luIHJlcXVlc3QuIFNvbWUgc2l0ZXMgb25seSByZXNwb25kIHRvIHNwZWNpZmljXG4gICAgICogaG9zdCBoZWFkZXJzLlxuICAgICAqL1xuICAgIGhvc3Q/OiBzdHJpbmcgfCBib29sZWFuXG4gIH1cblxuICAvKiogQHByaXZhdGUgKi9cbiAgb3JpZ2luPzogc3RyaW5nXG59XG5cblxuLyoqXG4gKiBBIHByb3h5IGBmZXRjaGAgbGlrZSBmdW5jdGlvbi4gVGhlc2UgZnVuY3Rpb25zIGluY2x1ZGUgdGhlaXIgXG4gKiBvcmlnaW5hbCBjb25maWd1cmF0aW9uIGluZm9ybWF0aW9uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFByb3h5RnVuY3Rpb248VCA9IHVua25vd24+IGV4dGVuZHMgRmV0Y2hGdW5jdGlvbiB7XG4gIHByb3h5Q29uZmlnOiBUXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUHJveHlGYWN0b3J5PFRPcHRzID0gYW55LCBUSW5wdXQgPSBhbnk+IHtcbiAgKG9wdGlvbnM6IFRJbnB1dCk6IFByb3h5RnVuY3Rpb248VE9wdHM+O1xuICBub3JtYWxpemVPcHRpb25zPzogKGlucHV0OiBhbnkpID0+IFRPcHRzO1xufVxuXG4vKlxuIFJlcXVlc3RzIHdpdGggcmV3cml0ZXM6XG4gICAtIGh0dHBzOi8vZXhhbXBsZS5jb20vYmxvZy8gLT4gaHR0cHM6Ly9leGFtcGxlLmJsb2dzZXJ2aWNlLmNvbS9cbiAgIC0gc3RyaXAgL2Jsb2cvIHRvIGJhY2tlbmQgKHByb3h5IGZ1bmN0aW9uIGRvZXMgdGhpcylcbiAgIC0gcHJlcGVuZCAvYmxvZy8gdG8gbG9jYXRpb24gaGVhZGVycyBvbiByZXNwb25zZVxuKi9cbiJdfQ==