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

jmclean 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 fca9e35401 Fixed UI routes ending in WebUIFilter (#9135)
fca9e35401 is described below

commit fca9e354016f9187a2d78513387bce9c00dd5904
Author: Joel <[email protected]>
AuthorDate: Tue Nov 18 22:22:35 2025 -0600

    Fixed UI routes ending in WebUIFilter (#9135)
    
    ### What changes were proposed in this pull request?
    
    This pull request fixes the routing logic in WebUIFilter to correctly
    resolve UI paths that either:
    
    1. End with a trailing slash
    2. Omit a file extension
    
    The filter now:
    
    - Forwards directory paths to index.html
    
    ````/ui/section/ → /ui/section/index.html````
    
    - Forwards extension-less UI paths to .html
    
    ````/ui/dashboard → /ui/dashboard.html````
    
    This ensures that static HTML pages are correctly served by the Web UI.
    
    ### Why are the changes needed?
    
    The previous implementation incorrectly handled directory-style UI
    routes.
A request such as:
    ````
    /ui/section/
    ````
    was forwarded to:
    
    ````
    /ui/section/.html
    ````
    instead of:
    
    ````
    /ui/section/index.html
    ````
    This caused the UI to render incorrectly and broke navigation on static
    exports.
    The PR fixes this bug by adding explicit handling for trailing-slash
    directory routes.
    
    Fix: #9123
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes.
    Requests to UI directories now correctly resolve to index.html pages
    instead of returning an invalid .html path.
---
 .../gravitino/server/web/ui/WebUIFilter.java       |  7 +++
 .../gravitino/server/web/ui/WebUIFilterTest.java   | 53 ++++++++++++++++++++++
 2 files changed, 60 insertions(+)

diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/ui/WebUIFilter.java 
b/server/src/main/java/org/apache/gravitino/server/web/ui/WebUIFilter.java
index d1722bff4a..9a87fcccdd 100644
--- a/server/src/main/java/org/apache/gravitino/server/web/ui/WebUIFilter.java
+++ b/server/src/main/java/org/apache/gravitino/server/web/ui/WebUIFilter.java
@@ -33,15 +33,22 @@ public class WebUIFilter implements Filter {
   @Override
   public void doFilter(ServletRequest request, ServletResponse response, 
FilterChain chain)
       throws IOException, ServletException {
+
     HttpServletRequest httpRequest = (HttpServletRequest) request;
     String path = httpRequest.getRequestURI();
     String lastPathSegment = path.substring(path.lastIndexOf("/") + 1);
+
     if (path.equals("/") || path.equals("/ui") || path.equals("/ui/")) {
       // Redirect to the index page.
       httpRequest.getRequestDispatcher("/ui/index.html").forward(request, 
response);
+
+    } else if (path.startsWith("/ui/") && path.endsWith("/")) {
+      httpRequest.getRequestDispatcher(path + "index.html").forward(request, 
response);
+
     } else if (path.startsWith("/ui/") && !lastPathSegment.contains(".")) {
       // Redirect to the static HTML file.
       httpRequest.getRequestDispatcher(path + ".html").forward(request, 
response);
+
     } else {
       // Continue processing the rest of the filter chain.
       chain.doFilter(request, response);
diff --git 
a/server/src/test/java/org/apache/gravitino/server/web/ui/WebUIFilterTest.java 
b/server/src/test/java/org/apache/gravitino/server/web/ui/WebUIFilterTest.java
new file mode 100644
index 0000000000..6051023613
--- /dev/null
+++ 
b/server/src/test/java/org/apache/gravitino/server/web/ui/WebUIFilterTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.server.web.ui;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import org.junit.jupiter.api.Test;
+
+public class WebUIFilterTest {
+  @Test
+  public void testNestedDirectoryRequestForwardsToIndexHtml() throws 
ServletException, IOException {
+    WebUIFilter filter = new WebUIFilter();
+    HttpServletRequest request = mock(HttpServletRequest.class);
+    ServletResponse response = mock(ServletResponse.class);
+    FilterChain chain = mock(FilterChain.class);
+    RequestDispatcher dispatcher = mock(RequestDispatcher.class);
+
+    when(request.getRequestURI()).thenReturn("/ui/section/subsection/");
+    
when(request.getRequestDispatcher("/ui/section/subsection/index.html")).thenReturn(dispatcher);
+
+    filter.doFilter(request, response, chain);
+
+    verify(dispatcher).forward(request, response);
+    verify(chain, never()).doFilter(any(), any());
+  }
+}

Reply via email to