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

jerryshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 75deae2b10 [#10846] fix(server): Add /health.html alias for legacy GTM 
standards (#10847)
75deae2b10 is described below

commit 75deae2b10feeaa0d4251506b2e5731eaaf4c73d
Author: Mark Hoerth <[email protected]>
AuthorDate: Thu Apr 23 01:08:41 2026 -0700

    [#10846] fix(server): Add /health.html alias for legacy GTM standards 
(#10847)
    
    Follow-up to #10839. #10840 added /health, /health/live, /health/ready
    root-level aliases but dropped /health.html during the merge refactor.
    This restores /health.html and maps it to the canonical /api/health
    aggregate endpoint — legacy GTM onboarding standards commonly hardcode
    the .html extension as a well-known probe path.
    
    Adds test coverage for /health.html in TestHealthAliasServlet.
    
    Fixes #10846
    
    ### What changes were proposed in this pull request?
    
    Restores `/health.html` as a root-level alias forwarding to
    `/api/health`. Three small changes:
    
    1. `HealthAliasServlet.doGet` — map `/health.html` to `/api/health` (the
    aggregate endpoint), rather than the default `/api` prefix rule which
    would incorrectly target `/api/health.html`.
    2. `GravitinoServer` — register the alias servlet at `/health.html`
    (outside the `/health/*` glob spec Jetty uses for sub-paths).
    3. `TestHealthAliasServlet` — extend the parameterized forward test to
    cover `/health.html → /api/health`.
    
    ### Why are the changes needed?
    
    #10840 added root-level aliases `/health`, `/health/live`,
    `/health/ready` for "enterprise GTM standards that hardcode well-known
    root paths." `/health.html` — arguably the most commonly hardcoded GTM
    probe path (predates MicroProfile Health, common in enterprise GTM
    onboarding specs) — was part of the original PR and was dropped during
    the merge refactor. Without `.html`, customers whose GTM standards
    specifically require `/health.html` cannot use the aliases.
    
    Smoke test confirms the fix:
    curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8090/health #
    200
    curl -s -o /dev/null -w "%{http_code}\n"
    http://localhost:8090/health.html # 200 (was 404)
    curl -s -o /dev/null -w "%{http_code}\n"
    http://localhost:8090/api/health # 200
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes — adds one public endpoint (`GET /health.html`). Returns the same
    aggregate JSON body as `/health` and `/api/health`. No other endpoint
    behavior is changed.
    
    ### How was this patch tested?
    
    - `TestHealthAliasServlet` parameterized test extended with
    `/health.html → /api/health` case.
    - Manual verification against a running Gravitino instance:
    `/health.html` returns 200 with the same body as `/api/health` (134-byte
    aggregate JSON); existing `/health`, `/health/live`, `/health/ready`,
    `/api/health*`, and `/api/version` all unchanged.
    
    ### Notes for reviewers
    
    - **Special-case mapping for `.html`**: `HealthAliasServlet` maps
    `/health.html` to the aggregate `/api/health`, not `/api/health.html`.
    `.html` is a legacy web-server convention used as a sibling of
    `/health`, not a sub-path. Keeping the mapping rule explicit in the
    servlet rather than adding a separate alias endpoint keeps the servlet
    single-purpose.
    - **Test gap observation**: this regression slipped through #10840
    because `TestHealthAliasServlet` mocks `getRequestDispatcher()`, which
    validates the servlet's path-rewriting logic but doesn't exercise
    Jetty's path-spec matching in `GravitinoServer.addServlet(...)`. The bug
    was one level up from what the unit test covers. Worth considering an
    integration test that boots the server and curls each GTM-relevant path
    — happy to open a separate issue if useful.
    - **This change should be cherry-picked to `branch-1.2`** alongside the
    main #10840 backport, so RBC and other 1.2 customers get the complete
    fix in one coherent change.
    
    ---------
    
    Co-authored-by: Mark Hoerth <[email protected]>
    Co-authored-by: Jerry Shao <[email protected]>
    Co-authored-by: Claude Sonnet 4.6 <[email protected]>
---
 docs/open-api/health.yaml                                     |  6 ++++++
 .../gravitino/server/authentication/AuthenticationFilter.java |  5 +++--
 .../server/authentication/TestAuthenticationFilter.java       |  1 +
 .../java/org/apache/gravitino/server/GravitinoServer.java     |  6 ++++--
 .../org/apache/gravitino/server/web/HealthAliasServlet.java   | 11 +++++++----
 .../apache/gravitino/server/web/TestHealthAliasServlet.java   |  1 +
 6 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/docs/open-api/health.yaml b/docs/open-api/health.yaml
index d6956446bd..dd4be8bdae 100644
--- a/docs/open-api/health.yaml
+++ b/docs/open-api/health.yaml
@@ -29,6 +29,8 @@ paths:
         Returns aggregate health status combining liveness and readiness 
checks.
         Returns 200 when all checks pass; 503 when any check fails.
         This endpoint is exempt from authentication so probes can reach it 
without credentials.
+        Root-level aliases at /health and /health.html (outside the /api base 
path) are also
+        available for GTMs that require probes at well-known root paths.
       security: []
       responses:
         "200":
@@ -50,6 +52,8 @@ paths:
         Returns 200 as long as the HTTP server thread can respond.
         Use this for Kubernetes liveness probes to determine whether to 
restart a pod.
         This endpoint is exempt from authentication so probes can reach it 
without credentials.
+        A root-level alias at /health/live (outside the /api base path) is 
also available
+        for GTMs that require probes at well-known root paths.
       security: []
       responses:
         "200":
@@ -70,6 +74,8 @@ paths:
         Returns 503 when the entity store is unavailable or slow.
         Use this for Kubernetes readiness probes to control traffic routing.
         This endpoint is exempt from authentication so probes can reach it 
without credentials.
+        A root-level alias at /health/ready (outside the /api base path) is 
also available
+        for GTMs that require probes at well-known root paths.
       security: []
       responses:
         "200":
diff --git 
a/server-common/src/main/java/org/apache/gravitino/server/authentication/AuthenticationFilter.java
 
b/server-common/src/main/java/org/apache/gravitino/server/authentication/AuthenticationFilter.java
index 66a05bd485..f91a55607a 100644
--- 
a/server-common/src/main/java/org/apache/gravitino/server/authentication/AuthenticationFilter.java
+++ 
b/server-common/src/main/java/org/apache/gravitino/server/authentication/AuthenticationFilter.java
@@ -140,10 +140,11 @@ public class AuthenticationFilter implements Filter {
     if (path == null) {
       return false;
     }
-    // Also match /health and /health/* — the root-level aliases that forward 
to /api/health/*.
-    // During a forward, getRequestURI() returns the original URI, not the 
forwarded target.
+    // Also match /health, /health/*, and /health.html — root-level aliases 
that forward to
+    // /api/health/*. During a forward, getRequestURI() returns the original 
URI, not the target.
     return path.equals("/health")
         || path.startsWith("/health/")
+        || path.equals("/health.html")
         || path.equals("/api/health")
         || path.startsWith("/api/health/");
   }
diff --git 
a/server-common/src/test/java/org/apache/gravitino/server/authentication/TestAuthenticationFilter.java
 
b/server-common/src/test/java/org/apache/gravitino/server/authentication/TestAuthenticationFilter.java
index 7366b89db6..8c227727b4 100644
--- 
a/server-common/src/test/java/org/apache/gravitino/server/authentication/TestAuthenticationFilter.java
+++ 
b/server-common/src/test/java/org/apache/gravitino/server/authentication/TestAuthenticationFilter.java
@@ -132,6 +132,7 @@ public class TestAuthenticationFilter {
       "/health",
       "/health/live",
       "/health/ready",
+      "/health.html",
       "/api/health",
       "/api/health/",
       "/api/health/live",
diff --git 
a/server/src/main/java/org/apache/gravitino/server/GravitinoServer.java 
b/server/src/main/java/org/apache/gravitino/server/GravitinoServer.java
index dc8dda7362..0d45a57721 100644
--- a/server/src/main/java/org/apache/gravitino/server/GravitinoServer.java
+++ b/server/src/main/java/org/apache/gravitino/server/GravitinoServer.java
@@ -177,9 +177,11 @@ public class GravitinoServer extends ResourceConfig {
     Servlet configServlet = new ConfigServlet(serverConfig);
     server.addServlet(configServlet, "/configs");
 
-    // Root-level alias for enterprise GTMs that require probes at well-known 
root paths.
-    // Forwards /health, /health/live, /health/ready to the canonical 
/api/health/* endpoints.
+    // Root-level aliases for enterprise GTMs that require probes at 
well-known root paths.
+    // Forwards /health, /health/live, /health/ready, and /health.html to the 
canonical
+    // /api/health/* endpoints.
     server.addServlet(new HealthAliasServlet(), "/health/*");
+    server.addServlet(new HealthAliasServlet(), "/health.html");
 
     server.addCustomFilters(API_ANY_PATH);
     server.addFilter(new VersioningFilter(), API_ANY_PATH);
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/HealthAliasServlet.java 
b/server/src/main/java/org/apache/gravitino/server/web/HealthAliasServlet.java
index daf21b9057..532bc44e4a 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/HealthAliasServlet.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/HealthAliasServlet.java
@@ -26,8 +26,8 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 /**
- * Serves root-level health paths ({@code /health}, {@code /health/live}, 
{@code /health/ready}) by
- * forwarding to the canonical {@code /api/health/*} endpoints.
+ * Serves root-level health paths ({@code /health}, {@code /health/live}, 
{@code /health/ready},
+ * {@code /health.html}) by forwarding to the canonical {@code /api/health/*} 
endpoints.
  *
  * <p>This alias exists for compatibility with enterprise global traffic 
managers that require
  * probes at well-known root paths. The canonical implementation remains at 
{@code /api/health}.
@@ -37,8 +37,11 @@ public class HealthAliasServlet extends HttpServlet {
   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
       throws ServletException, IOException {
-    // Prepend /api to the incoming path: /health → /api/health, /health/live 
→ /api/health/live
-    String targetPath = "/api" + req.getRequestURI();
+    // Map root-level health paths to their canonical /api/health counterparts.
+    // /health and /health.html both target the aggregate /api/health; legacy 
GTM
+    // standards sometimes hardcode the .html extension.
+    String uri = req.getRequestURI();
+    String targetPath = "/health.html".equals(uri) ? "/api/health" : "/api" + 
uri;
     RequestDispatcher dispatcher = req.getRequestDispatcher(targetPath);
     if (dispatcher == null) {
       resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "health 
dispatcher unavailable");
diff --git 
a/server/src/test/java/org/apache/gravitino/server/web/TestHealthAliasServlet.java
 
b/server/src/test/java/org/apache/gravitino/server/web/TestHealthAliasServlet.java
index 876af0111b..1d0e6e3e8a 100644
--- 
a/server/src/test/java/org/apache/gravitino/server/web/TestHealthAliasServlet.java
+++ 
b/server/src/test/java/org/apache/gravitino/server/web/TestHealthAliasServlet.java
@@ -34,6 +34,7 @@ public class TestHealthAliasServlet {
   @ParameterizedTest
   @CsvSource({
     "/health,        /api/health",
+    "/health.html,   /api/health",
     "/health/live,   /api/health/live",
     "/health/ready,  /api/health/ready"
   })

Reply via email to