18 lines
1.4 KiB
JavaScript
18 lines
1.4 KiB
JavaScript
const http=require('node:http');
|
|
function postLoopback({port,route,token,body,signal,maxResponseBytes=2*1024*1024}){
|
|
if(!Number.isInteger(Number(port))||Number(port)<1||Number(port)>65535||!/^\/[a-z0-9/-]+$/i.test(route)||typeof token!=='string')return Promise.reject(Error('Local endpoint rejected'));
|
|
const payload=Buffer.from(JSON.stringify(body));
|
|
return new Promise((resolve,reject)=>{
|
|
// Direct TCP avoids environment/global proxy routing of private content.
|
|
const request=http.request({hostname:'127.0.0.1',port:Number(port),path:route,method:'POST',agent:false,signal,
|
|
headers:{authorization:`Bearer ${token}`,'content-type':'application/json','content-length':payload.length}},response=>{
|
|
if(response.statusCode>=300&&response.statusCode<400){response.resume();reject(Error('Local redirects rejected'));return;}
|
|
let size=0;const chunks=[];response.on('error',reject);
|
|
response.on('data',chunk=>{size+=chunk.length;if(size>maxResponseBytes){response.destroy();request.destroy();reject(Error('Local response budget exceeded'));}else chunks.push(chunk);});
|
|
response.on('end',()=>{try{resolve({status:response.statusCode,body:JSON.parse(Buffer.concat(chunks).toString('utf8'))});}catch{reject(Error('Invalid local JSON response'));}});
|
|
});
|
|
request.on('error',reject);request.end(payload);
|
|
});
|
|
}
|
|
module.exports={postLoopback};
|