Spaces:
Running
Running
File size: 5,101 Bytes
0005168 87dbf53 0005168 5e52290 5aae06e 1269be7 5e52290 7f06821 87dbf53 22613d0 87dbf53 22613d0 32ccfb1 0005168 32ccfb1 85a98e1 87dbf53 85a98e1 22613d0 87dbf53 0005168 1269be7 5aae06e 1269be7 ce92389 7a4b1ae f8a9810 87dbf53 85a98e1 f8a9810 87dbf53 f8a9810 85a98e1 f8a9810 87dbf53 f8a9810 87dbf53 0005168 f8a9810 85a98e1 f8a9810 22613d0 87dbf53 85a98e1 87dbf53 85a98e1 11e4d16 0005168 f8a9810 87dbf53 f8a9810 87dbf53 f8a9810 87dbf53 f8a9810 87dbf53 f8a9810 87dbf53 85a98e1 0005168 87dbf53 f8a9810 ce92389 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
import express from 'express';
import fetch, { Headers as FetchHeaders } from 'node-fetch';
const app = express();
app.use(express.raw({
type: '*/*',
limit: '100mb'
}));
app.options('*', (req, res) => {
const origin = req.headers.origin;
if (origin) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
} else {
res.setHeader('Access-Control-Allow-Origin', '*');
}
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD');
const requestedHeaders = req.headers['access-control-request-headers'];
if (requestedHeaders) {
res.setHeader('Access-Control-Allow-Headers', requestedHeaders);
} else {
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, X-CSRF-Token, Accept, Origin');
}
res.setHeader('Access-Control-Max-Age', '86400');
if (origin) {
res.setHeader('Vary', 'Origin');
}
res.status(204).end();
});
app.get('/', (req, res) => {
const origin = req.headers.origin;
if (origin) {
res.setHeader('Access-Control-Allow-Origin', origin);
res.setHeader('Vary', 'Origin');
if (req.method === 'OPTIONS') {
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
res.status(204).end();
return;
}
} else {
res.setHeader('Access-Control-Allow-Origin', '*');
}
res.send('Hello World');
});
app.all('*', async (req, res) => {
if (req.url === '/') {
return;
}
const clientRequestOrigin = req.headers.origin;
try {
let targetUrlString = req.url.substring(1);
try {
targetUrlString = decodeURIComponent(targetUrlString);
} catch (e) {}
if (!targetUrlString) {
addCorsHeaders(res, clientRequestOrigin);
res.status(400).send('Target URL is missing in the path.');
return;
}
let targetUrl;
try {
targetUrl = new URL(targetUrlString);
} catch (e) {
addCorsHeaders(res, clientRequestOrigin);
res.status(400).send(`Invalid target URL provided in path: ${targetUrlString}`);
return;
}
const requestHeaders = {...req.headers};
delete requestHeaders['host'];
delete requestHeaders['content-length'];
const response = await fetch(targetUrl.toString(), {
method: req.method,
headers: requestHeaders,
body: (req.method !== 'GET' && req.method !== 'HEAD') ? req.body : undefined,
redirect: 'manual',
compress: false
});
response.headers.forEach((value, key) => {
const lowerKey = key.toLowerCase();
if (!lowerKey.startsWith('access-control-') &&
lowerKey !== 'strict-transport-security' &&
lowerKey !== 'content-security-policy' &&
lowerKey !== 'public-key-pins' &&
lowerKey !== 'transfer-encoding' &&
lowerKey !== 'connection' &&
lowerKey !== 'keep-alive' &&
lowerKey !== 'proxy-authenticate' &&
lowerKey !== 'proxy-authorization' &&
lowerKey !== 'te' &&
lowerKey !== 'trailers' &&
lowerKey !== 'upgrade'
) {
res.setHeader(key, value);
}
});
addCorsHeaders(res, clientRequestOrigin);
const exposedHeaders = Array.from(response.headers.keys()).filter(key =>
!key.toLowerCase().startsWith('access-control-')
).join(', ');
if (exposedHeaders) {
res.setHeader('Access-Control-Expose-Headers', exposedHeaders || '*');
}
res.status(response.status);
if (response.body) {
response.body.pipe(res);
} else {
res.end();
}
} catch (error) {
if (!res.headersSent) {
addCorsHeaders(res, clientRequestOrigin);
let statusCode = 500;
let message = 'Proxy error occurred.';
if (error.code === 'ENOTFOUND') {
statusCode = 404;
message = `Target host not found: ${req.url.substring(1)}`;
} else if (error.message && error.message.includes('Invalid URL')) {
statusCode = 400;
message = `Invalid target URL in path: ${req.url.substring(1)}`;
} else if (error.code === 'ECONNREFUSED') {
statusCode = 502;
message = `Bad Gateway: Could not connect to target server at ${req.url.substring(1)}`;
} else if (error.code === 'ERR_INVALID_URL') {
statusCode = 400;
message = `Invalid target URL format in path: ${req.url.substring(1)}`;
}
res.status(statusCode).send(message);
} else {
res.end();
}
}
});
function addCorsHeaders(res, clientRequestOrigin) {
if (clientRequestOrigin) {
res.setHeader('Access-Control-Allow-Origin', clientRequestOrigin);
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Vary', 'Origin');
} else {
res.setHeader('Access-Control-Allow-Origin', '*');
}
}
const PORT = process.env.PORT || 7860;
const HOST = '0.0.0.0';
app.listen(PORT, HOST); |