forked from dwgx/WindsurfAPI
- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttps-proxy.js
More file actions
Latest commit
97 lines (83 loc) · 3.34 KB
/
Copy pathhttps-proxy.js
File metadata and controls
97 lines (83 loc) · 3.34 KB
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
importhttp2from'http2';
importhttpfrom'http';
import{readFileSync}from'fs';
constHTTPS_PORT=parseInt(process.env.HTTPS_PORT||'3443',10);
constTARGET_PORT=parseInt(process.env.TARGET_PORT||'3003',10);
constCORS_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',
};
functionproxy(req,res){
constts=newDate().toISOString().slice(11,19);
constmethod=req.method||req.headers[':method']||'GET';
consturl=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);
returnres.end();
}
// Build headers for the HTTP/1.1 backend
constfwdHeaders={};
for(const[k,v]ofObject.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}`;
constproxyReq=http.request({
hostname: '127.0.0.1',
port: TARGET_PORT,
path: req.url,
method: req.method,
headers: fwdHeaders,
},(proxyRes)=>{
constct=proxyRes.headers['content-type']||'';
constisSSE=ct.includes('text/event-stream');
console.log(`[${ts}] ← ${proxyRes.statusCode}${ct.split(';')[0]}${isSSE ? ' (SSE)' : ''}`);
constrespHeaders={};
consthop=newSet(['connection','transfer-encoding','keep-alive','upgrade','proxy-connection','proxy-authenticate','proxy-authorization']);
for(const[k,v]ofObject.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
constserver=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}`);
});