diff --git a/application/src/main/java/com/codbex/phoebe/proxy/TextResponseBodyRewriter.java b/application/src/main/java/com/codbex/phoebe/proxy/TextResponseBodyRewriter.java index 6e796e0..fbc19e2 100644 --- a/application/src/main/java/com/codbex/phoebe/proxy/TextResponseBodyRewriter.java +++ b/application/src/main/java/com/codbex/phoebe/proxy/TextResponseBodyRewriter.java @@ -111,7 +111,9 @@ private String rewriteFullURLs(ServerRequest request, String body) { String replacement = newAirflowUrl + (extraPath != null ? "/" + extraPath : ""); - matcher.appendReplacement(result, replacement); + // quoteReplacement escapes any '$' or '\' in the matched path (common in minified JS bundles) + // so they are not interpreted as group references by appendReplacement + matcher.appendReplacement(result, Matcher.quoteReplacement(replacement)); } matcher.appendTail(result); @@ -131,7 +133,7 @@ private String rewriteEncodedQueryParams(String body) { String updatedPath = "/services/airflow" + decodedPath; String reEncodedPath = URLEncoder.encode(updatedPath, StandardCharsets.UTF_8); - matcher.appendReplacement(result, paramName + reEncodedPath); + matcher.appendReplacement(result, Matcher.quoteReplacement(paramName + reEncodedPath)); } matcher.appendTail(result); diff --git a/application/src/test/java/com/codbex/phoebe/proxy/TextResponseBodyRewriterTest.java b/application/src/test/java/com/codbex/phoebe/proxy/TextResponseBodyRewriterTest.java index ad563fb..81e92ab 100644 --- a/application/src/test/java/com/codbex/phoebe/proxy/TextResponseBodyRewriterTest.java +++ b/application/src/test/java/com/codbex/phoebe/proxy/TextResponseBodyRewriterTest.java @@ -128,6 +128,21 @@ void rewriteBody_shouldReplaceAirflowUrl_whenHostHeaderIsPresent() { assertEquals(expectedBody, result); } + @Test + void rewriteBody_shouldNotFail_whenAirflowUrlIsFollowedByDollarOrBackslash() { + // minified JS bundles (e.g. Airflow's static assets) may contain '$' or '\' right after the + // Airflow URL; these are special chars for Matcher.appendReplacement and previously caused + // an IllegalArgumentException: Illegal group reference -> HTTP 500 + byte[] body = "var a=\"http://localhost:8080/path/$1\\foo\";".getBytes(StandardCharsets.UTF_8); + String expectedBody = "var a=\"http://localhost:8080/services/airflow/path/$1\\foo\";"; + + when(request.uri()).thenReturn(URI.create("http://localhost:8080/services/airflow")); + + String result = rewriter.rewriteBody(request, body); + + assertEquals(expectedBody, result); + } + @Test void rewriteBody_shouldNotReplaceAirflowUrl_whenHostHeaderIsMissing() { byte[] body = "http://old-airflow-url".getBytes(StandardCharsets.UTF_8);