opex792 commited on
Commit
a4dd161
·
verified ·
1 Parent(s): 14d4892

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +188 -37
server.js CHANGED
@@ -1,22 +1,32 @@
1
  import express from 'express';
2
- import http from 'http';
3
  import { spawn } from 'child_process';
4
- import url from 'url';
 
5
 
6
- const EXPRESS_PORT = 3000; // Внутренний порт для Express-приложения (для туннеля)
7
- const HF_PORT = 7860; // Порт для Hugging Face
8
 
9
- // Функция для форматирования информации о запросе
10
- function formatRequestInfo(req, isExpress = true) {
 
11
  let info = 'ИНФОРМАЦИЯ О ЗАПРОСЕ:\n\n';
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- // Основная информация
14
  info += `Метод запроса: ${req.method}\n`;
15
- info += `URL: ${isExpress ? req.originalUrl : req.url}\n`;
16
- info += `IP клиента: ${isExpress ? req.ip : req.socket.remoteAddress}\n\n`;
17
 
18
- // Query параметры
19
- const queryParams = isExpress ? req.query : url.parse(req.url, true).query;
20
  info += 'QUERY ПАРАМЕТРЫ:\n';
21
  if (Object.keys(queryParams).length === 0) {
22
  info += '(нет параметров)\n';
@@ -27,50 +37,181 @@ function formatRequestInfo(req, isExpress = true) {
27
  }
28
  info += '\n';
29
 
30
- // Заголовки запроса
31
  info += 'ЗАГОЛОВКИ ЗАПРОСА:\n';
32
  const headers = req.headers;
33
  for (const [key, value] of Object.entries(headers)) {
34
  info += `${key}: ${value}\n`;
35
  }
36
 
37
- // User-Agent (информация о браузере)
38
  info += '\nИНФОРМАЦИЯ О БРАУЗЕРЕ:\n';
39
  info += headers['user-agent'] || 'Информация недоступна';
40
 
41
  return info;
42
  }
43
 
44
- // --- Сервер 1: Express-приложение для localhost.run ---
45
- const app = express();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
- app.get('*', (req, res) => {
48
- const requestInfo = formatRequestInfo(req);
 
49
  res.setHeader('Content-Type', 'text/plain; charset=utf-8');
50
- res.send(requestInfo);
51
  });
52
 
53
- app.listen(EXPRESS_PORT, () => {
54
- console.log(`Express server (для туннеля) слушает порт ${EXPRESS_PORT}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
- // Запускаем туннель localhost.run ПОСЛЕ того, как Express-сервер стартовал
57
- console.log(`Попытка запустить туннель localhost.run для порта ${EXPRESS_PORT}...`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  const tunnel = spawn('ssh', [
59
- '-R', `80:localhost:${EXPRESS_PORT}`, // Туннелируем порт 80 публичного URL на наш localhost:EXPRESS_PORT
60
- '-o', 'StrictHostKeyChecking=no', // Отключаем проверку ключа хоста для автоматизации
61
- '-o', 'UserKnownHostsFile=/dev/null', // Не сохраняем ключи хостов
62
- '-o', 'ServerAliveInterval=60', // Поддерживать соединение активным
63
- '-o', 'ExitOnForwardFailure=yes', // Выйти, если форвардинг не удался
 
64
  'nokey@localhost.run'
65
  ]);
66
 
67
  tunnel.stdout.on('data', (data) => {
68
  const output = data.toString();
69
  console.log(`localhost.run stdout: ${output}`);
70
- // Попытка извлечь URL из вывода
71
- const urlMatch = output.match(/https?:\/\/[a-zA-Z0-9-]+\.lhr\.life/);
72
  if (urlMatch) {
73
- console.log(`>>> Туннель активен: ${urlMatch[0]}`);
74
  }
75
  });
76
 
@@ -87,17 +228,27 @@ app.listen(EXPRESS_PORT, () => {
87
  });
88
  });
89
 
90
- // --- Сервер 2: Простой HTTP-сервер для Hugging Face на порту 7860 ---
91
- const server2 = http.createServer((req, res) => {
92
- const requestInfo = formatRequestInfo(req, false);
93
- res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
94
- res.end(requestInfo);
 
 
 
 
 
 
 
 
 
95
  });
96
 
97
- server2.listen(HF_PORT, () => {
98
- console.log(`Второй HTTP-сервер (для Hugging Face) слушает порт ${HF_PORT}`);
99
  });
100
 
 
101
  // Обработка сигналов для корректного завершения
102
  process.on('SIGINT', () => {
103
  console.log('Получен SIGINT. Завершение...');
 
1
  import express from 'express';
2
+ import http from 'http'; // Нужен для второго сервера
3
  import { spawn } from 'child_process';
4
+ import url from 'url'; // Нужен для formatRequestInfo для второго сервера
5
+ import fetch from 'node-fetch';
6
 
7
+ const PROXY_PORT = 3000; // Порт для CORS-прокси (будет туннелироваться)
8
+ const SECONDARY_SERVER_PORT = 7860; // Порт для второго сервера (Hugging Face / Hello World)
9
 
10
+ // Функция для форматирования информации о запросе (из оригинального server.js.txt)
11
+ // Немного адаптирована, чтобы можно было использовать для обоих типов серверов
12
+ function formatRequestInfo(req, serverType = 'express') {
13
  let info = 'ИНФОРМАЦИЯ О ЗАПРОСЕ:\n\n';
14
+ let reqUrl, queryParams, clientIp;
15
+
16
+ if (serverType === 'express') {
17
+ reqUrl = req.originalUrl;
18
+ queryParams = req.query;
19
+ clientIp = req.ip;
20
+ } else { // 'http'
21
+ reqUrl = req.url;
22
+ queryParams = url.parse(req.url, true).query;
23
+ clientIp = req.socket.remoteAddress;
24
+ }
25
 
 
26
  info += `Метод запроса: ${req.method}\n`;
27
+ info += `URL: ${reqUrl}\n`;
28
+ info += `IP клиента: ${clientIp}\n\n`;
29
 
 
 
30
  info += 'QUERY ПАРАМЕТРЫ:\n';
31
  if (Object.keys(queryParams).length === 0) {
32
  info += '(нет параметров)\n';
 
37
  }
38
  info += '\n';
39
 
 
40
  info += 'ЗАГОЛОВКИ ЗАПРОСА:\n';
41
  const headers = req.headers;
42
  for (const [key, value] of Object.entries(headers)) {
43
  info += `${key}: ${value}\n`;
44
  }
45
 
 
46
  info += '\nИНФОРМАЦИЯ О БРАУЗЕРЕ:\n';
47
  info += headers['user-agent'] || 'Информация недоступна';
48
 
49
  return info;
50
  }
51
 
52
+ // --- Сервер 1: CORS Proxy на порту PROXY_PORT (будет туннелироваться) ---
53
+ const proxyApp = express();
54
+
55
+ proxyApp.use(express.raw({
56
+ type: '*/*',
57
+ limit: '100mb'
58
+ }));
59
+
60
+ function addCorsHeaders(res, clientRequestOrigin) {
61
+ if (clientRequestOrigin) {
62
+ res.setHeader('Access-Control-Allow-Origin', clientRequestOrigin);
63
+ res.setHeader('Access-Control-Allow-Credentials', 'true');
64
+ res.setHeader('Vary', 'Origin');
65
+ } else {
66
+ res.setHeader('Access-Control-Allow-Origin', '*');
67
+ }
68
+ }
69
+
70
+ proxyApp.options('*', (req, res) => {
71
+ const origin = req.headers.origin;
72
+ addCorsHeaders(res, origin);
73
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD');
74
+ const requestedHeaders = req.headers['access-control-request-headers'];
75
+ if (requestedHeaders) {
76
+ res.setHeader('Access-Control-Allow-Headers', requestedHeaders);
77
+ } else {
78
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With, X-CSRF-Token, Accept, Origin, User-Agent');
79
+ }
80
+ res.setHeader('Access-Control-Max-Age', '86400');
81
+ res.status(204).end();
82
+ });
83
 
84
+ proxyApp.get('/', (req, res) => {
85
+ const origin = req.headers.origin;
86
+ addCorsHeaders(res, origin);
87
  res.setHeader('Content-Type', 'text/plain; charset=utf-8');
88
+ res.send(`CORS Proxy is running on port ${PROXY_PORT}. Append target URL to proxy, e.g., /http://example.com. Tunnel will be established for this port.`);
89
  });
90
 
91
+ proxyApp.all('*', async (req, res) => {
92
+ if (req.path === '/') {
93
+ return;
94
+ }
95
+
96
+ const clientRequestOrigin = req.headers.origin;
97
+
98
+ try {
99
+ let targetUrlString = req.url.substring(1);
100
+ try {
101
+ const decoded = decodeURIComponent(targetUrlString);
102
+ if (decoded.startsWith('http://') || decoded.startsWith('https://')) {
103
+ targetUrlString = decoded;
104
+ }
105
+ } catch (e) { /* Игнорируем ошибку декодирования, используем как есть */ }
106
+
107
+ if (!targetUrlString) {
108
+ addCorsHeaders(res, clientRequestOrigin);
109
+ res.status(400).send('Target URL is missing in the path.');
110
+ return;
111
+ }
112
+
113
+ if (!targetUrlString.match(/^https?:\/\//i)) {
114
+ if (!targetUrlString.startsWith('http://') && !targetUrlString.startsWith('https://')) {
115
+ targetUrlString = 'http://' + targetUrlString;
116
+ }
117
+ }
118
 
119
+ let targetUrl;
120
+ try {
121
+ targetUrl = new URL(targetUrlString);
122
+ } catch (e) {
123
+ addCorsHeaders(res, clientRequestOrigin);
124
+ res.status(400).send(`Invalid target URL provided in path: ${targetUrlString}. Error: ${e.message}`);
125
+ return;
126
+ }
127
+
128
+ const requestHeaders = {...req.headers};
129
+ delete requestHeaders['host'];
130
+ delete requestHeaders['content-length'];
131
+ delete requestHeaders['connection'];
132
+
133
+ const proxyResponse = await fetch(targetUrl.toString(), {
134
+ method: req.method,
135
+ headers: requestHeaders,
136
+ body: (req.method !== 'GET' && req.method !== 'HEAD' && req.body && req.body.length > 0) ? req.body : undefined,
137
+ redirect: 'manual',
138
+ compress: false
139
+ });
140
+
141
+ proxyResponse.headers.forEach((value, key) => {
142
+ const lowerKey = key.toLowerCase();
143
+ if (!lowerKey.startsWith('access-control-') &&
144
+ !['strict-transport-security', 'content-security-policy', 'public-key-pins',
145
+ 'transfer-encoding', 'connection', 'keep-alive', 'proxy-authenticate',
146
+ 'proxy-authorization', 'te', 'trailers', 'upgrade'].includes(lowerKey)
147
+ ) {
148
+ res.setHeader(key, value);
149
+ }
150
+ });
151
+
152
+ addCorsHeaders(res, clientRequestOrigin);
153
+ const exposedHeaders = Array.from(proxyResponse.headers.keys()).filter(key =>
154
+ !key.toLowerCase().startsWith('access-control-') &&
155
+ key.toLowerCase() !== 'transfer-encoding' &&
156
+ key.toLowerCase() !== 'connection'
157
+ ).join(', ');
158
+
159
+ if (exposedHeaders) {
160
+ res.setHeader('Access-Control-Expose-Headers', exposedHeaders);
161
+ } else {
162
+ res.setHeader('Access-Control-Expose-Headers', '*');
163
+ }
164
+
165
+ res.status(proxyResponse.status);
166
+
167
+ if (proxyResponse.body) {
168
+ proxyResponse.body.pipe(res);
169
+ } else {
170
+ res.end();
171
+ }
172
+
173
+ } catch (error) {
174
+ console.error('Proxy error:', error);
175
+ if (!res.headersSent) {
176
+ addCorsHeaders(res, clientRequestOrigin);
177
+ let statusCode = 500;
178
+ let message = 'Proxy error occurred.';
179
+ if (error.code === 'ENOTFOUND' || error.cause?.code === 'ENOTFOUND') {
180
+ statusCode = 404; message = `Target host not found: ${req.url.substring(1)}`;
181
+ } else if (error.message?.includes('Invalid URL') || (error.name === 'TypeError' && error.message?.includes('Invalid URL'))) {
182
+ statusCode = 400; message = `Invalid target URL in path: ${req.url.substring(1)}. Detail: ${error.message}`;
183
+ } else if (error.code === 'ECONNREFUSED' || error.cause?.code === 'ECONNREFUSED') {
184
+ statusCode = 502; message = `Bad Gateway: Could not connect to target server at ${req.url.substring(1)}`;
185
+ } else if (error.code === 'ERR_INVALID_URL') {
186
+ statusCode = 400; message = `Invalid target URL format in path: ${req.url.substring(1)}`;
187
+ }
188
+ res.status(statusCode).send(message);
189
+ } else {
190
+ res.end();
191
+ }
192
+ }
193
+ });
194
+
195
+ proxyApp.listen(PROXY_PORT, '0.0.0.0', () => {
196
+ console.log(`CORS Proxy server (для туннеля) слушает порт ${PROXY_PORT}`);
197
+
198
+ console.log(`Попытка запустить туннель localhost.run для порта ${PROXY_PORT}...`);
199
  const tunnel = spawn('ssh', [
200
+ '-R', `80:localhost:${PROXY_PORT}`,
201
+ '-o', 'StrictHostKeyChecking=no',
202
+ '-o', 'UserKnownHostsFile=/dev/null',
203
+ '-o', 'ServerAliveInterval=60',
204
+ '-o', 'ExitOnForwardFailure=yes',
205
+ '-o', 'ConnectTimeout=10',
206
  'nokey@localhost.run'
207
  ]);
208
 
209
  tunnel.stdout.on('data', (data) => {
210
  const output = data.toString();
211
  console.log(`localhost.run stdout: ${output}`);
212
+ const urlMatch = output.match(/https?:\/\/[a-zA-Z0-9-]+\.(lhr\.life|lhr\.run|localhost\.run)/);
 
213
  if (urlMatch) {
214
+ console.log(`>>> Туннель для PROXY (порт ${PROXY_PORT}) активен: ${urlMatch[0]}`);
215
  }
216
  });
217
 
 
228
  });
229
  });
230
 
231
+
232
+ // --- Сервер 2: Простой HTTP-сервер на порту SECONDARY_SERVER_PORT (например, для Hugging Face / Hello World) ---
233
+ // Ты просил оставить "Hello World" или оригинальный сервер. Я оставлю оригинальный, который показывает инфо о запросе.
234
+ // Если нужен просто Hello World, замени тело обработчика.
235
+ const secondaryServer = http.createServer((req, res) => {
236
+ if (req.url === '/' && req.method === 'GET') {
237
+ res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
238
+ res.end(`Hello World from secondary server on port ${SECONDARY_SERVER_PORT}!`);
239
+ } else {
240
+ // Показываем информацию о запросе для других путей, как в оригинале
241
+ const requestInfo = formatRequestInfo(req, 'http');
242
+ res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
243
+ res.end(requestInfo);
244
+ }
245
  });
246
 
247
+ secondaryServer.listen(SECONDARY_SERVER_PORT, '0.0.0.0', () => {
248
+ console.log(`Второй HTTP-сервер (для Hugging Face / Hello World) слушает порт ${SECONDARY_SERVER_PORT}`);
249
  });
250
 
251
+
252
  // Обработка сигналов для корректного завершения
253
  process.on('SIGINT', () => {
254
  console.log('Получен SIGINT. Завершение...');