"use strict";var e=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.httpsOverHttps=exports.httpsOverHttp=void 0;const t=require("https"),s=e(require("../../log")),o=require("tls"),n=require("http"),r=require("https");exports.httpsOverHttp=function(e){return new i(n.request,e)},exports.httpsOverHttps=function(e){return new i(r.request,e)};class i extends t.Agent{constructor(e,t){super(t),this.mRequests=[],this.mSockets=[],this.mRequest=e,this.options=t||{},this.proxyOptions=this.options.proxy,this.maxSockets=this.options&&this.options.maxSockets?this.options.maxSockets:1/0}addRequest(e,t,s,o){const n=this.mergeOptions({request:e},this.options,this.toOptions(t,s,o));this.mSockets.length>=this.maxSockets?this.mRequests.push(n):this.createSocket(n,(t=>this.createCallback(e,t)))}createSocket(e,t){const o={};this.mSockets.push(o);const n=this.genConnOptions(e);s.default.debug("","making connect request...");const r=this.mRequest(n);r.useChunkedEncodingByDefault=!1,r.once("response",(e=>{e.upgrade=!0})).once("upgrade",((s,n,i)=>{process.nextTick((()=>{this.onConnect({options:e,connectReq:r,placeholder:o,res:s,socket:n,head:i,callback:t})}))})).once("connect",((s,n,i)=>{this.onConnect({options:e,connectReq:r,placeholder:o,res:s,socket:n,head:i,callback:t})})).once("error",(t=>{r.removeAllListeners(),s.default.debug("","tunneling socket could not be established, cause={}\n",t.message);const n=new Error(`tunneling socket could not be established, cause=${t.message}`);n.code="ECONNRESET",e.request.emit("error",n),this.removeSocket(o)})),r.end()}onConnect(e){if(e.connectReq.removeAllListeners(),e.socket.removeAllListeners(),200!==e.res.statusCode){s.default.debug("","tunneling socket could not be established, statusCode={}",e.res.statusCode),e.socket.destroy();const t=new Error(`tunneling socket could not be established, statusCode=${e.res.statusCode}`);return t.code="ECONNRESET",e.options.request.emit("error",t),void this.removeSocket(e.placeholder)}if(e.head.length>0){s.default.debug("","got illegal response body from proxy"),e.socket.destroy();const t=new Error("got illegal response body from proxy");return t.code="ECONNRESET",e.options.request.emit("error",t),void this.removeSocket(e.placeholder)}s.default.debug("","tunneling connection has established"),this.mSockets[this.mSockets.indexOf(e.placeholder)]=e.socket;const t=e.options.request.getHeader("host"),n=this.mergeOptions({},this.options,{socket:e.socket,servername:t?t.toString().replace(/:.*$/,""):e.options.host}),r=o.connect(0,n);this.mSockets[this.mSockets.indexOf(e.socket)]=r,e.callback(r)}onFreeEvent(e,t,s,o){const n=this.toOptions(t,s,o);for(let t=0;t<this.mRequests.length;t++){const s=this.mRequests[t];if(s&&s.host===n.host&&s.port===n.port)return this.mRequests.splice(t,1),void s.request.onSocket(e)}e.destroy(),this.removeSocket(e)}createCallback(e,t){t.on("free",(()=>this.onFreeListener(t))),t.on("close",(e=>this.onCloseOrRemoveListener(t,e))),t.on("agentRemove",(e=>this.onCloseOrRemoveListener(t,e))),e.onSocket(t)}onFreeListener(e){this.emit("free",e,this.options)}onCloseOrRemoveListener(e,t){t&&s.default.debug("",`onCloseOrRemoveListener, err: ${t}`),this.removeSocket(e),e.removeListener("free",this.onFreeEvent),e.removeListener("close",this.onCloseOrRemoveListener),e.removeListener("agentRemove",this.onCloseOrRemoveListener)}genConnOptions(e){const t=this.mergeOptions({},this.proxyOptions,{method:"CONNECT",path:`${e.host}:${e.port}`,agent:!1,headers:{host:`${e.host}:${e.port}`}});return e.localAddress&&(t.localAddress=e.localAddress),t.proxyAuth&&(t.headers=t.headers||{},t.headers["Proxy-Authorization"]=`Basic ${new Buffer(t.proxyAuth).toString("base64")}`),t}removeSocket(e){const t=this.mSockets.indexOf(e);if(-1===t)return;this.mSockets.splice(t,1);const s=this.mRequests.shift();s&&this.createSocket(s,(function(e){s.request.onSocket(e)}))}toOptions(e,t,s){return"string"==typeof e?{host:e,port:t,localAddress:s}:e}mergeOptions(e,...t){for(let s=0;s<t.length;s++){const o=t[s];if("object"!=typeof o)continue;const n=Object.keys(o);for(let t=0;t<n.length;t++){const s=n[t];void 0!==o[s]&&(e[s]=o[s])}}return e}}