123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.errorRequestHandler = exports.proxyRequestHandler = void 0;
- const lodash_1 = require("lodash");
- const node_fetch_1 = require("node-fetch");
- const stream_1 = require("stream");
- const url_1 = require("url");
- const apiv2_1 = require("../apiv2");
- const error_1 = require("../error");
- const logger_1 = require("../logger");
- const REQUIRED_VARY_VALUES = ["Accept-Encoding", "Authorization", "Cookie"];
- function makeVary(vary = "") {
- if (!vary) {
- return "Accept-Encoding, Authorization, Cookie";
- }
- const varies = vary.split(/, ?/).map((v) => {
- return v
- .split("-")
- .map((part) => (0, lodash_1.capitalize)(part))
- .join("-");
- });
- REQUIRED_VARY_VALUES.forEach((requiredVary) => {
- if (!(0, lodash_1.includes)(varies, requiredVary)) {
- varies.push(requiredVary);
- }
- });
- return varies.join(", ");
- }
- function proxyRequestHandler(url, rewriteIdentifier, options = {}) {
- return async (req, res, next) => {
- var _a;
- logger_1.logger.info(`[hosting] Rewriting ${req.url} to ${url} for ${rewriteIdentifier}`);
- const cookie = req.headers.cookie || "";
- const sessionCookie = cookie.split(/; ?/).find((c) => {
- return c.trim().startsWith("__session=");
- });
- const u = new url_1.URL(url + req.url);
- const c = new apiv2_1.Client({ urlPrefix: u.origin, auth: false });
- let passThrough;
- if (req.method && !["GET", "HEAD"].includes(req.method)) {
- passThrough = new stream_1.PassThrough();
- req.pipe(passThrough);
- }
- const headers = new node_fetch_1.Headers({
- "X-Forwarded-Host": req.headers.host || "",
- "X-Original-Url": req.url || "",
- Pragma: "no-cache",
- "Cache-Control": "no-cache, no-store",
- Cookie: sessionCookie || "",
- });
- const headersToSkip = new Set(["host"]);
- for (const key of Object.keys(req.headers)) {
- if (headersToSkip.has(key)) {
- continue;
- }
- const value = req.headers[key];
- if (value === undefined) {
- headers.delete(key);
- }
- else if (Array.isArray(value)) {
- headers.delete(key);
- for (const v of value) {
- headers.append(key, v);
- }
- }
- else {
- headers.set(key, value);
- }
- }
- let proxyRes;
- try {
- proxyRes = await c.request({
- method: (req.method || "GET"),
- path: u.pathname,
- queryParams: u.searchParams,
- headers,
- resolveOnHTTPError: true,
- responseType: "stream",
- redirect: "manual",
- body: passThrough,
- timeout: 60000,
- compress: false,
- });
- }
- catch (err) {
- const isAbortError = err instanceof error_1.FirebaseError && ((_a = err.original) === null || _a === void 0 ? void 0 : _a.name.includes("AbortError"));
- const isTimeoutError = err instanceof error_1.FirebaseError &&
- err.original instanceof node_fetch_1.FetchError &&
- err.original.code === "ETIMEDOUT";
- const isSocketTimeoutError = err instanceof error_1.FirebaseError &&
- err.original instanceof node_fetch_1.FetchError &&
- err.original.code === "ESOCKETTIMEDOUT";
- if (isAbortError || isTimeoutError || isSocketTimeoutError) {
- res.statusCode = 504;
- return res.end("Timed out waiting for function to respond.\n");
- }
- res.statusCode = 500;
- return res.end(`An internal error occurred while proxying for ${rewriteIdentifier}\n`);
- }
- if (proxyRes.status === 404) {
- const cascade = proxyRes.response.headers.get("x-cascade");
- if (options.forceCascade || (cascade && cascade.toUpperCase() === "PASS")) {
- return next();
- }
- }
- if (!proxyRes.response.headers.get("cache-control")) {
- proxyRes.response.headers.set("cache-control", "private");
- }
- const cc = proxyRes.response.headers.get("cache-control");
- if (cc && !cc.includes("private")) {
- proxyRes.response.headers.delete("set-cookie");
- }
- proxyRes.response.headers.set("vary", makeVary(proxyRes.response.headers.get("vary")));
- const location = proxyRes.response.headers.get("location");
- if (location) {
- try {
- const locationURL = new url_1.URL(location);
- if (locationURL.origin === u.origin) {
- const unborkedLocation = location.replace(locationURL.origin, "");
- proxyRes.response.headers.set("location", unborkedLocation);
- }
- }
- catch (e) {
- logger_1.logger.debug(`[hosting] had trouble parsing location header, but this may be okay: "${location}"`);
- }
- }
- for (const [key, value] of Object.entries(proxyRes.response.headers.raw())) {
- res.setHeader(key, value);
- }
- res.statusCode = proxyRes.status;
- proxyRes.response.body.pipe(res);
- };
- }
- exports.proxyRequestHandler = proxyRequestHandler;
- function errorRequestHandler(error) {
- return (req, res) => {
- res.statusCode = 500;
- const out = `A problem occurred while trying to handle a proxied rewrite: ${error}`;
- logger_1.logger.error(out);
- res.end(out);
- };
- }
- exports.errorRequestHandler = errorRequestHandler;
|