[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/dwgx/WindsurfAPI/master/https-proxy.js [Back]  [Original]

import http2 from 'http2';
import http from 'http';
import { readFileSync } from 'fs';

const HTTPS_PORT = parseInt(process.env.HTTPS_PORT || '3443', 10);
const TARGET_PORT = parseInt(process.env.TARGET_PORT || '3003', 10);

const CORS_HEADERS = {
  'access-control-allow-origin': '*',
  'access-control-allow-methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
  'access-control-allow-headers': '*',
  'access-control-expose-headers': '*',
  'access-control-max-age': '86400',
};

function proxy(req, res) {
  const ts = new Date().toISOString().slice(11, 19);
  const method = req.method || req.headers[':method'] || 'GET';
  const url = req.url || req.headers[':path'] || '/';
  console.log(`[${ts}] ${method} ${url} (${req.httpVersion})`);

  // Handle CORS preflight directly  don't forward to backend
  if (method === 'OPTIONS') {
    console.log(`[${ts}]  204 CORS preflight`);
    res.writeHead(204, CORS_HEADERS);
    return res.end();
  }

  // Build headers for the HTTP/1.1 backend
  const fwdHeaders = {};
  for (const [k, v] of Object.entries(req.headers)) {
    // Skip HTTP/2 pseudo-headers and hop-by-hop
    if (k.startsWith(':') || k === 'connection' || k === 'transfer-encoding') continue;
    fwdHeaders[k] = v;
  }
  fwdHeaders['host'] = `127.0.0.1:${TARGET_PORT}`;

  const proxyReq = http.request({
    hostname: '127.0.0.1',
    port: TARGET_PORT,
    path: req.url,
    method: req.method,
    headers: fwdHeaders,
  }, (proxyRes) => {
    const ct = proxyRes.headers['content-type'] || '';
    const isSSE = ct.includes('text/event-stream');
    console.log(`[${ts}]  ${proxyRes.statusCode} ${ct.split(';')[0]}${isSSE ? ' (SSE)' : ''}`);

    const respHeaders = {};
    const hop = new Set(['connection', 'transfer-encoding', 'keep-alive', 'upgrade', 'proxy-connection', 'proxy-authenticate', 'proxy-authorization']);
    for (const [k, v] of Object.entries(proxyRes.headers)) {
      if (hop.has(k)) continue;
      respHeaders[k] = v;
    }
    if (isSSE) {
      respHeaders['cache-control'] = 'no-cache';
      respHeaders['x-accel-buffering'] = 'no';
    }
    // Inject CORS headers into every response
    Object.assign(respHeaders, CORS_HEADERS);
    res.writeHead(proxyRes.statusCode, respHeaders);

    proxyRes.on('data', (chunk) => {
      res.write(chunk);
    });
    proxyRes.on('end', () => res.end());
  });

  proxyReq.on('error', (e) => {
    console.error(`[${ts}] Proxy error: ${e.message} (${req.method} ${req.url})`);
    if (!res.headersSent) {
      res.writeHead(502, { 'content-type': 'application/json' });
      res.end(JSON.stringify({ error: { message: 'Bad Gateway', type: 'proxy_error' } }));
    }
  });

  req.on('error', () => proxyReq.destroy());
  req.on('close', () => { if (!proxyReq.destroyed) proxyReq.destroy(); });
  req.pipe(proxyReq);
}

// HTTP/2 secure server with HTTP/1.1 fallback
const server = http2.createSecureServer({
  key: readFileSync('./localhost+3-key.pem'),
  cert: readFileSync('./localhost+3.pem'),
  allowHTTP1: true,
}, proxy);

server.timeout = 300_000;

server.on('error', (e) => console.error('Server error:', e.message));

server.listen(HTTPS_PORT, '0.0.0.0', () => {
  console.log(`HTTPS proxy (HTTP/2 + HTTP/1.1) on https://0.0.0.0:${HTTPS_PORT}  http://127.0.0.1:${TARGET_PORT}`);
  console.log(`  Local:   https://localhost:${HTTPS_PORT}`);
  console.log(`  LAN:     https://192.168.50.7:${HTTPS_PORT}`);
});

Web Proxy Viewer  |  New URL  |  Original Page