2026-07-18 14:09:04 +09:00
|
|
|
import http from 'node:http'
|
|
|
|
|
import net from 'node:net'
|
|
|
|
|
|
|
|
|
|
const upstreamHost = 'qualification-ingress'
|
|
|
|
|
const upstreamPort = 80
|
|
|
|
|
|
|
|
|
|
const server = http.createServer((request, response) => {
|
2026-07-19 18:21:17 +09:00
|
|
|
const headers = upstreamHeaders(request.headers)
|
2026-07-18 14:09:04 +09:00
|
|
|
const upstream = http.request(
|
|
|
|
|
{
|
|
|
|
|
host: upstreamHost,
|
|
|
|
|
port: upstreamPort,
|
|
|
|
|
method: request.method,
|
|
|
|
|
path: request.url,
|
2026-07-19 18:21:17 +09:00
|
|
|
headers,
|
2026-07-18 14:09:04 +09:00
|
|
|
},
|
|
|
|
|
(upstreamResponse) => {
|
|
|
|
|
response.writeHead(
|
|
|
|
|
upstreamResponse.statusCode ?? 502,
|
|
|
|
|
upstreamResponse.headers,
|
|
|
|
|
)
|
|
|
|
|
upstreamResponse.pipe(response)
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
upstream.on('error', () => {
|
|
|
|
|
response.writeHead(502)
|
|
|
|
|
response.end()
|
|
|
|
|
})
|
|
|
|
|
request.pipe(upstream)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
server.on('upgrade', (request, socket, head) => {
|
|
|
|
|
const upstream = net.connect(upstreamPort, upstreamHost, () => {
|
2026-07-19 18:21:17 +09:00
|
|
|
const headers = Object.entries(upstreamHeaders(request.headers))
|
2026-07-18 14:09:04 +09:00
|
|
|
.filter(([name]) => name.toLowerCase() !== 'host')
|
|
|
|
|
.map(([name, value]) => `${name}: ${String(value)}`)
|
|
|
|
|
.join('\r\n')
|
|
|
|
|
upstream.write(
|
|
|
|
|
`${request.method} ${request.url} HTTP/${request.httpVersion}\r\nHost: ${upstreamHost}\r\n${headers}\r\n\r\n`,
|
|
|
|
|
)
|
|
|
|
|
if (head.length > 0) upstream.write(head)
|
|
|
|
|
socket.pipe(upstream).pipe(socket)
|
|
|
|
|
})
|
|
|
|
|
upstream.on('error', () => socket.destroy())
|
2026-07-19 18:21:17 +09:00
|
|
|
socket.on('error', () => upstream.destroy())
|
2026-07-18 14:09:04 +09:00
|
|
|
})
|
|
|
|
|
|
2026-07-19 18:21:17 +09:00
|
|
|
function upstreamHeaders(incoming) {
|
|
|
|
|
const headers = { ...incoming, host: upstreamHost }
|
|
|
|
|
const session = qualificationSession(headers.cookie)
|
|
|
|
|
if (typeof session === 'string' && /^[A-Za-z0-9_-]{43}$/.test(session))
|
|
|
|
|
headers.cookie = `__Host-remora-session=${session}`
|
|
|
|
|
else delete headers.cookie
|
|
|
|
|
return headers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function qualificationSession(cookieHeader) {
|
|
|
|
|
if (typeof cookieHeader !== 'string') return null
|
|
|
|
|
for (const cookie of cookieHeader.split(';')) {
|
|
|
|
|
const [name, value] = cookie.trim().split('=', 2)
|
|
|
|
|
if (name === 'remora-qualification-session') return value
|
|
|
|
|
}
|
|
|
|
|
return null
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-18 14:09:04 +09:00
|
|
|
server.listen(4174, '127.0.0.1')
|