This is an automated email from the ASF dual-hosted git repository.
pzampino pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new d484689bf KNOX-3058: Avoid 404 When Topology Is Being Redeployed (#929)
d484689bf is described below
commit d484689bfd22d633f13209cc65dc17994bfd4c3e
Author: Phil Zampino <[email protected]>
AuthorDate: Wed Aug 21 18:11:15 2024 -0400
KNOX-3058: Avoid 404 When Topology Is Being Redeployed (#929)
---
.../org/apache/knox/gateway/GatewayServer.java | 84 +++++++++++++++++++++-
1 file changed, 83 insertions(+), 1 deletion(-)
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
index 4e8c83458..40f926bcd 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
@@ -62,11 +62,13 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.NetworkConnector;
+import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.util.ssl.SslContextFactory;
@@ -84,6 +86,8 @@ import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.servlet.SessionCookieConfig;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import java.io.File;
@@ -148,6 +152,8 @@ public class GatewayServer {
private AtomicBoolean stopped = new AtomicBoolean(false);
private GatewayStatusService gatewayStatusService;
+ private final Set<String> inactiveTopologies = new HashSet<>();
+
public static void main( String[] args ) {
try {
logSysProps();
@@ -717,6 +723,22 @@ public class GatewayServer {
jetty.setAttribute(ContextHandler.MAX_FORM_KEYS_KEY,
config.getJettyMaxFormKeys());
log.setMaxFormKeys(config.getJettyMaxFormKeys());
+ // Add a handler for the 404 responses when a topology is being redeployed
(i.e., is inactive)
+// jetty.setErrorHandler(new ErrorHandler() {
+// @Override
+// public void doError(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response) throws IOException {
+// final int gatewayPrefixLength = ("/" + config.getGatewayPath() +
"/").length();
+// String pathInfo = baseRequest.getPathInfo();
+// String topologyName = pathInfo.substring(gatewayPrefixLength,
pathInfo.indexOf('/', gatewayPrefixLength));
+// if (isInactiveTopology(topologyName) && (response.getStatus() ==
HttpServletResponse.SC_NOT_FOUND)) {
+// request.setAttribute("javax.servlet.error.message", "Service
Unavailable"); // The default ErrorHandler references this attribute
+// response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+// }
+// super.doError(target, baseRequest, request, response);
+// }
+// });
+ jetty.setErrorHandler(new Http404ErrorHandler(this,
config.getGatewayPath()));
+
/* topologyName is null because all topology listen on this port */
List<Connector> connectors = createConnector( jetty, config,
config.getGatewayPort(), null);
for (Connector connector : connectors) {
@@ -915,13 +937,21 @@ public class GatewayServer {
}
private synchronized void internalActivateTopology( Topology topology, File
topoDir ) {
- log.activatingTopology( topology.getName() );
+ final String name = topology.getName();
+
+ // Add the topology to the inactive set until it has been activated
+ addInactiveTopology(name);
+
+ log.activatingTopology(name);
File[] files = topoDir.listFiles( new RegexFilenameFilter( "%.*" ) );
if( files != null ) {
for( File file : files ) {
internalActivateArchive( topology, file );
}
}
+
+ // Remove the topology from the inactive set
+ removeInactiveTopology(name);
}
private synchronized void internalActivateArchive( Topology topology, File
warDir ) {
@@ -962,10 +992,32 @@ public class GatewayServer {
});
}
+ private void addInactiveTopology(final String topologyName) {
+ synchronized (inactiveTopologies) {
+ inactiveTopologies.add(topologyName);
+ }
+ }
+
+ private void removeInactiveTopology(final String topologyName) {
+ synchronized (inactiveTopologies) {
+ inactiveTopologies.remove(topologyName);
+ }
+ }
+
+ private boolean isInactiveTopology(final String topologyName) {
+ boolean result = false;
+ synchronized (inactiveTopologies) {
+ result = inactiveTopologies.contains(topologyName);
+ }
+ return result;
+ }
+
private synchronized void internalDeactivateTopology( Topology topology ) {
log.deactivatingTopology( topology.getName() );
+ addInactiveTopology(topology.getName());
+
String topoName = topology.getName();
String topoPath = "/" + Urls.trimLeadingAndTrailingSlashJoin(
config.getGatewayPath(), topoName );
String topoPathSlash = topoPath + "/";
@@ -1026,6 +1078,10 @@ public class GatewayServer {
auditor.audit(Action.UNDEPLOY, topology.getName(),
ResourceType.TOPOLOGY,
ActionOutcome.UNAVAILABLE);
internalDeactivateTopology( topology );
+
+ // Since it is being deleted, then no longer consider it as only
inactive
+ removeInactiveTopology(topology.getName());
+
for( File file : files ) {
log.deletingDeployment( file.getAbsolutePath() );
FileUtils.deleteQuietly( file );
@@ -1164,4 +1220,30 @@ public class GatewayServer {
return Long.compare(rightTime, leftTime);
}
}
+
+ /**
+ * Jetty ErrorHandler extension for handling 404 responses when topologies
are inactive.
+ */
+ private static class Http404ErrorHandler extends ErrorHandler {
+ private final GatewayServer gs;
+ private final String gatewayPath;
+
+ Http404ErrorHandler(final GatewayServer gs, final String gatewayPath) {
+ this.gs = gs;
+ this.gatewayPath = gatewayPath;
+ }
+
+ @Override
+ public void doError(String target, Request baseRequest, HttpServletRequest
request, HttpServletResponse response) throws IOException {
+ final int gatewayPrefixLength = ("/" + gatewayPath + "/").length();
+ String pathInfo = baseRequest.getPathInfo();
+ String topologyName = pathInfo.substring(gatewayPrefixLength,
pathInfo.indexOf('/', gatewayPrefixLength));
+ if (gs.isInactiveTopology(topologyName) && (response.getStatus() ==
HttpServletResponse.SC_NOT_FOUND)) {
+ request.setAttribute("javax.servlet.error.message", "Service
Unavailable"); // The default ErrorHandler references this attribute
+ response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ }
+ super.doError(target, baseRequest, request, response);
+ }
+ }
+
}