This is an automated email from the ASF dual-hosted git repository.

thiagoelg pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git


The following commit(s) were added to refs/heads/main by this push:
     new 99526f14e87 kie-issues#2209: CORS Proxy sometimes break with gzip 
encoded responses (#3395)
99526f14e87 is described below

commit 99526f14e87f701422eb25daa1835bb422552c9f
Author: Thiago Lugli <[email protected]>
AuthorDate: Thu Jan 22 16:36:55 2026 -0300

    kie-issues#2209: CORS Proxy sometimes break with gzip encoded responses 
(#3395)
---
 packages/cors-proxy-api/src/index.ts              |  1 +
 packages/cors-proxy/src/proxy/ExpressCorsProxy.ts | 77 ++++++++++++++++-------
 packages/cors-proxy/webpack.config.js             |  2 +-
 packages/online-editor/build/defaultEnvJson.ts    |  1 -
 4 files changed, 56 insertions(+), 25 deletions(-)

diff --git a/packages/cors-proxy-api/src/index.ts 
b/packages/cors-proxy-api/src/index.ts
index b623f62e559..b0488990940 100644
--- a/packages/cors-proxy-api/src/index.ts
+++ b/packages/cors-proxy-api/src/index.ts
@@ -21,6 +21,7 @@ export enum CorsProxyHeaderKeys {
   TARGET_URL = "target-url",
   INSECURELY_DISABLE_TLS_CERTIFICATE_VALIDATION = 
"insecurely-disable-tls-certificate-validation",
   DISABLE_ENCODING = "disable-encoding",
+  ADD_PROXIED_URL_AS_ORIGIN = "add-proxied-url-as-origin",
 }
 
 export type CorsConfig = {
diff --git a/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts 
b/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
index edc367daed9..3b40cec3fca 100644
--- a/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
+++ b/packages/cors-proxy/src/proxy/ExpressCorsProxy.ts
@@ -46,8 +46,7 @@ export class ExpressCorsProxy implements CorsProxy<Request, 
Response> {
   ) {
     this.logger = new Logger(args.verbose);
 
-    this.logger.debug("");
-    this.logger.debug("Proxy Configuration:");
+    this.logger.debug("\nProxy Configuration:");
     this.logger.debug("* Verbose: ", args.verbose);
     this.logger.debug("");
   }
@@ -60,26 +59,33 @@ export class ExpressCorsProxy implements CorsProxy<Request, 
Response> {
       this.logger.debugEscapeNewLines("Request Method: ", req.method);
       this.logger.debugEscapeNewLines("Request Headers: ", req.headers);
 
-      // Creating the headers for the new request
+      // Build outgoing headers
       const outHeaders: Record<string, string> = { 
...info?.corsConfig?.customHeaders };
 
       Object.keys(req.headers).forEach((header) => {
         if (!BANNED_PROXY_HEADERS.includes(header) && !outHeaders[header]) {
           if (!info.corsConfig || 
info.corsConfig.allowHeaders.includes(header)) {
-            outHeaders[header] = req.headers[header] as string;
+            const value = req.headers[header];
+            // header value can be string | string[] | undefined
+            if (Array.isArray(value)) {
+              outHeaders[header] = value.join(", ");
+            } else if (typeof value === "string") {
+              outHeaders[header] = value;
+            }
           }
         }
       });
 
-      // TO DO: Figure out why this gzip encoding is broken with insecure tls 
certificates!
-      if 
(req.headers[CorsProxyHeaderKeys.INSECURELY_DISABLE_TLS_CERTIFICATE_VALIDATION] 
=== "true") {
-        outHeaders["accept-encoding"] = "identity";
-      }
       // Force uncompressed response if encoding is disabled via header
       if (req.headers[CorsProxyHeaderKeys.DISABLE_ENCODING] === "true") {
         outHeaders["accept-encoding"] = "identity";
       }
 
+      // Useful for Atlassian Bitbucket Data Center XSRF-check-failed issue
+      if (req.headers[CorsProxyHeaderKeys.ADD_PROXIED_URL_AS_ORIGIN] === 
"true") {
+        outHeaders["Origin"] = info.proxyUrl.origin;
+      }
+
       this.logger.log("Proxying to: ", info.proxyUrl.toString());
       this.logger.debugEscapeNewLines("Proxy Method: ", req.method);
       this.logger.debug("Proxy Headers: ", outHeaders);
@@ -88,6 +94,7 @@ export class ExpressCorsProxy implements CorsProxy<Request, 
Response> {
         method: req.method,
         headers: outHeaders,
         redirect: "manual",
+        // pass the original request stream for non-GET/HEAD methods
         body: req.method !== "GET" && req.method !== "HEAD" ? req : undefined,
         agent: this.getProxyAgent(info),
       });
@@ -102,6 +109,7 @@ export class ExpressCorsProxy implements CorsProxy<Request, 
Response> {
         proxyResponse.headers.set("location", info.targetUrl);
       }
 
+      // Copy allowed headers to response
       proxyResponse.headers.forEach((value, header) => {
         if (header.toLowerCase() === "access-control-allow-origin") {
           return;
@@ -119,23 +127,46 @@ export class ExpressCorsProxy implements 
CorsProxy<Request, Response> {
 
       res.status(proxyResponse.status);
 
-      this.logger.debug("Writing Response...");
-      if (proxyResponse.body) {
-        const stream = proxyResponse.body.pipe(res);
-        stream.on("close", () => {
-          this.logger.log("Request succesfully proxied!");
+      this.logger.debug("Streaming response to client...");
+
+      try {
+        if (proxyResponse.body) {
+          // Prevent client-side truncation due to mismatched content-length
+          try {
+            res.removeHeader("content-encoding");
+            res.removeHeader("content-length");
+          } catch (e) {
+            // ignore if not settable
+          }
+
+          proxyResponse.body.on("error", (e: any) => {
+            this.logger.warn("Stream error while proxying response: ", e);
+            // make sure connection is closed and middleware chain proceeds
+            try {
+              if (!res.headersSent) {
+                res.status(502);
+              }
+              res.end();
+            } catch (err) {
+              // ignore
+            }
+            next();
+          });
+
+          // Pipe and let Node manage ending the response
+          proxyResponse.body.pipe(res).on("finish", () => {
+            this.logger.log("Request successfully proxied!");
+          });
+        } else {
+          this.logger.log("Request successfully proxied (no body).");
           res.end();
-        });
-        stream.on("error", (e) => {
-          this.logger.warn("Something went wrong when writting the new 
response... ", e);
-          next();
-        });
-      } else {
-        this.logger.log("Request succesfully proxied!");
-        res.end();
+        }
+      } catch (err: any) {
+        this.logger.warn("Unexpected error while streaming response: ", err);
+        next();
       }
-    } catch (err) {
-      this.logger.warn("Couldn't handle request correctly due to: ", 
err.message);
+    } catch (err: any) {
+      this.logger.warn("Couldn't handle request correctly due to: ", 
err?.message ?? err);
       next();
     }
   }
diff --git a/packages/cors-proxy/webpack.config.js 
b/packages/cors-proxy/webpack.config.js
index 50f4700501a..9172d65917b 100644
--- a/packages/cors-proxy/webpack.config.js
+++ b/packages/cors-proxy/webpack.config.js
@@ -27,6 +27,6 @@ module.exports = (webpackEnv, webpackArgv) => [
     },
     target: "node",
     // FIXME: Ignoring warnings for express due to: 
https://github.com/webpack/webpack/issues/1576
-    ignoreWarnings: [/express/],
+    ignoreWarnings: [/express/, /https-proxy-agent/, /agent-base/],
   }),
 ];
diff --git a/packages/online-editor/build/defaultEnvJson.ts 
b/packages/online-editor/build/defaultEnvJson.ts
index 5608b7d9c3d..b5104f88f8f 100644
--- a/packages/online-editor/build/defaultEnvJson.ts
+++ b/packages/online-editor/build/defaultEnvJson.ts
@@ -77,7 +77,6 @@ export const defaultEnvJson: EnvJson = {
       enabled: true,
       iconPath: routes.static.images.gitlabLogo.path({}),
       group: AuthProviderGroup.GIT,
-      disableEncoding: true,
     },
     {
       id: "bitbucket_dot_org",


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to