(method, path, body, timeoutMs)
| 26 | } |
| 27 | |
| 28 | function _proxyRequest(method, path, body, timeoutMs) { |
| 29 | const proxyUrl = getProxyUrl(); |
| 30 | if (!proxyUrl) return Promise.resolve({ ok: false, error: 'proxy_not_running' }); |
| 31 | |
| 32 | const url = new URL(path, proxyUrl); |
| 33 | const timeout = timeoutMs || require('../config').HTTP_TRANSPORT_TIMEOUT_MS; |
| 34 | |
| 35 | return new Promise(function (resolve) { |
| 36 | const payload = body ? JSON.stringify(body) : ''; |
| 37 | const headers = { 'Content-Type': 'application/json' }; |
| 38 | if (payload) headers['Content-Length'] = Buffer.byteLength(payload); |
| 39 | const proxyToken = getProxyToken(); |
| 40 | if (proxyToken) headers['Authorization'] = 'Bearer ' + proxyToken; |
| 41 | |
| 42 | const req = http.request( |
| 43 | { |
| 44 | hostname: url.hostname, |
| 45 | port: url.port, |
| 46 | path: url.pathname + (url.search || ''), |
| 47 | method: method, |
| 48 | headers: headers, |
| 49 | timeout: timeout, |
| 50 | }, |
| 51 | function (res) { |
| 52 | const chunks = []; |
| 53 | res.on('data', function (c) { chunks.push(c); }); |
| 54 | res.on('end', function () { |
| 55 | const raw = Buffer.concat(chunks).toString(); |
| 56 | if (res.statusCode >= 200 && res.statusCode < 300) { |
| 57 | try { resolve({ ok: true, data: JSON.parse(raw) }); } |
| 58 | catch (_) { resolve({ ok: true, data: { raw: raw } }); } |
| 59 | } else { |
| 60 | resolve({ ok: false, status: res.statusCode, error: raw.slice(0, 400) }); |
| 61 | } |
| 62 | }); |
| 63 | } |
| 64 | ); |
| 65 | req.on('error', function (err) { resolve({ ok: false, error: err.message }); }); |
| 66 | req.on('timeout', function () { req.destroy(); resolve({ ok: false, error: 'proxy_timeout' }); }); |
| 67 | if (payload) req.write(payload); |
| 68 | req.end(); |
| 69 | }); |
| 70 | } |
| 71 | |
| 72 | // Route through hubFetch() rather than the global `fetch()` for two |
| 73 | // reasons (both flagged by Cursor reviewers on PR #160): |
no test coverage detected