@aikidosec/broker-client 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/app/client.js +41 -39
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -21,7 +21,7 @@ docker compose up -d
21
21
  ## Quick Start
22
22
 
23
23
  1. **Generate CLIENT_SECRET in Aikido UI**:
24
- - Navigate to: Settings → Broker Clients → Add New Client
24
+ - Navigate to: Settings → [Broker Clients](https://app.aikido.dev/settings/integrations/broker/clients) → Add New Client
25
25
  - Copy the generated `CLIENT_SECRET`
26
26
 
27
27
  2. **Configure environment** (`.env`):
package/app/client.js CHANGED
@@ -13,7 +13,6 @@ import dns from 'native-dns';
13
13
  import { ResourceManager } from './resourceManager.js';
14
14
  import { HttpsProxyAgent } from 'https-proxy-agent';
15
15
  import { getClientId, setClientIdCache, getServerUrl, getClientSecret } from './config.js';
16
- import { STREAMING_THRESHOLD } from './streaming/state.js';
17
16
  import { registerStreamingHandlers } from './streaming/handlers.js';
18
17
  import { initStreamingResponse } from './streaming/initStreamingResponse.js';
19
18
  import { startStaleStreamCleanup, cleanupAllStreams } from './streaming/cleanup.js';
@@ -33,7 +32,7 @@ const DNS_SERVERS = process.env.DNS_SERVERS
33
32
  : null;
34
33
 
35
34
  // Configure axios defaults
36
- const MAX_RESPONSE_SIZE = 100 * 1024 * 1024; // 100 MB
35
+ const MAX_RESPONSE_SIZE = 50 * 1024 * 1024; // 50 MB (falls back to streaming if exceeded)
37
36
  const axiosConfig = {
38
37
  timeout: 300000,
39
38
  maxRedirects: 5,
@@ -105,28 +104,44 @@ async function resolveInternalHostname(hostname) {
105
104
  }
106
105
 
107
106
  /**
108
- * Get Content-Length via HEAD request to determine if streaming should be used.
109
- * @param {string} url - URL to check
110
- * @param {object} headers - Headers to send with the request
111
- * @returns {Promise<number|null>} Content-Length in bytes, or null if unavailable
107
+ * Make an internal HTTP request with automatic fallback to streaming if buffered response is too large.
108
+ * @param {object} options - Request options
109
+ * @param {string} options.method - HTTP method
110
+ * @param {string} options.url - Target URL
111
+ * @param {object} options.headers - Request headers
112
+ * @param {*} options.body - Request body
113
+ * @param {string} options.requestId - Request ID for logging
114
+ * @returns {Promise<{response: object, streaming: boolean}>} Response and whether streaming was used
112
115
  */
113
- async function getContentLengthViaHead(url, headers) {
114
- try {
115
- const headResponse = await internalHttpClient.head(url, {
116
+ async function forwardRequestToInternalResource ({ method, url, headers, body, requestId }) {
117
+ const makeRequest = async (streaming) => {
118
+ let requestData = {
119
+ method,
120
+ url,
116
121
  headers,
117
- validateStatus: () => true,
118
- timeout: 5000
119
- });
120
- // Headers can be any case (Content-Length, content-length, CONTENT-LENGTH)
121
- const contentLengthHeader = Object.keys(headResponse.headers)
122
- .find(key => key.toLowerCase() === 'content-length');
123
- const contentLength = contentLengthHeader
124
- ? parseInt(headResponse.headers[contentLengthHeader])
125
- : NaN;
126
- return isNaN(contentLength) ? null : contentLength;
127
- } catch (e) {
128
- log.warn(`HEAD request failed, will use buffered approach: ${e.message}`);
129
- return null;
122
+ data: body,
123
+ validateStatus: () => true, // Accept all status codes
124
+ responseType: streaming ? 'stream' : 'arraybuffer'
125
+ }
126
+ if (streaming) {
127
+ requestData.maxContentLength = Infinity;
128
+ }
129
+ // if streaming, this returns a stream instantly, it does not wait for the full response
130
+ return await internalHttpClient.request(requestData);
131
+ };
132
+
133
+ // Try buffered request first, fallback to streaming if response too large
134
+ try {
135
+ return { response: await makeRequest(false), useStreaming: false };
136
+ } catch (reqError) {
137
+ // Fallback to streaming if buffered request exceeded maxContentLength (axios ERR_BAD_RESPONSE)
138
+ if (axios.isAxiosError(reqError) && // axios does not have a specific error for maxcontent length, so we have to check message (this is about the MAX_RESPONSE_SIZE we set above)
139
+ reqError.code === 'ERR_BAD_RESPONSE' &&
140
+ reqError.message?.includes('maxContentLength')) {
141
+ log.warn(`Buffered request exceeded maxContentLength for ${requestId}, falling back to streaming`);
142
+ return { response: await makeRequest(true), useStreaming: true };
143
+ }
144
+ throw reqError;
130
145
  }
131
146
  }
132
147
 
@@ -342,26 +357,13 @@ socket.on('forward_request', async (data, callback) => {
342
357
  }
343
358
  }
344
359
 
345
- // Check Content-Length first with HEAD request to decide streaming vs buffered
346
- let useStreaming = false;
347
- let contentLength = null;
348
-
349
- if (method === 'GET') {
350
- contentLength = await getContentLengthViaHead(resolvedUrl, headers);
351
- if (contentLength !== null && contentLength > STREAMING_THRESHOLD) {
352
- useStreaming = true;
353
- log.info(`Large response detected (${(contentLength / (1024 * 1024)).toFixed(2)} MB) - using streaming`);
354
- }
355
- }
356
-
357
- // Make the request with appropriate response type
358
- const response = await internalHttpClient.request({
360
+ // Make the request (with automatic fallback to streaming if buffered response is too large)
361
+ const { response, useStreaming } = await forwardRequestToInternalResource ({
359
362
  method,
360
363
  url: resolvedUrl,
361
364
  headers,
362
- data: body,
363
- validateStatus: () => true, // Accept any status code
364
- responseType: useStreaming ? 'stream' : 'arraybuffer',
365
+ body,
366
+ requestId
365
367
  });
366
368
 
367
369
  if (useStreaming) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aikidosec/broker-client",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Aikido Broker Client - Runs in customer network to forward requests to internal resources",
5
5
  "main": "app/client.js",
6
6
  "type": "module",