From d49342ce48f439095b0165fe15e05c4b801d0319 Mon Sep 17 00:00:00 2001 From: Ainur <59531286+yagudin10@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:25:47 +0200 Subject: [PATCH] CB-5713 fix action links (#2991) --- .../actions/AbstractActionServletHandler.java | 3 +- .../server/jetty/CBJettyServer.java | 6 +- .../server/servlets/CBStaticServlet.java | 54 ++++++++++++- .../server/servlets/ProxyResourceHandler.java | 80 ------------------- .../auth/local/LocalServletHandler.java | 2 +- 5 files changed, 59 insertions(+), 86 deletions(-) delete mode 100644 server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/ProxyResourceHandler.java diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/actions/AbstractActionServletHandler.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/actions/AbstractActionServletHandler.java index f6c68805f8..bcf97f7aaf 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/actions/AbstractActionServletHandler.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/actions/AbstractActionServletHandler.java @@ -18,6 +18,7 @@ import io.cloudbeaver.model.session.WebSession; import io.cloudbeaver.service.DBWServletHandler; +import io.cloudbeaver.utils.WebAppUtils; import jakarta.servlet.Servlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -43,7 +44,7 @@ protected void createActionFromParams(WebSession session, HttpServletRequest req action.saveInSession(session); // Redirect to home - response.sendRedirect("/"); + response.sendRedirect(WebAppUtils.getWebApplication().getServerConfiguration().getRootURI()); } protected abstract String getActionConsole(); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServer.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServer.java index 4c7cfde0cc..e3c94cce88 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServer.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/jetty/CBJettyServer.java @@ -24,7 +24,6 @@ import io.cloudbeaver.server.servlets.CBImageServlet; import io.cloudbeaver.server.servlets.CBStaticServlet; import io.cloudbeaver.server.servlets.CBStatusServlet; -import io.cloudbeaver.server.servlets.ProxyResourceHandler; import io.cloudbeaver.server.websockets.CBJettyWebSocketManager; import io.cloudbeaver.service.DBWServiceBindingServlet; import io.cloudbeaver.service.DBWServiceBindingWebSocket; @@ -101,11 +100,12 @@ public void runServer() { String rootURI = serverConfiguration.getRootURI(); servletContextHandler.setContextPath(rootURI); - ServletHolder staticServletHolder = new ServletHolder("static", new CBStaticServlet()); + ServletHolder staticServletHolder = new ServletHolder( + "static", new CBStaticServlet(Path.of(serverConfiguration.getContentRoot())) + ); staticServletHolder.setInitParameter("dirAllowed", "false"); staticServletHolder.setInitParameter("cacheControl", "public, max-age=" + CBStaticServlet.STATIC_CACHE_SECONDS); servletContextHandler.addServlet(staticServletHolder, "/"); - servletContextHandler.insertHandler(new ProxyResourceHandler(Path.of(serverConfiguration.getContentRoot()))); if (Files.isSymbolicLink(contentRootPath)) { servletContextHandler.addAliasCheck(new CBSymLinkContentAllowedAliasChecker(contentRootPath)); diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java index e558dd4c75..232d57f3f9 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/CBStaticServlet.java @@ -35,14 +35,23 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.ee10.servlet.DefaultServlet; +import org.eclipse.jetty.http.HttpHeader; +import org.jkiss.code.NotNull; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.auth.SMAuthInfo; import org.jkiss.dbeaver.model.auth.SMAuthProvider; import org.jkiss.dbeaver.model.security.SMAuthProviderCustomConfiguration; import org.jkiss.utils.CommonUtils; +import org.jkiss.utils.IOUtils; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Map; @WebServlet(urlPatterns = "/") @@ -54,6 +63,13 @@ public class CBStaticServlet extends DefaultServlet { private static final Log log = Log.getLog(CBStaticServlet.class); + @NotNull + private final Path contentRoot; + + public CBStaticServlet(@NotNull Path contentRoot) { + this.contentRoot = contentRoot; + } + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { for (WebServletHandlerDescriptor handler : WebHandlerRegistry.getInstance().getServletHandlers()) { @@ -83,7 +99,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t } catch (DBWebException e) { log.error("Error reading websession", e); } - super.doGet(request, response); + patchStaticContentIfNeeded(request, response); } private void performAutoLoginIfNeeded(HttpServletRequest request, WebSession webSession) { @@ -177,4 +193,40 @@ private boolean processSessionStart(HttpServletRequest request, HttpServletRespo return false; } + private void patchStaticContentIfNeeded(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + String pathInContext = request.getServletPath(); + + if ("/".equals(pathInContext)) { + pathInContext = "index.html"; + } + + if (pathInContext == null || !pathInContext.endsWith("index.html") + && !pathInContext.endsWith("sso.html") + && !pathInContext.endsWith("ssoError.html") + ) { + super.doGet(request, response); + return; + } + + if (pathInContext.startsWith("/")) { + pathInContext = pathInContext.substring(1); + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + var filePath = contentRoot.resolve(pathInContext); + try (InputStream fis = Files.newInputStream(filePath)) { + IOUtils.copyStream(fis, baos); + } + String indexContents = baos.toString(StandardCharsets.UTF_8); + CBServerConfig serverConfig = CBApplication.getInstance().getServerConfiguration(); + indexContents = indexContents + .replace("{ROOT_URI}", serverConfig.getRootURI()) + .replace("{STATIC_CONTENT}", serverConfig.getStaticContent()); + byte[] indexBytes = indexContents.getBytes(StandardCharsets.UTF_8); + + // Disable cache for index.html + response.setHeader(HttpHeader.CACHE_CONTROL.toString(), "no-cache, no-store, must-revalidate"); + response.setHeader(HttpHeader.EXPIRES.toString(), "0"); + response.getOutputStream().write(ByteBuffer.wrap(indexBytes)); + } + } \ No newline at end of file diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/ProxyResourceHandler.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/ProxyResourceHandler.java deleted file mode 100644 index c9c20d874b..0000000000 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/server/servlets/ProxyResourceHandler.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * DBeaver - Universal Database Manager - * Copyright (C) 2010-2024 DBeaver Corp and others - * - * Licensed 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 io.cloudbeaver.server.servlets; - -import io.cloudbeaver.model.config.CBServerConfig; -import io.cloudbeaver.server.CBApplication; -import org.eclipse.jetty.http.HttpHeader; -import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Response; -import org.eclipse.jetty.util.Callback; -import org.jkiss.code.NotNull; -import org.jkiss.utils.IOUtils; - -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; - -public class ProxyResourceHandler extends Handler.Wrapper { - @NotNull - private final Path contentRoot; - - public ProxyResourceHandler(@NotNull Path contentRoot) { - this.contentRoot = contentRoot; - } - - public boolean handle(Request request, Response response, Callback callback) throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - String pathInContext = Request.getPathInContext(request); - - if ("/".equals(pathInContext)) { - pathInContext = "index.html"; - } - - if (pathInContext == null || !pathInContext.endsWith("index.html") - && !pathInContext.endsWith("sso.html") - && !pathInContext.endsWith("ssoError.html") - ) { - return super.handle(request, response, callback); - } - - if (pathInContext.startsWith("/")) { - pathInContext = pathInContext.substring(1); - } - var filePath = contentRoot.resolve(pathInContext); - try (InputStream fis = Files.newInputStream(filePath)) { - IOUtils.copyStream(fis, baos); - } - String indexContents = baos.toString(StandardCharsets.UTF_8); - CBServerConfig serverConfig = CBApplication.getInstance().getServerConfiguration(); - indexContents = indexContents - .replace("{ROOT_URI}", serverConfig.getRootURI()) - .replace("{STATIC_CONTENT}", serverConfig.getStaticContent()); - byte[] indexBytes = indexContents.getBytes(StandardCharsets.UTF_8); - - // Disable cache for index.html - response.getHeaders().put(HttpHeader.CACHE_CONTROL.toString(), "no-cache, no-store, must-revalidate"); - response.getHeaders().put(HttpHeader.EXPIRES.toString(), "0"); - - response.write(true, ByteBuffer.wrap(indexBytes), callback); - return true; - } -} diff --git a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/local/LocalServletHandler.java b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/local/LocalServletHandler.java index 9f31bf115f..42d2024e83 100644 --- a/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/local/LocalServletHandler.java +++ b/server/bundles/io.cloudbeaver.service.auth/src/io/cloudbeaver/service/auth/local/LocalServletHandler.java @@ -40,7 +40,7 @@ public class LocalServletHandler extends AbstractActionServletHandler { @Override public boolean handleRequest(Servlet servlet, HttpServletRequest request, HttpServletResponse response) throws DBException, IOException { - if (URI_PREFIX.equals(WebAppUtils.removeSideSlashes(request.getPathInfo()))) { + if (URI_PREFIX.equals(WebAppUtils.removeSideSlashes(request.getServletPath()))) { try { WebSession webSession = CBPlatform.getInstance().getSessionManager().getWebSession(request, response, true); createActionFromParams(webSession, request, response);