import*as b from"node:http";import{AsyncLocalStorage as A}from"node:async_hooks";import{Readable as S,Stream as C}from"node:stream";import{pipeline as H}from"node:stream/promises";import{ReadableStream as k}from"node:stream/web";import{getPathPrefix as u}from"@redocly/theme/core/utils";import{ALLOWED_CORS_ORIGINS as L}from"../constants/common.js";import{logger as d}from"../tools/notifiers/logger.js";import{shutdowner as x}from"../tools/shutdowner.js";import{envConfig as I}from"../config/env-config.js";import{getClientIp as T}from"./utils/get-client-ip.js";import{normalizeIpAddress as O}from"./utils.js";import{CORS_PROXY_STREAM_HEADER as P}from"./routes/cors-proxy.js";const R=new A;globalThis.redoclyCookieStorage=R;function X(n,c=4e3){return new Promise((m,p)=>{const f=b.createServer(async(t,r)=>{const y=t.headers.cookie||"";R.run(y,async()=>{let s;try{const e=new URL(t.url||"",`http://${t.headers.host}`),o=[],l=t.rawHeaders.length;for(let i=0;i<l;i+=2)o.push([t.rawHeaders[i],t.rawHeaders[i+1]]);const a={headers:o,method:t.method};t.method==="GET"||t.method==="HEAD"||(a.body=S.toWeb(t),a.duplex="half");const h=new Request(e.toString(),a),v=T(h)||"127.0.0.1",E=h?.headers?.get("x-forwarded-host")||O(t.socket.remoteAddress);h.context={remoteAddr:{hostname:E,port:t.socket.localPort,ipAddress:v},url:e},s=await n.fetch(h)}catch(e){s=new Response(null,{status:500}),e instanceof Error&&(e.name==="TimeoutError"||e.constructor.name==="TimeoutError"?s=new Response(null,{status:504}):e.code==="ERR_INVALID_URL"&&(s=new Response("Invalid URL",{status:404})),d.error(`Error while handling request: %s
%s`,e.message,e.stack))}const w=t.headers.origin;w&&L.some(e=>w===e)&&(r.setHeader("Access-Control-Allow-Origin",w),r.setHeader("Access-Control-Allow-Credentials","true"));for(const[e,o]of s.headers||[])try{e==="set-cookie"?r.setHeader(e,s.headers.getSetCookie(e)):r.setHeader(e,o)}catch(l){d.error(`Error while setting header: ${l?.message}`)}if(r.setHeader("Vary","Cookie"),r.statusCode=s.status||500,s.body)try{if(_(s)){const e=new C.Transform({transform(o,l,a){if(r.closed||r.destroyed)return a();r.write(o,l)?process.nextTick(a):r.once("drain",a)},flush(o){if(r.closed||r.destroyed)return o();r.end(),o()}});await H(s.body instanceof k?S.fromWeb(s.body):s.body,e)}else{const e=await s.text();r.setHeader("Content-Length",Buffer.byteLength(e)),r.end(e)}}catch(e){console.error(e);const o=e instanceof Error?e:new Error("unknown error",{cause:e});r.destroy(o)}else r.end()})});x.registerShutdownCallback(()=>new Promise(t=>{d.verbose("Shutting down http server"),f.close(()=>{d.verbose("Http server shut down"),t()})})),f.listen(parseInt(String(c),10)).on("listening",()=>{I.isDevelopMode?d.logInFooter("server",`  \u{1F310} Preview URL: http://127.0.0.1:${c}${u()}`):d.logInFooter("server",`Server started at: http://127.0.0.1:${c}${u()}`),m(f)}).on("error",p)})}function _(n){const c=n.headers.get("content-type")||"",m=n.headers.get("x-accel-buffering")||"",p=n.headers.get("content-encoding"),f=n.headers.get("content-length"),t=n.headers.get("transfer-encoding");return n.headers.get(P)==="1"||p||t||f||/^no$/i.test(m)||!/^(text\/(?!event-stream\b))/i.test(c)}export{X as startHttpServer};
