PR-824002: Using proxy instead of a redirect.

This commit is contained in:
Alejandro Lembke Barrientos 2025-01-13 04:36:45 +00:00
parent 32eec62ad0
commit 4e45f0a04f
Signed by: aleleba
GPG Key ID: F48D7CDEB47942BD
11 changed files with 197 additions and 106 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
node_modules
dist
.env

View File

@ -1,24 +1,13 @@
import request from 'supertest';
import express from 'express';
import { setRoutes } from '../src/routes/index';
import dotenv from 'dotenv';
import app from '../src/app';
dotenv.config();
const app = express();
setRoutes(app);
describe('GET /', () => {
it('should redirect to CDN URL', async () => {
describe('Proxy Middleware', () => {
it('should proxy to CDN URL', async () => {
const response = await request(app).get('/');
expect(response.status).toBe(302);
expect(response.header.location).toBe(process.env.CDN_URL);
expect(response.status).toBe(200);
});
it('should return 500 if CDN URL is not configured', async () => {
process.env.CDN_URL = '';
const response = await request(app).get('/');
expect(response.status).toBe(500);
expect(response.text).toBe('CDN URL not configured');
});
});
});

17
dist/app.js vendored
View File

@ -1,17 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const dotenv_1 = __importDefault(require("dotenv"));
const index_1 = require("./routes/index");
dotenv_1.default.config();
const app = (0, express_1.default)();
const PORT = process.env.PORT || 3000;
app.use(express_1.default.json());
app.use(express_1.default.urlencoded({ extended: true }));
(0, index_1.setRoutes)(app);
app.listen(PORT, () => {
console.log(`Servidor corriendo en http://localhost:${PORT}`);
});

View File

@ -1,26 +0,0 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getIndex = void 0;
const getIndex = (req, res) => __awaiter(void 0, void 0, void 0, function* () {
try {
const cdnUrl = process.env.CDN_URL;
if (!cdnUrl) {
res.status(500).send('CDN URL not configured');
return;
}
res.redirect(cdnUrl);
}
catch (error) {
res.status(500).send('Internal Server Error');
}
});
exports.getIndex = getIndex;

View File

@ -1,9 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.setRoutes = setRoutes;
const index_1 = require("../controllers/index");
function setRoutes(app) {
app.get('/', (req, res) => {
(0, index_1.getIndex)(req, res);
});
}

2
dist/types/index.js vendored
View File

@ -1,2 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

149
package-lock.json generated
View File

@ -10,10 +10,12 @@
"license": "MIT",
"dependencies": {
"dotenv": "^16.4.7",
"express": "^4.21.2"
"express": "^4.21.2",
"http-proxy-middleware": "^3.0.3"
},
"devDependencies": {
"@types/express": "^5.0.0",
"@types/http-proxy-middleware": "^0.19.3",
"@types/jest": "^29.5.14",
"@types/node": "^22.10.5",
"@types/supertest": "^6.0.2",
@ -1196,6 +1198,27 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/http-proxy": {
"version": "1.17.15",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz",
"integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/http-proxy-middleware": {
"version": "0.19.3",
"resolved": "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-0.19.3.tgz",
"integrity": "sha512-lnBTx6HCOUeIJMLbI/LaL5EmdKLhczJY5oeXZpX/cXE4rRqb3RmV7VcMpiEfYkmTjipv3h7IAyIINe4plEv7cA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/connect": "*",
"@types/http-proxy": "*",
"@types/node": "*"
}
},
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
@ -1252,7 +1275,6 @@
"version": "22.10.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz",
"integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~6.20.0"
@ -1644,7 +1666,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
@ -2299,6 +2320,12 @@
"node": ">= 0.6"
}
},
"node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
"license": "MIT"
},
"node_modules/execa": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
@ -2456,7 +2483,6 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
@ -2497,6 +2523,26 @@
"node": ">=8"
}
},
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
@ -2774,6 +2820,60 @@
"node": ">= 0.8"
}
},
"node_modules/http-proxy": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
"license": "MIT",
"dependencies": {
"eventemitter3": "^4.0.0",
"follow-redirects": "^1.0.0",
"requires-port": "^1.0.0"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/http-proxy-middleware": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz",
"integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==",
"license": "MIT",
"dependencies": {
"@types/http-proxy": "^1.17.15",
"debug": "^4.3.6",
"http-proxy": "^1.18.1",
"is-glob": "^4.0.3",
"is-plain-object": "^5.0.0",
"micromatch": "^4.0.8"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/http-proxy-middleware/node_modules/debug": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/http-proxy-middleware/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/human-signals": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@ -2876,6 +2976,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@ -2896,16 +3005,36 @@
"node": ">=6"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@ -3854,7 +3983,6 @@
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.3",
@ -4166,7 +4294,6 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@ -4326,6 +4453,12 @@
"node": ">=0.10.0"
}
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"license": "MIT"
},
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
@ -4845,7 +4978,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
@ -5023,7 +5155,6 @@
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
"dev": true,
"license": "MIT"
},
"node_modules/unpipe": {

View File

@ -12,10 +12,12 @@
},
"dependencies": {
"dotenv": "^16.4.7",
"express": "^4.21.2"
"express": "^4.21.2",
"http-proxy-middleware": "^3.0.3"
},
"devDependencies": {
"@types/express": "^5.0.0",
"@types/http-proxy-middleware": "^0.19.3",
"@types/jest": "^29.5.14",
"@types/node": "^22.10.5",
"@types/supertest": "^6.0.2",

View File

@ -1,17 +1,61 @@
import express from 'express';
import dotenv from 'dotenv';
import { setRoutes } from './routes/index';
import { createProxyMiddleware } from 'http-proxy-middleware';
import type { Request, Response } from 'express';
import { NextFunction } from 'http-proxy-middleware/dist/types';
import { ClientRequest } from 'http';
dotenv.config();
const app = express();
const PORT = process.env.PORT || 3000;
const cdnUrl = process.env.CDN_URL;
// Configuración del middleware de proxy
const proxyOptions = {
target: cdnUrl, // URL del CDN
changeOrigin: true, // Cambiar el origen para evitar problemas de CORS,
pathRewrite: (path: string) => path.replace("/", ""),
onProxyReq: (proxyReq: ClientRequest, req: Request, res: Response) => {
console.log(`Proxying request: ${req.url}`);
},
onError: (err: any, req: Request, res: Response) => {
console.error('Proxy error:', err);
if (!cdnUrl) {
res.status(500).send('CDN URL not configured');
throw new Error('CDN URL not configured');
}
},
};
// Crear el middleware proxy
const proxyMiddleware = createProxyMiddleware(proxyOptions);
// Middlewares para manejar JSON y formularios
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
setRoutes(app);
// Middleware para validar si cdnUrl está configurado
const validateCdnUrl = (req: Request, res: Response, next: NextFunction) => {
if (!cdnUrl) {
res.status(500).send('CDN URL not configured');
throw new Error('CDN URL not configured');
}
next();
};
app.listen(PORT, () => {
// Usar el middleware de validación antes del proxy
app.use(validateCdnUrl);
// Configurar el middleware proxy
app.use('/', proxyMiddleware);
// DO NOT DO app.listen() unless we're testing this directly
if (require.main === module) {
// Iniciar el servidor
app.listen(PORT, () => {
console.log(`Servidor corriendo en http://localhost:${PORT}`);
});
});
};
// Instead do export the app:
export default app;

View File

@ -1,14 +0,0 @@
import { Request, Response } from 'express';
export const getIndex = async (req: Request, res: Response): Promise<void> => {
try {
const cdnUrl = process.env.CDN_URL;
if (!cdnUrl) {
res.status(500).send('CDN URL not configured');
return;
}
res.redirect(cdnUrl);
} catch (error) {
res.status(500).send('Internal Server Error');
}
};

View File

@ -1,8 +0,0 @@
import { Application, Request, Response } from 'express';
import { getIndex } from '../controllers/index';
export function setRoutes(app: Application) {
app.get('/', (req: Request, res: Response) => {
getIndex(req, res);
});
}