This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new 00729a9593 [SONAR] cleanup some security warnings and hardening (#6837)
00729a9593 is described below
commit 00729a95933c7681db630eb698b428b31c03cc2c
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Thu Mar 19 20:32:09 2026 +0100
[SONAR] cleanup some security warnings and hardening (#6837)
Add deprecation to some endpoints
cleanup and jetty fix
---
docker/integration-tests/unit-tests.Dockerfile | 1 -
.../modules/ROOT/pages/hop-server/rest-api.adoc | 34 ++++-
engine/pom.xml | 8 +-
.../java/org/apache/hop/www/AddExportServlet.java | 12 +-
.../org/apache/hop/www/AddPipelineServlet.java | 18 ++-
.../org/apache/hop/www/AddWorkflowServlet.java | 20 ++-
.../org/apache/hop/www/BaseHopServerPlugin.java | 18 +--
.../java/org/apache/hop/www/BaseHttpServlet.java | 147 ++++++++++++---------
.../java/org/apache/hop/www/BodyHttpServlet.java | 14 +-
.../apache/hop/www/DeleteExecutionInfoServlet.java | 18 ++-
.../org/apache/hop/www/ExecPipelineServlet.java | 55 +++++---
.../org/apache/hop/www/ExecWorkflowServlet.java | 55 +++++---
.../apache/hop/www/GetExecutionInfoServlet.java | 5 +-
.../apache/hop/www/GetPipelineStatusServlet.java | 22 ++-
.../java/org/apache/hop/www/GetRootServlet.java | 5 +-
.../java/org/apache/hop/www/GetStatusServlet.java | 16 +--
.../apache/hop/www/GetWorkflowStatusServlet.java | 21 ++-
.../java/org/apache/hop/www/HopServerServlet.java | 21 ++-
.../org/apache/hop/www/PausePipelineServlet.java | 22 ++-
.../hop/www/PrepareExecutionPipelineServlet.java | 68 ++++++----
.../hop/www/RegisterExecutionInfoServlet.java | 10 +-
.../org/apache/hop/www/RemovePipelineServlet.java | 31 ++---
.../org/apache/hop/www/RemoveWorkflowServlet.java | 29 ++--
.../org/apache/hop/www/SniffTransformServlet.java | 86 ++++++++----
.../hop/www/StartExecutionPipelineServlet.java | 42 ++++--
.../org/apache/hop/www/StartPipelineServlet.java | 33 +++--
.../org/apache/hop/www/StartWorkflowServlet.java | 34 +++--
.../org/apache/hop/www/StopPipelineServlet.java | 17 ++-
.../org/apache/hop/www/StopWorkflowServlet.java | 19 ++-
.../main/java/org/apache/hop/www/WebResult.java | 10 ++
.../main/java/org/apache/hop/www/WebServer.java | 2 +-
.../java/org/apache/hop/www/WebServiceServlet.java | 10 +-
lib/pom.xml | 36 ++++-
plugins/engines/beam/src/assembly/assembly.xml | 1 +
.../apache/hop/metadata/rest/RestConnection.java | 4 +-
plugins/tech/google/pom.xml | 2 -
pom.xml | 34 +++++
37 files changed, 663 insertions(+), 317 deletions(-)
diff --git a/docker/integration-tests/unit-tests.Dockerfile
b/docker/integration-tests/unit-tests.Dockerfile
index dad75bdb1e..c33853b125 100644
--- a/docker/integration-tests/unit-tests.Dockerfile
+++ b/docker/integration-tests/unit-tests.Dockerfile
@@ -90,7 +90,6 @@ RUN chown -R ${JENKINS_USER}:${JENKINS_GROUP}
${DEPLOYMENT_PATH}/hop \
# Download Additional drivers/dependencies
ADD --chown=${JENKINS_USER}:${JENKINS_GROUP}
https://repo1.maven.org/maven2/com/vertica/jdbc/vertica-jdbc/23.4.0-0/vertica-jdbc-23.4.0-0.jar
/opt/hop/lib/jdbc/vertica-jdbc-23.4.0-0.jar
ADD --chown=${JENKINS_USER}:${JENKINS_GROUP}
https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/9.2.0/mysql-connector-j-9.2.0.jar
/opt/hop/lib/jdbc/mysql-connector-j-9.2.0.jar
-ADD --chown=${JENKINS_USER}:${JENKINS_GROUP}
https://repo1.maven.org/maven2/org/openjdk/nashorn/nashorn-core/15.4/nashorn-core-15.4.jar
/opt/hop/plugins/transforms/script/lib/nashorn-core-15.4.jar
# make volume available so that hop pipeline and workflow files can be
provided easily
VOLUME ["/files"]
diff --git a/docs/hop-user-manual/modules/ROOT/pages/hop-server/rest-api.adoc
b/docs/hop-user-manual/modules/ROOT/pages/hop-server/rest-api.adoc
index d5a7362f9a..72c5b658e8 100644
--- a/docs/hop-user-manual/modules/ROOT/pages/hop-server/rest-api.adoc
+++ b/docs/hop-user-manual/modules/ROOT/pages/hop-server/rest-api.adoc
@@ -24,7 +24,14 @@ Hop Server has a rich set of web services that can be used
to query and manage t
TIP: when specified, the id for a workflow or pipeline represents one
execution of a workflow or pipeline on the server.
-== addExport
+== addExport _(deprecated)_
+
+[WARNING]
+====
+*Deprecated since 2.18.0.* Use `registerPackage` (`hop/registerPackage`)
instead.
+The remote pipeline and workflow engines call `registerPackage` for all export
operations.
+This endpoint will be removed in a future release.
+====
name::
addExport
@@ -32,6 +39,7 @@ addExport
description::
Upload a resources export file.
Add a zipped pipeline or workflow to the body payload as a binary file.
+*Deprecated* — use `registerPackage` instead.
endPoint::
GET `hop/addExport`
@@ -56,13 +64,20 @@ A zip file with the export is created on the server's file
system.
</webresult>
----
-== addPipeline
+== addPipeline _(deprecated)_
+
+[WARNING]
+====
+*Deprecated since 2.18.0.* Use <<Register Pipeline,`registerPipeline`>>
(`hop/registerPipeline`) instead.
+This endpoint is no longer used by the remote pipeline engine and will be
removed in a future release.
+====
name::
addPipeline
description::
-Add a pipeline for execution
+Add a pipeline for execution.
+*Deprecated* — use `registerPipeline` instead.
endPoint::
GET `hop/addPipeline`
@@ -75,15 +90,22 @@ example request::
`+http://localhost:8081/hop/addPipeline/xml=Y+` with XML payload
result::
--
+-
+
+== addWorkflow _(deprecated)_
-== addWorkflow
+[WARNING]
+====
+*Deprecated since 2.18.0.* Use <<Register Workflow,`registerWorkflow`>>
(`hop/registerWorkflow`) instead.
+This endpoint is no longer used by the remote workflow engine and will be
removed in a future release.
+====
name::
addWorkflow
description::
-Add a workflow for execution
+Add a workflow for execution.
+*Deprecated* — use `registerWorkflow` instead.
endPoint::
GET `hop/addWorkflow`
diff --git a/engine/pom.xml b/engine/pom.xml
index f5bad594c8..1633115e2b 100644
--- a/engine/pom.xml
+++ b/engine/pom.xml
@@ -120,10 +120,6 @@
</exclusion>
</exclusions>
</dependency>
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-jaas</artifactId>
- </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
@@ -199,6 +195,10 @@
</exclusion>
</exclusions>
</dependency>
+ <dependency>
+ <groupId>org.jspecify</groupId>
+ <artifactId>jspecify</artifactId>
+ </dependency>
<dependency>
<groupId>org.mozilla</groupId>
<artifactId>rhino-all</artifactId>
diff --git a/engine/src/main/java/org/apache/hop/www/AddExportServlet.java
b/engine/src/main/java/org/apache/hop/www/AddExportServlet.java
index 94fe726c3b..2f20374d71 100644
--- a/engine/src/main/java/org/apache/hop/www/AddExportServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/AddExportServlet.java
@@ -56,8 +56,13 @@ import org.w3c.dom.Document;
* a zip file. It ends up in a temporary file.
*
* <p>The servlet returns the name of the file stored.
+ *
+ * @deprecated Use {@link RegisterPackageServlet} ({@code
/hop/registerPackage}) instead. The remote
+ * pipeline and workflow engines call {@code registerPackage} for all
export operations. This
+ * endpoint will be removed in a future release.
*/
-@HopServerServlet(id = "addExport", name = "Upload a resources export file")
+@Deprecated(since = "2.18.0")
+@HopServerServlet(id = "addExport", name = "Upload a resources export file
(deprecated)")
public class AddExportServlet extends BaseHttpServlet implements
IHopServerPlugin {
public static final String PARAMETER_LOAD = "load";
public static final String PARAMETER_TYPE = "type";
@@ -84,7 +89,10 @@ public class AddExportServlet extends BaseHttpServlet
implements IHopServerPlugi
logDebug("Addition of export requested");
}
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
InputStream in = request.getInputStream(); // read from the client
if (log.isDetailed()) {
logDetailed("Encoding: " + request.getCharacterEncoding());
diff --git a/engine/src/main/java/org/apache/hop/www/AddPipelineServlet.java
b/engine/src/main/java/org/apache/hop/www/AddPipelineServlet.java
index 343d404df0..988599f3fa 100644
--- a/engine/src/main/java/org/apache/hop/www/AddPipelineServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/AddPipelineServlet.java
@@ -42,7 +42,13 @@ import org.apache.hop.pipeline.PipelineMeta;
import org.apache.hop.pipeline.engine.IPipelineEngine;
import org.apache.hop.pipeline.engine.PipelineEngineFactory;
-@HopServerServlet(id = "addPipeline", name = "Add a pipeline for execution")
+/**
+ * @deprecated Use {@link RegisterPipelineServlet} ({@code
/hop/registerPipeline}) instead. This
+ * endpoint is no longer called by the remote pipeline engine and will be
removed in a future
+ * release.
+ */
+@Deprecated(since = "2.18.0")
+@HopServerServlet(id = "addPipeline", name = "Add a pipeline for execution
(deprecated)")
public class AddPipelineServlet extends BaseHttpServlet implements
IHopServerPlugin {
@Serial private static final long serialVersionUID = -6850701762586992604L;
@@ -67,8 +73,14 @@ public class AddPipelineServlet extends BaseHttpServlet
implements IHopServerPlu
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
- PrintWriter out = response.getWriter();
- BufferedReader in = request.getReader();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
+ BufferedReader in = getSafeReader(request, response);
+ if (in == null) {
+ return;
+ }
if (log.isDetailed()) {
logDetailed("Encoding: " + request.getCharacterEncoding());
}
diff --git a/engine/src/main/java/org/apache/hop/www/AddWorkflowServlet.java
b/engine/src/main/java/org/apache/hop/www/AddWorkflowServlet.java
index b8a7d8d474..12ceb0ebd2 100644
--- a/engine/src/main/java/org/apache/hop/www/AddWorkflowServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/AddWorkflowServlet.java
@@ -42,7 +42,13 @@ import org.apache.hop.workflow.action.ActionMeta;
import org.apache.hop.workflow.engine.IWorkflowEngine;
import org.apache.hop.workflow.engine.WorkflowEngineFactory;
-@HopServerServlet(id = "addWorkflow", name = "Add a workflow to the server")
+/**
+ * @deprecated Use {@link RegisterWorkflowServlet} ({@code
/hop/registerWorkflow}) instead. This
+ * endpoint is no longer called by the remote workflow engine and will be
removed in a future
+ * release.
+ */
+@Deprecated(since = "2.18.0")
+@HopServerServlet(id = "addWorkflow", name = "Add a workflow to the server
(deprecated)")
public class AddWorkflowServlet extends BaseHttpServlet implements
IHopServerPlugin {
@Serial private static final long serialVersionUID = -6850701762586992604L;
@@ -67,8 +73,14 @@ public class AddWorkflowServlet extends BaseHttpServlet
implements IHopServerPlu
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
- PrintWriter out = response.getWriter();
- BufferedReader in = request.getReader(); // read from the client
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
+ BufferedReader in = getSafeReader(request, response);
+ if (in == null) {
+ return;
+ }
if (log.isDetailed()) {
logDetailed("Encoding: " + request.getCharacterEncoding());
}
@@ -196,7 +208,7 @@ public class AddWorkflowServlet extends BaseHttpServlet
implements IHopServerPlu
protected String[] getAllArgumentStrings(Map<String, String> arguments) {
if (Utils.isEmpty(arguments)) {
- return null;
+ return new String[0];
}
String[] argNames = arguments.keySet().toArray(new
String[arguments.size()]);
diff --git a/engine/src/main/java/org/apache/hop/www/BaseHopServerPlugin.java
b/engine/src/main/java/org/apache/hop/www/BaseHopServerPlugin.java
index 1dacab357b..d1a95c954b 100644
--- a/engine/src/main/java/org/apache/hop/www/BaseHopServerPlugin.java
+++ b/engine/src/main/java/org/apache/hop/www/BaseHopServerPlugin.java
@@ -19,6 +19,7 @@ package org.apache.hop.www;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMultimap;
+import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@@ -40,8 +41,15 @@ public abstract class BaseHopServerPlugin extends
BaseHttpServlet
*/
@Deprecated(since = "2.0")
@Override
- public void doGet(HttpServletRequest req, final HttpServletResponse resp)
throws IOException {
- service(req, resp);
+ public void doGet(HttpServletRequest req, final HttpServletResponse resp)
+ throws ServletException, IOException {
+ try {
+ service(req, resp);
+ } catch (IOException e) {
+ logError("I/O error servicing request for " + getContextPath(), e);
+ sendSafeError(
+ resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to
process server request.");
+ }
}
@Override
@@ -57,12 +65,6 @@ public abstract class BaseHopServerPlugin extends
BaseHttpServlet
handleRequest(new HopServerRequestImpl(req, resp));
}
- @Override
- public abstract void handleRequest(IHopServerRequest request) throws
IOException;
-
- @Override
- public abstract String getContextPath();
-
@Override
public String getService() {
return getContextPath() + " (" + toString() + ")";
diff --git a/engine/src/main/java/org/apache/hop/www/BaseHttpServlet.java
b/engine/src/main/java/org/apache/hop/www/BaseHttpServlet.java
index c8a840ac66..913b0f8b25 100644
--- a/engine/src/main/java/org/apache/hop/www/BaseHttpServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/BaseHttpServlet.java
@@ -21,8 +21,12 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
+import java.io.BufferedReader;
import java.io.IOException;
+import java.io.PrintWriter;
import java.io.Serial;
+import lombok.Getter;
+import lombok.Setter;
import org.apache.hop.core.Const;
import org.apache.hop.core.logging.ILogChannel;
import org.apache.hop.core.logging.LogChannel;
@@ -33,15 +37,17 @@ import org.apache.http.entity.ContentType;
public class BaseHttpServlet extends HttpServlet {
@Serial protected static final long serialVersionUID = -1348342810327662788L;
- protected PipelineMap pipelineMap;
- protected WorkflowMap workflowMap;
- protected HopServerConfig serverConfig;
+ @Setter @Getter protected PipelineMap pipelineMap;
+
+ @Setter @Getter protected WorkflowMap workflowMap;
+
+ @Setter @Getter protected HopServerConfig serverConfig;
protected IVariables variables;
protected boolean supportGraphicEnvironment;
- private boolean jettyMode = false;
+ @Setter @Getter private boolean jettyMode = false;
- protected ILogChannel log = new LogChannel("Servlet");
+ @Setter @Getter protected ILogChannel log = new LogChannel("Servlet");
public String convertContextPath(String contextPath) {
if (jettyMode) {
@@ -105,19 +111,90 @@ public class BaseHttpServlet extends HttpServlet {
@Override
protected void doPut(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException {
- doGet(request, response);
+ try {
+ doGet(request, response);
+ } catch (Exception e) {
+ logError("Error handling PUT request", e);
+ sendSafeError(
+ response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to
process PUT request.");
+ }
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException {
- doGet(request, response);
+ try {
+ doGet(request, response);
+ } catch (Exception e) {
+ logError("Error handling POST request", e);
+ sendSafeError(
+ response,
+ HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+ "Unable to process POST request.");
+ }
}
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
- doGet(req, resp);
+ try {
+ doGet(req, resp);
+ } catch (Exception e) {
+ logError("Error handling DELETE request", e);
+ sendSafeError(
+ resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to
process DELETE request.");
+ }
+ }
+
+ protected boolean isJsonRequest(HttpServletRequest request) {
+ return "Y".equalsIgnoreCase(request.getParameter("json"));
+ }
+
+ protected void setResponseFormat(HttpServletResponse response, boolean
useXml, boolean useJson) {
+ if (useXml) {
+ response.setContentType("text/xml");
+ response.setCharacterEncoding(Const.XML_ENCODING);
+ } else if (useJson) {
+ response.setContentType("application/json");
+ response.setCharacterEncoding(Const.XML_ENCODING);
+ } else {
+ response.setContentType("text/html;charset=UTF-8");
+ }
+ }
+
+ protected PrintWriter getSafeWriter(HttpServletResponse response) {
+ try {
+ return response.getWriter();
+ } catch (IOException e) {
+ log.logError("Failed to obtain response writer", e);
+ sendSafeError(
+ response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to
process request.");
+ return null;
+ }
+ }
+
+ protected BufferedReader getSafeReader(HttpServletRequest request,
HttpServletResponse response) {
+ try {
+ return request.getReader();
+ } catch (IOException e) {
+ log.logError("Failed to obtain request reader", e);
+ sendSafeError(
+ response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to
process request.");
+ return null;
+ }
+ }
+
+ protected void sendSafeError(HttpServletResponse response, int status,
String message) {
+ if (response.isCommitted()) {
+ response.setStatus(status);
+ return;
+ }
+ try {
+ response.sendError(status, message);
+ } catch (IOException e) {
+ log.logError("Failed to send error response (" + status + "): " +
message, e);
+ response.setStatus(status);
+ }
}
public PipelineMap getPipelineMap() {
@@ -134,14 +211,6 @@ public class BaseHttpServlet extends HttpServlet {
return workflowMap;
}
- public boolean isJettyMode() {
- return jettyMode;
- }
-
- public void setJettyMode(boolean jettyMode) {
- this.jettyMode = jettyMode;
- }
-
public void logMinimal(String s) {
log.logMinimal(s);
}
@@ -189,52 +258,6 @@ public class BaseHttpServlet extends HttpServlet {
this.variables = serverConfig.getVariables();
}
- /**
- * @param pipelineMap The pipelineMap to set
- */
- public void setPipelineMap(PipelineMap pipelineMap) {
- this.pipelineMap = pipelineMap;
- }
-
- /**
- * @param workflowMap The workflowMap to set
- */
- public void setWorkflowMap(WorkflowMap workflowMap) {
- this.workflowMap = workflowMap;
- }
-
- /**
- * Gets serverConfig
- *
- * @return value of serverConfig
- */
- public HopServerConfig getServerConfig() {
- return serverConfig;
- }
-
- /**
- * @param serverConfig The serverConfig to set
- */
- public void setServerConfig(HopServerConfig serverConfig) {
- this.serverConfig = serverConfig;
- }
-
- /**
- * Gets log
- *
- * @return value of log
- */
- public ILogChannel getLog() {
- return log;
- }
-
- /**
- * @param log The log to set
- */
- public void setLog(ILogChannel log) {
- this.log = log;
- }
-
private String getContentEncoding(String contentTypeValue) {
ContentType contentType = ContentType.parse(contentTypeValue);
if ("text/xml".equals(contentType.getMimeType())) {
diff --git a/engine/src/main/java/org/apache/hop/www/BodyHttpServlet.java
b/engine/src/main/java/org/apache/hop/www/BodyHttpServlet.java
index 09c24c397b..0e54a97207 100644
--- a/engine/src/main/java/org/apache/hop/www/BodyHttpServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/BodyHttpServlet.java
@@ -52,32 +52,42 @@ public abstract class BodyHttpServlet extends
BaseHttpServlet implements IHopSer
}
boolean useXML = useXML(request);
+ boolean useJson = isJsonRequest(request);
PrintWriter out = new PrintWriter(response.getOutputStream());
try {
if (useXML) {
startXml(response, out);
+ } else if (useJson) {
+ response.setContentType("application/json");
+ response.setCharacterEncoding(Const.XML_ENCODING);
} else {
beginHtml(response, out);
}
WebResult result = generateBody(request, response, useXML, variables);
if (result != null) {
- out.println(result.getXml());
+ if (useJson) {
+ out.println(result.getJson());
+ } else {
+ out.println(result.getXml());
+ }
}
} catch (Exception e) {
String st = ExceptionUtils.getFullStackTrace(e);
if (useXML) {
out.println(new WebResult(WebResult.STRING_ERROR, st).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR, st).getJson());
} else {
out.println("<p><pre>");
out.println(Encode.forHtml(st));
out.println("</pre>");
}
} finally {
- if (!useXML) {
+ if (!useXML && !useJson) {
endHtml(out);
}
out.flush();
diff --git
a/engine/src/main/java/org/apache/hop/www/DeleteExecutionInfoServlet.java
b/engine/src/main/java/org/apache/hop/www/DeleteExecutionInfoServlet.java
index b2e7784dbc..07edd37eea 100644
--- a/engine/src/main/java/org/apache/hop/www/DeleteExecutionInfoServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/DeleteExecutionInfoServlet.java
@@ -34,7 +34,13 @@ import org.apache.hop.execution.ExecutionInfoLocation;
import org.apache.hop.metadata.api.IHopMetadataSerializer;
import org.apache.hop.metadata.serializer.multi.MultiMetadataProvider;
-@HopServerServlet(id = "registerExecInfo", name = "Register execution
information")
+/**
+ * @deprecated Execution deletion is now handled by {@link
GetExecutionInfoServlet} ({@code
+ * /hop/getExecInfo}) via its {@code DELETE} type parameter. This endpoint
has no callers in the
+ * application and will be removed in a future release.
+ */
+@Deprecated(since = "2.18.0")
+@HopServerServlet(id = "deleteExecInfo", name = "Delete execution information
(deprecated)")
public class DeleteExecutionInfoServlet extends BaseHttpServlet implements
IHopServerPlugin {
@Serial private static final long serialVersionUID = -1901302231769020201L;
@@ -67,8 +73,14 @@ public class DeleteExecutionInfoServlet extends
BaseHttpServlet implements IHopS
//
String locationName =
StringEscapeUtils.escapeHtml(request.getParameter(PARAMETER_LOCATION));
- PrintWriter out = response.getWriter();
- BufferedReader in = request.getReader();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
+ BufferedReader in = getSafeReader(request, response);
+ if (in == null) {
+ return;
+ }
response.setContentType("text/xml");
out.print(XmlHandler.getXmlHeader());
diff --git a/engine/src/main/java/org/apache/hop/www/ExecPipelineServlet.java
b/engine/src/main/java/org/apache/hop/www/ExecPipelineServlet.java
index 669da1782e..05cf7075f2 100644
--- a/engine/src/main/java/org/apache/hop/www/ExecPipelineServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/ExecPipelineServlet.java
@@ -42,6 +42,7 @@ import org.apache.hop.pipeline.PipelineMeta;
import org.apache.hop.pipeline.config.PipelineRunConfiguration;
import org.apache.hop.pipeline.engine.IPipelineEngine;
import org.apache.hop.pipeline.engine.PipelineEngineFactory;
+import org.owasp.encoder.Encode;
@HopServerServlet(id = "execPipeline", name = "Execute pipeline from file
path")
public class ExecPipelineServlet extends BaseHttpServlet implements
IHopServerPlugin {
@@ -97,23 +98,34 @@ public class ExecPipelineServlet extends BaseHttpServlet
implements IHopServerPl
String levelOption = request.getParameter(LEVEL);
String runConfigOption = request.getParameter(RUN_CONFIG);
+ boolean useJson = isJsonRequest(request);
+
response.setStatus(HttpServletResponse.SC_OK);
- String encoding = System.getProperty("HOP_DEFAULT_SERVLET_ENCODING", null);
- if (encoding != null && !Utils.isEmpty(encoding.trim())) {
- response.setCharacterEncoding(encoding);
- response.setContentType("text/html; charset=" + encoding);
- } else {
- response.setContentType("text/xml");
+ if (useJson) {
+ response.setContentType("application/json");
response.setCharacterEncoding(Const.XML_ENCODING);
+ } else {
+ String encoding = System.getProperty("HOP_DEFAULT_SERVLET_ENCODING",
null);
+ if (encoding != null && !Utils.isEmpty(encoding.trim())) {
+ response.setCharacterEncoding(encoding);
+ response.setContentType("text/html; charset=" + encoding);
+ } else {
+ response.setContentType("text/xml");
+ response.setCharacterEncoding(Const.XML_ENCODING);
+ }
}
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
if (pipelineOption == null) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
- out.println(
- new WebResult(WebResult.STRING_ERROR, "Missing mandatory parameter:
" + PIPELINE));
+ WebResult missing =
+ new WebResult(WebResult.STRING_ERROR, "Missing mandatory parameter:
" + PIPELINE);
+ out.println(useJson ? missing.getJson() : missing.getXml());
return;
}
@@ -229,30 +241,39 @@ public class ExecPipelineServlet extends BaseHttpServlet
implements IHopServerPl
// Check for errors
if (pipeline.isFinished() && pipeline.getErrors() > 0) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- out.println(new WebResult(WebResult.STRING_ERROR, "Error executing
pipeline: " + logging));
+ WebResult err =
+ new WebResult(WebResult.STRING_ERROR, "Error executing pipeline: "
+ logging);
+ out.println(useJson ? err.getJson() : err.getXml());
} else {
- out.println(new WebResult(WebResult.STRING_OK, "Pipeline executed
successfully"));
+ WebResult ok = new WebResult(WebResult.STRING_OK, "Pipeline executed
successfully");
+ out.println(useJson ? ok.getJson() : ok.getXml());
}
out.flush();
} catch (Exception ex) {
if (ex.getMessage() != null &&
ex.getMessage().contains(UNABLE_TO_FIND_PIPELINE)) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
- out.println(
+ String safePipelineOption =
+ pipelineOption != null ? Encode.forHtml(pipelineOption) : "null";
+ String safeResolved =
+ pipelineOption != null ?
Encode.forHtml(variables.resolve(pipelineOption)) : "null";
+ WebResult notFound =
new WebResult(
WebResult.STRING_ERROR,
"Unable to find pipeline: "
- + pipelineOption
+ + safePipelineOption
+ " (resolved: "
- + (pipelineOption != null ?
variables.resolve(pipelineOption) : "null")
- + ")"));
+ + safeResolved
+ + ")");
+ out.println(useJson ? notFound.getJson() : notFound.getXml());
} else {
String logging = Const.getStackTracker(ex);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- out.println(
+ WebResult err =
new WebResult(
WebResult.STRING_ERROR,
- "Unexpected error executing pipeline: " + Const.CR + logging));
+ "Unexpected error executing pipeline: " + Const.CR + logging);
+ out.println(useJson ? err.getJson() : err.getXml());
}
}
}
diff --git a/engine/src/main/java/org/apache/hop/www/ExecWorkflowServlet.java
b/engine/src/main/java/org/apache/hop/www/ExecWorkflowServlet.java
index 8a24f81d08..cdd24d784e 100644
--- a/engine/src/main/java/org/apache/hop/www/ExecWorkflowServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/ExecWorkflowServlet.java
@@ -42,6 +42,7 @@ import org.apache.hop.workflow.WorkflowMeta;
import org.apache.hop.workflow.config.WorkflowRunConfiguration;
import org.apache.hop.workflow.engine.IWorkflowEngine;
import org.apache.hop.workflow.engine.WorkflowEngineFactory;
+import org.owasp.encoder.Encode;
@HopServerServlet(id = "execWorkflow", name = "Execute workflow from file
path")
public class ExecWorkflowServlet extends BaseHttpServlet implements
IHopServerPlugin {
@@ -97,23 +98,34 @@ public class ExecWorkflowServlet extends BaseHttpServlet
implements IHopServerPl
String levelOption = request.getParameter(LEVEL);
String runConfigOption = request.getParameter(RUN_CONFIG);
+ boolean useJson = isJsonRequest(request);
+
response.setStatus(HttpServletResponse.SC_OK);
- String encoding = System.getProperty("HOP_DEFAULT_SERVLET_ENCODING", null);
- if (encoding != null && !Utils.isEmpty(encoding.trim())) {
- response.setCharacterEncoding(encoding);
- response.setContentType("text/html; charset=" + encoding);
- } else {
- response.setContentType("text/xml");
+ if (useJson) {
+ response.setContentType("application/json");
response.setCharacterEncoding(Const.XML_ENCODING);
+ } else {
+ String encoding = System.getProperty("HOP_DEFAULT_SERVLET_ENCODING",
null);
+ if (encoding != null && !Utils.isEmpty(encoding.trim())) {
+ response.setCharacterEncoding(encoding);
+ response.setContentType("text/html; charset=" + encoding);
+ } else {
+ response.setContentType("text/xml");
+ response.setCharacterEncoding(Const.XML_ENCODING);
+ }
}
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
if (workflowOption == null) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
- out.println(
- new WebResult(WebResult.STRING_ERROR, "Missing mandatory parameter:
" + WORKFLOW));
+ WebResult missing =
+ new WebResult(WebResult.STRING_ERROR, "Missing mandatory parameter:
" + WORKFLOW);
+ out.println(useJson ? missing.getJson() : missing.getXml());
return;
}
@@ -227,30 +239,39 @@ public class ExecWorkflowServlet extends BaseHttpServlet
implements IHopServerPl
Result result = workflow.getResult();
if (workflow.isFinished() && (result == null || result.getNrErrors() >
0)) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- out.println(new WebResult(WebResult.STRING_ERROR, "Error executing
workflow: " + logging));
+ WebResult err =
+ new WebResult(WebResult.STRING_ERROR, "Error executing workflow: "
+ logging);
+ out.println(useJson ? err.getJson() : err.getXml());
} else {
- out.println(new WebResult(WebResult.STRING_OK, "Workflow executed
successfully"));
+ WebResult ok = new WebResult(WebResult.STRING_OK, "Workflow executed
successfully");
+ out.println(useJson ? ok.getJson() : ok.getXml());
}
out.flush();
} catch (Exception ex) {
if (ex.getMessage() != null &&
ex.getMessage().contains(UNABLE_TO_FIND_WORKFLOW)) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
- out.println(
+ String safeWorkflowOption =
+ workflowOption != null ? Encode.forHtml(workflowOption) : "null";
+ String safeResolved =
+ workflowOption != null ?
Encode.forHtml(variables.resolve(workflowOption)) : "null";
+ WebResult notFound =
new WebResult(
WebResult.STRING_ERROR,
"Unable to find workflow: "
- + workflowOption
+ + safeWorkflowOption
+ " (resolved: "
- + (workflowOption != null ?
variables.resolve(workflowOption) : "null")
- + ")"));
+ + safeResolved
+ + ")");
+ out.println(useJson ? notFound.getJson() : notFound.getXml());
} else {
String logging = Const.getStackTracker(ex);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- out.println(
+ WebResult err =
new WebResult(
WebResult.STRING_ERROR,
- "Unexpected error executing workflow: " + Const.CR + logging));
+ "Unexpected error executing workflow: " + Const.CR + logging);
+ out.println(useJson ? err.getJson() : err.getXml());
}
}
}
diff --git
a/engine/src/main/java/org/apache/hop/www/GetExecutionInfoServlet.java
b/engine/src/main/java/org/apache/hop/www/GetExecutionInfoServlet.java
index 019475357e..396e6733b9 100644
--- a/engine/src/main/java/org/apache/hop/www/GetExecutionInfoServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/GetExecutionInfoServlet.java
@@ -91,7 +91,10 @@ public class GetExecutionInfoServlet extends BaseHttpServlet
implements IHopServ
response.setContentType("application/json");
response.setCharacterEncoding(Const.XML_ENCODING);
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
// The type of information to request
//
diff --git
a/engine/src/main/java/org/apache/hop/www/GetPipelineStatusServlet.java
b/engine/src/main/java/org/apache/hop/www/GetPipelineStatusServlet.java
index d6b28001b3..61ffdddd11 100644
--- a/engine/src/main/java/org/apache/hop/www/GetPipelineStatusServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/GetPipelineStatusServlet.java
@@ -101,17 +101,7 @@ public class GetPipelineStatusServlet extends
BaseHttpServlet implements IHopSer
response.setStatus(HttpServletResponse.SC_OK);
- if (useXml) {
- response.setContentType("text/xml");
- response.setCharacterEncoding(Const.XML_ENCODING);
- }
- if (useJson) {
- response.setContentType("application/json");
- response.setCharacterEncoding(Const.XML_ENCODING);
- } else {
- response.setCharacterEncoding("UTF-8");
- response.setContentType("text/html;charset=UTF-8");
- }
+ setResponseFormat(response, useXml, useJson);
// ID is optional...
//
@@ -201,7 +191,10 @@ public class GetPipelineStatusServlet extends
BaseHttpServlet implements IHopSer
throw new ServletException("Unable to get the pipeline status in XML
or JSON format", e);
}
} else {
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
int lastLineNr = HopLogStore.getLastBufferLineNr();
int tableBorder = 0;
@@ -578,7 +571,10 @@ public class GetPipelineStatusServlet extends
BaseHttpServlet implements IHopSer
out.println("</HTML>");
}
} else {
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
if (useXml) {
out.println(
new WebResult(
diff --git a/engine/src/main/java/org/apache/hop/www/GetRootServlet.java
b/engine/src/main/java/org/apache/hop/www/GetRootServlet.java
index e9c2cfe8a1..47e5d70c0c 100644
--- a/engine/src/main/java/org/apache/hop/www/GetRootServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/GetRootServlet.java
@@ -49,7 +49,10 @@ public class GetRootServlet extends BaseHttpServlet
implements IHopServerPlugin
response.setContentType("text/html;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
out.println("<HTML>");
out.println(
diff --git a/engine/src/main/java/org/apache/hop/www/GetStatusServlet.java
b/engine/src/main/java/org/apache/hop/www/GetStatusServlet.java
index 3a96ea76de..d774013db6 100644
--- a/engine/src/main/java/org/apache/hop/www/GetStatusServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/GetStatusServlet.java
@@ -106,18 +106,12 @@ public class GetStatusServlet extends BaseHttpServlet
implements IHopServerPlugi
boolean useJson = "Y".equalsIgnoreCase(request.getParameter("json"));
boolean useLightTheme =
"Y".equalsIgnoreCase(request.getParameter("useLightTheme"));
- if (useXml) {
- response.setContentType("text/xml");
- response.setCharacterEncoding(Const.XML_ENCODING);
- }
- if (useJson) {
- response.setContentType("application/json");
- response.setCharacterEncoding(Const.XML_ENCODING);
- } else {
- response.setContentType("text/html;charset=UTF-8");
- }
+ setResponseFormat(response, useXml, useJson);
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
List<HopServerObjectEntry> pipelineEntries =
getPipelineMap().getPipelineObjects();
List<HopServerObjectEntry> actions = getWorkflowMap().getWorkflowObjects();
diff --git
a/engine/src/main/java/org/apache/hop/www/GetWorkflowStatusServlet.java
b/engine/src/main/java/org/apache/hop/www/GetWorkflowStatusServlet.java
index bf8b47e227..ec3a5c2985 100644
--- a/engine/src/main/java/org/apache/hop/www/GetWorkflowStatusServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/GetWorkflowStatusServlet.java
@@ -92,16 +92,7 @@ public class GetWorkflowStatusServlet extends
BaseHttpServlet implements IHopSer
response.setStatus(HttpServletResponse.SC_OK);
- if (useXml) {
- response.setContentType("text/xml");
- response.setCharacterEncoding(Const.XML_ENCODING);
- }
- if (useJson) {
- response.setContentType("application/json");
- response.setCharacterEncoding(Const.XML_ENCODING);
- } else {
- response.setContentType("text/html;charset=UTF-8");
- }
+ setResponseFormat(response, useXml, useJson);
// ID is optional...
//
@@ -206,7 +197,10 @@ public class GetWorkflowStatusServlet extends
BaseHttpServlet implements IHopSer
}
} else {
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
int lastLineNr = HopLogStore.getLastBufferLineNr();
int tableBorder = 0;
@@ -436,7 +430,10 @@ public class GetWorkflowStatusServlet extends
BaseHttpServlet implements IHopSer
out.println("</HTML>");
}
} else {
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
if (useXml) {
out.println(
new WebResult(
diff --git a/engine/src/main/java/org/apache/hop/www/HopServerServlet.java
b/engine/src/main/java/org/apache/hop/www/HopServerServlet.java
index bc569032b2..ee44a0e646 100644
--- a/engine/src/main/java/org/apache/hop/www/HopServerServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/HopServerServlet.java
@@ -53,7 +53,26 @@ public class HopServerServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
- doGet(req, resp);
+ try {
+ doGet(req, resp);
+ } catch (Exception e) {
+ log.logError("Error handling HopServer POST request", e);
+ sendSafeError(
+ resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to
process server request.");
+ }
+ }
+
+ private void sendSafeError(HttpServletResponse response, int status, String
message) {
+ if (response.isCommitted()) {
+ response.setStatus(status);
+ return;
+ }
+ try {
+ response.sendError(status, message);
+ } catch (IOException e) {
+ log.logError("Failed to send error response (" + status + "): " +
message, e);
+ response.setStatus(status);
+ }
}
@Override
diff --git a/engine/src/main/java/org/apache/hop/www/PausePipelineServlet.java
b/engine/src/main/java/org/apache/hop/www/PausePipelineServlet.java
index cf08f27f8c..f54f7cc263 100644
--- a/engine/src/main/java/org/apache/hop/www/PausePipelineServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/PausePipelineServlet.java
@@ -61,19 +61,23 @@ public class PausePipelineServlet extends BaseHttpServlet
implements IHopServerP
String pipelineName = request.getParameter("name");
String id = request.getParameter("id");
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
+ boolean useJson = isJsonRequest(request);
response.setStatus(HttpServletResponse.SC_OK);
- response.setCharacterEncoding("UTF-8");
-
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
try {
if (useXML) {
response.setContentType("text/xml");
response.setCharacterEncoding(Const.XML_ENCODING);
out.print(XmlHandler.getXmlHeader(Const.XML_ENCODING));
+ } else if (useJson) {
+ response.setContentType("application/json");
+ response.setCharacterEncoding(Const.XML_ENCODING);
} else {
-
response.setContentType("text/html;charset=UTF-8");
out.println("<HTML>");
out.println("<HEAD>");
@@ -133,6 +137,8 @@ public class PausePipelineServlet extends BaseHttpServlet
implements IHopServerP
if (useXML) {
out.println(new WebResult(WebResult.STRING_OK, message).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_OK, message).getJson());
} else {
out.println("<H1>" + Encode.forHtml(message) + "</H1>");
out.println(
@@ -152,6 +158,8 @@ public class PausePipelineServlet extends BaseHttpServlet
implements IHopServerP
if (useXML) {
out.println(new WebResult(WebResult.STRING_ERROR, message).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
message).getJson());
} else {
out.println("<H1>" + Encode.forHtml(message) + "</H1>");
out.println(
@@ -166,16 +174,18 @@ public class PausePipelineServlet extends BaseHttpServlet
implements IHopServerP
} catch (Exception ex) {
if (useXML) {
out.println(new WebResult(WebResult.STRING_ERROR,
Const.getStackTracker(ex)).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
Const.getStackTracker(ex)).getJson());
} else {
out.println("<p>");
out.println("<pre>");
- out.println(Const.getStackTracker(ex));
+ out.println(Encode.forHtml(Const.getStackTracker(ex)));
out.println("</pre>");
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
}
- if (!useXML) {
+ if (!useXML && !useJson) {
out.println("<p>");
out.println("</BODY>");
out.println("</HTML>");
diff --git
a/engine/src/main/java/org/apache/hop/www/PrepareExecutionPipelineServlet.java
b/engine/src/main/java/org/apache/hop/www/PrepareExecutionPipelineServlet.java
index 64bfac145a..93ba820393 100644
---
a/engine/src/main/java/org/apache/hop/www/PrepareExecutionPipelineServlet.java
+++
b/engine/src/main/java/org/apache/hop/www/PrepareExecutionPipelineServlet.java
@@ -72,16 +72,22 @@ public class PrepareExecutionPipelineServlet extends
BaseHttpServlet implements
String pipelineName = request.getParameter("name");
String id = request.getParameter("id");
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
+ boolean useJson = isJsonRequest(request);
response.setStatus(HttpServletResponse.SC_OK);
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
if (useXML) {
response.setContentType("text/xml");
+ response.setCharacterEncoding(Const.XML_ENCODING);
out.print(XmlHandler.getXmlHeader(Const.XML_ENCODING));
+ } else if (useJson) {
+ response.setContentType("application/json");
+ response.setCharacterEncoding(Const.XML_ENCODING);
} else {
-
- response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
out.println("<HTML>");
@@ -140,8 +146,9 @@ public class PrepareExecutionPipelineServlet extends
BaseHttpServlet implements
if (useXML) {
out.println(WebResult.OK.getXml());
+ } else if (useJson) {
+ out.println(WebResult.OK.getJson());
} else {
-
out.println(
CONST_HEADER_OPEN
+ Encode.forHtml(
@@ -164,19 +171,20 @@ public class PrepareExecutionPipelineServlet extends
BaseHttpServlet implements
HopLogStore.getAppender()
.getBuffer(pipeline.getLogChannel().getLogChannelId(), true)
.toString();
+ String errorMsg =
+ BaseMessages.getString(
+ PKG,
+ "PrepareExecutionPipelineServlet.Error.PipelineInitFailed",
+ Const.CR
+ + logText
+ + Const.CR
+ + Const.getSimpleStackTrace(e)
+ + Const.CR
+ + Const.getStackTracker(e));
if (useXML) {
- out.println(
- new WebResult(
- WebResult.STRING_ERROR,
- BaseMessages.getString(
- PKG,
-
"PrepareExecutionPipelineServlet.Error.PipelineInitFailed",
- Const.CR
- + logText
- + Const.CR
- + Const.getSimpleStackTrace(e)
- + Const.CR
- + Const.getStackTracker(e))));
+ out.println(new WebResult(WebResult.STRING_ERROR,
errorMsg).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
errorMsg).getJson());
} else {
out.println(
CONST_HEADER_OPEN
@@ -204,12 +212,13 @@ public class PrepareExecutionPipelineServlet extends
BaseHttpServlet implements
}
}
} else {
+ String notFoundMsg =
+ BaseMessages.getString(
+ PKG, "PipelineStatusServlet.Log.CoundNotFindSpecPipeline",
pipelineName);
if (useXML) {
- out.println(
- new WebResult(
- WebResult.STRING_ERROR,
- BaseMessages.getString(
- PKG,
"PipelineStatusServlet.Log.CoundNotFindSpecPipeline", pipelineName)));
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getJson());
} else {
out.println(
CONST_HEADER_OPEN
@@ -227,14 +236,15 @@ public class PrepareExecutionPipelineServlet extends
BaseHttpServlet implements
}
}
} catch (Exception ex) {
+ String errorMsg =
+ BaseMessages.getString(
+ PKG,
+ "PrepareExecutionPipelineServlet.Error.UnexpectedError",
+ Const.CR + Const.getStackTracker(ex));
if (useXML) {
- out.println(
- new WebResult(
- WebResult.STRING_ERROR,
- BaseMessages.getString(
- PKG,
- "PrepareExecutionPipelineServlet.Error.UnexpectedError",
- Const.CR + Const.getStackTracker(ex))));
+ out.println(new WebResult(WebResult.STRING_ERROR, errorMsg).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR, errorMsg).getJson());
} else {
out.println("<p>");
out.println("<pre>");
@@ -244,7 +254,7 @@ public class PrepareExecutionPipelineServlet extends
BaseHttpServlet implements
}
}
- if (!useXML) {
+ if (!useXML && !useJson) {
out.println("<p>");
out.println("</BODY>");
out.println("</HTML>");
diff --git
a/engine/src/main/java/org/apache/hop/www/RegisterExecutionInfoServlet.java
b/engine/src/main/java/org/apache/hop/www/RegisterExecutionInfoServlet.java
index f9fe921d5f..c738a7215d 100644
--- a/engine/src/main/java/org/apache/hop/www/RegisterExecutionInfoServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/RegisterExecutionInfoServlet.java
@@ -75,8 +75,14 @@ public class RegisterExecutionInfoServlet extends
BaseHttpServlet implements IHo
//
String locationName =
StringEscapeUtils.escapeHtml(request.getParameter(PARAMETER_LOCATION));
- PrintWriter out = response.getWriter();
- BufferedReader in = request.getReader();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
+ BufferedReader in = getSafeReader(request, response);
+ if (in == null) {
+ return;
+ }
response.setContentType("text/xml");
out.print(XmlHandler.getXmlHeader());
diff --git a/engine/src/main/java/org/apache/hop/www/RemovePipelineServlet.java
b/engine/src/main/java/org/apache/hop/www/RemovePipelineServlet.java
index d6427117ac..c461e34e03 100644
--- a/engine/src/main/java/org/apache/hop/www/RemovePipelineServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/RemovePipelineServlet.java
@@ -60,20 +60,16 @@ public class RemovePipelineServlet extends BaseHttpServlet
implements IHopServer
String pipelineName = request.getParameter("name");
String id = request.getParameter("id");
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
+ boolean useJson = isJsonRequest(request);
response.setStatus(HttpServletResponse.SC_OK);
+ setResponseFormat(response, useXML, useJson);
- if (useXML) {
- response.setContentType("text/xml");
- response.setCharacterEncoding(Const.XML_ENCODING);
- } else {
- response.setContentType("text/html;charset=UTF-8");
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
}
- response.setCharacterEncoding("UTF-8");
-
- PrintWriter out = response.getWriter();
-
// ID is optional...
//
IPipelineEngine<PipelineMeta> pipeline;
@@ -101,13 +97,11 @@ public class RemovePipelineServlet extends BaseHttpServlet
implements IHopServer
getPipelineMap().removePipeline(entry);
if (useXML) {
- response.setContentType("text/xml");
- response.setCharacterEncoding(Const.XML_ENCODING);
out.print(XmlHandler.getXmlHeader(Const.XML_ENCODING));
out.print(WebResult.OK.getXml());
+ } else if (useJson) {
+ out.println(WebResult.OK.getJson());
} else {
- response.setContentType("text/html;charset=UTF-8");
-
out.println("<HTML>");
out.println("<HEAD>");
out.println(
@@ -136,12 +130,13 @@ public class RemovePipelineServlet extends
BaseHttpServlet implements IHopServer
out.println("</HTML>");
}
} else {
+ String notFoundMsg =
+ BaseMessages.getString(
+ PKG, "PipelineStatusServlet.Log.CoundNotFindSpecPipeline",
pipelineName);
if (useXML) {
- out.println(
- new WebResult(
- WebResult.STRING_ERROR,
- BaseMessages.getString(
- PKG, "PipelineStatusServlet.Log.CoundNotFindSpecPipeline",
pipelineName)));
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getJson());
} else {
out.println(
"<H1>"
diff --git a/engine/src/main/java/org/apache/hop/www/RemoveWorkflowServlet.java
b/engine/src/main/java/org/apache/hop/www/RemoveWorkflowServlet.java
index 897f26a05a..424b7a6afb 100644
--- a/engine/src/main/java/org/apache/hop/www/RemoveWorkflowServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/RemoveWorkflowServlet.java
@@ -61,18 +61,16 @@ public class RemoveWorkflowServlet extends BaseHttpServlet
implements IHopServer
String workflowName = request.getParameter("name");
String id = request.getParameter("id");
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
+ boolean useJson = isJsonRequest(request);
response.setStatus(HttpServletResponse.SC_OK);
+ setResponseFormat(response, useXML, useJson);
- if (useXML) {
- response.setContentType("text/xml");
- response.setCharacterEncoding(Const.XML_ENCODING);
- } else {
- response.setContentType("text/html;charset=UTF-8");
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
}
- PrintWriter out = response.getWriter();
-
// ID is optional...
//
IWorkflowEngine<WorkflowMeta> workflow;
@@ -99,13 +97,11 @@ public class RemoveWorkflowServlet extends BaseHttpServlet
implements IHopServer
getWorkflowMap().removeWorkflow(entry);
if (useXML) {
- response.setContentType("text/xml");
- response.setCharacterEncoding(Const.XML_ENCODING);
out.print(XmlHandler.getXmlHeader(Const.XML_ENCODING));
out.print(WebResult.OK.getXml());
+ } else if (useJson) {
+ out.println(WebResult.OK.getJson());
} else {
- response.setContentType("text/html;charset=UTF-8");
-
out.println("<HTML>");
out.println("<HEAD>");
out.println(
@@ -134,12 +130,13 @@ public class RemoveWorkflowServlet extends
BaseHttpServlet implements IHopServer
out.println("</HTML>");
}
} else {
+ String notFoundMsg =
+ BaseMessages.getString(
+ PKG, "RemoveWorkflowServlet.Log.CoundNotFindSpecWorkflow",
workflowName);
if (useXML) {
- out.println(
- new WebResult(
- WebResult.STRING_ERROR,
- BaseMessages.getString(
- PKG, "RemoveWorkflowServlet.Log.CoundNotFindSpecWorkflow",
workflowName)));
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getJson());
} else {
out.println(
"<H1>"
diff --git a/engine/src/main/java/org/apache/hop/www/SniffTransformServlet.java
b/engine/src/main/java/org/apache/hop/www/SniffTransformServlet.java
index f98e438fb0..73f2e3ac46 100644
--- a/engine/src/main/java/org/apache/hop/www/SniffTransformServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/SniffTransformServlet.java
@@ -19,6 +19,8 @@ package org.apache.hop.www;
import static java.nio.charset.StandardCharsets.UTF_8;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@@ -30,6 +32,7 @@ import java.util.List;
import org.apache.hop.core.Const;
import org.apache.hop.core.annotations.HopServerServlet;
import org.apache.hop.core.exception.HopTransformException;
+import org.apache.hop.core.json.HopJson;
import org.apache.hop.core.row.IRowMeta;
import org.apache.hop.core.row.IValueMeta;
import org.apache.hop.core.row.RowBuffer;
@@ -77,18 +80,16 @@ public class SniffTransformServlet extends BaseHttpServlet
implements IHopServer
final int nrLines = Const.toInt(request.getParameter("lines"), 0);
String type = Const.NVL(request.getParameter("type"), TYPE_OUTPUT);
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
+ boolean useJson = isJsonRequest(request);
response.setStatus(HttpServletResponse.SC_OK);
+ setResponseFormat(response, useXML, useJson);
- if (useXML) {
- response.setContentType("text/xml");
- response.setCharacterEncoding(Const.XML_ENCODING);
- } else {
- response.setContentType("text/html;charset=UTF-8");
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
}
- PrintWriter out = response.getWriter();
-
// ID is optional...
//
IPipelineEngine<PipelineMeta> pipeline;
@@ -201,6 +202,42 @@ public class SniffTransformServlet extends BaseHttpServlet
implements IHopServer
out.print(XmlHandler.getXmlHeader(Const.XML_ENCODING));
out.println(rowBuffer.getXml());
+ } else if (useJson) {
+
+ // Send the result back as JSON
+ //
+ try {
+ ObjectNode root = HopJson.newMapper().createObjectNode();
+ if (rowBuffer.getRowMeta() != null) {
+ ArrayNode fields = root.putArray("fields");
+ for (IValueMeta vm : rowBuffer.getRowMeta().getValueMetaList()) {
+ ObjectNode field = fields.addObject();
+ field.put("name", vm.getName());
+ field.put("type", vm.getTypeDesc());
+ }
+ ArrayNode rows = root.putArray("rows");
+ for (Object[] rowData : rowBuffer.getBuffer()) {
+ ArrayNode row = rows.addArray();
+ for (int v = 0; v < rowBuffer.getRowMeta().size(); v++) {
+ IValueMeta vm = rowBuffer.getRowMeta().getValueMeta(v);
+ try {
+ row.add(vm.getString(rowData[v]));
+ } catch (Exception e) {
+ row.addNull();
+ }
+ }
+ }
+ }
+ out.println(
+
HopJson.newMapper().writerWithDefaultPrettyPrinter().writeValueAsString(root));
+ } catch (Exception e) {
+ out.println(
+ new WebResult(
+ WebResult.STRING_ERROR,
+ "Failed to serialize rows to JSON: " + e.getMessage())
+ .getJson());
+ }
+
} else {
response.setContentType("text/html;charset=UTF-8");
@@ -273,24 +310,15 @@ public class SniffTransformServlet extends
BaseHttpServlet implements IHopServer
out.println("</HTML>");
}
} else {
+ String notFoundMsg =
+ BaseMessages.getString(
+ PKG, "SniffTransformServlet.Log.CoundNotFindSpecTransform",
transformName);
if (useXML) {
- out.println(
- new WebResult(
- WebResult.STRING_ERROR,
- BaseMessages.getString(
- PKG,
-
"SniffTransformServlet.Log.CoundNotFindSpecTransform",
- transformName))
- .getXml());
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getJson());
} else {
- out.println(
- CONST_HEADER_START
- + Encode.forHtml(
- BaseMessages.getString(
- PKG,
-
"SniffTransformServlet.Log.CoundNotFindSpecTransform",
- transformName))
- + CONST_HEADER_END);
+ out.println(CONST_HEADER_START + Encode.forHtml(notFoundMsg) +
CONST_HEADER_END);
out.println(
"<a href=\""
+ convertContextPath(GetStatusServlet.CONTEXT_PATH)
@@ -300,13 +328,13 @@ public class SniffTransformServlet extends
BaseHttpServlet implements IHopServer
}
}
} else {
+ String notFoundMsg =
+ BaseMessages.getString(
+ PKG, "SniffTransformServlet.Log.CoundNotFindSpecPipeline",
pipelineName);
if (useXML) {
- out.println(
- new WebResult(
- WebResult.STRING_ERROR,
- BaseMessages.getString(
- PKG,
"SniffTransformServlet.Log.CoundNotFindSpecPipeline", pipelineName))
- .getXml());
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getJson());
} else {
out.println(
CONST_HEADER_START
diff --git
a/engine/src/main/java/org/apache/hop/www/StartExecutionPipelineServlet.java
b/engine/src/main/java/org/apache/hop/www/StartExecutionPipelineServlet.java
index 954c295055..dff3a56902 100644
--- a/engine/src/main/java/org/apache/hop/www/StartExecutionPipelineServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/StartExecutionPipelineServlet.java
@@ -65,11 +65,19 @@ public class StartExecutionPipelineServlet extends
BaseHttpServlet implements IH
String pipelineName =
StringEscapeUtils.escapeHtml(request.getParameter("name"));
String id = request.getParameter("id");
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
+ boolean useJson = isJsonRequest(request);
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
if (useXML) {
response.setContentType("text/xml");
+ response.setCharacterEncoding(Const.XML_ENCODING);
out.print(XmlHandler.getXmlHeader(Const.XML_ENCODING));
+ } else if (useJson) {
+ response.setContentType("application/json");
+ response.setCharacterEncoding(Const.XML_ENCODING);
} else {
response.setContentType("text/html;charset=UTF-8");
out.println("<HTML>");
@@ -119,6 +127,8 @@ public class StartExecutionPipelineServlet extends
BaseHttpServlet implements IH
if (useXML) {
out.println(WebResult.OK.getXml());
+ } else if (useJson) {
+ out.println(WebResult.OK.getJson());
} else {
out.println(
"<H1>Pipeline "
@@ -139,7 +149,9 @@ public class StartExecutionPipelineServlet extends
BaseHttpServlet implements IH
+ pipelineName
+ "] is not ready to be started. (Was not prepared for
execution)";
if (useXML) {
- out.println(new WebResult(WebResult.STRING_ERROR, message));
+ out.println(new WebResult(WebResult.STRING_ERROR,
message).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
message).getJson());
} else {
out.println("<H1>" + Encode.forHtml(message) + "</H1>");
out.println(
@@ -151,12 +163,13 @@ public class StartExecutionPipelineServlet extends
BaseHttpServlet implements IH
}
}
} else {
+ String notFoundMsg =
+ BaseMessages.getString(
+ PKG, "PipelineStatusServlet.Log.CoundNotFindSpecPipeline",
pipelineName);
if (useXML) {
- out.println(
- new WebResult(
- WebResult.STRING_ERROR,
- BaseMessages.getString(
- PKG,
"PipelineStatusServlet.Log.CoundNotFindSpecPipeline", pipelineName)));
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
notFoundMsg).getJson());
} else {
out.println(
"<H1>"
@@ -173,13 +186,14 @@ public class StartExecutionPipelineServlet extends
BaseHttpServlet implements IH
}
}
} catch (Exception ex) {
+ String errorMsg =
+ "Unexpected error during pipeline execution preparation:"
+ + Const.CR
+ + Const.getStackTracker(ex);
if (useXML) {
- out.println(
- new WebResult(
- WebResult.STRING_ERROR,
- "Unexpected error during pipeline execution preparation:"
- + Const.CR
- + Const.getStackTracker(ex)));
+ out.println(new WebResult(WebResult.STRING_ERROR, errorMsg).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR, errorMsg).getJson());
} else {
out.println("<p>");
out.println("<pre>");
@@ -188,7 +202,7 @@ public class StartExecutionPipelineServlet extends
BaseHttpServlet implements IH
}
}
- if (!useXML) {
+ if (!useXML && !useJson) {
out.println("<p>");
out.println("</BODY>");
out.println("</HTML>");
diff --git a/engine/src/main/java/org/apache/hop/www/StartPipelineServlet.java
b/engine/src/main/java/org/apache/hop/www/StartPipelineServlet.java
index 331345e924..c79ca44679 100644
--- a/engine/src/main/java/org/apache/hop/www/StartPipelineServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/StartPipelineServlet.java
@@ -73,14 +73,21 @@ public class StartPipelineServlet extends BaseHttpServlet
implements IHopServerP
pipelineName = "";
}
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
+ boolean useJson = isJsonRequest(request);
response.setStatus(HttpServletResponse.SC_OK);
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
if (useXML) {
response.setContentType("text/xml");
response.setCharacterEncoding(Const.XML_ENCODING);
out.print(XmlHandler.getXmlHeader(Const.XML_ENCODING));
+ } else if (useJson) {
+ response.setContentType("application/json");
+ response.setCharacterEncoding(Const.XML_ENCODING);
} else {
response.setContentType("text/html;charset=UTF-8");
out.println("<HTML>");
@@ -141,8 +148,9 @@ public class StartPipelineServlet extends BaseHttpServlet
implements IHopServerP
BaseMessages.getString(PKG,
"StartPipelineServlet.Log.PipelineStarted", pipelineName);
if (useXML) {
out.println(new WebResult(WebResult.STRING_OK, message).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_OK, message).getJson());
} else {
-
out.println("<H1>" + Encode.forHtml(message) + "</H1>");
out.println(
"<a href=\""
@@ -160,7 +168,9 @@ public class StartPipelineServlet extends BaseHttpServlet
implements IHopServerP
BaseMessages.getString(
PKG, "PipelineStatusServlet.Log.CoundNotFindSpecPipeline",
pipelineName);
if (useXML) {
- out.println(new WebResult(WebResult.STRING_ERROR, message, id));
+ out.println(new WebResult(WebResult.STRING_ERROR, message,
id).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR, message,
id).getJson());
} else {
out.println("<H1>" + Encode.forHtml(message) + "</H1>");
out.println(
@@ -173,14 +183,15 @@ public class StartPipelineServlet extends BaseHttpServlet
implements IHopServerP
}
}
} catch (Exception ex) {
+ String errorMsg =
+ BaseMessages.getString(
+ PKG,
+ "StartPipelineServlet.Error.UnexpectedError",
+ Const.CR + Const.getStackTracker(ex));
if (useXML) {
- out.println(
- new WebResult(
- WebResult.STRING_ERROR,
- BaseMessages.getString(
- PKG,
- "StartPipelineServlet.Error.UnexpectedError",
- Const.CR + Const.getStackTracker(ex))));
+ out.println(new WebResult(WebResult.STRING_ERROR, errorMsg).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR, errorMsg).getJson());
} else {
out.println("<p>");
out.println("<pre>");
@@ -190,7 +201,7 @@ public class StartPipelineServlet extends BaseHttpServlet
implements IHopServerP
}
}
- if (!useXML) {
+ if (!useXML && !useJson) {
out.println("<p>");
out.println("</BODY>");
out.println("</HTML>");
diff --git a/engine/src/main/java/org/apache/hop/www/StartWorkflowServlet.java
b/engine/src/main/java/org/apache/hop/www/StartWorkflowServlet.java
index 202f15ca09..6ff69acdb0 100644
--- a/engine/src/main/java/org/apache/hop/www/StartWorkflowServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/StartWorkflowServlet.java
@@ -72,14 +72,21 @@ public class StartWorkflowServlet extends BaseHttpServlet
implements IHopServerP
String workflowName =
StringEscapeUtils.escapeHtml(request.getParameter("name"));
String id = StringEscapeUtils.escapeHtml(request.getParameter("id"));
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
+ boolean useJson = isJsonRequest(request);
response.setStatus(HttpServletResponse.SC_OK);
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
if (useXML) {
response.setContentType("text/xml");
response.setCharacterEncoding(Const.XML_ENCODING);
out.print(XmlHandler.getXmlHeader(Const.XML_ENCODING));
+ } else if (useJson) {
+ response.setContentType("application/json");
+ response.setCharacterEncoding(Const.XML_ENCODING);
} else {
response.setContentType("text/html;charset=UTF-8");
out.println("<HTML>");
@@ -164,8 +171,10 @@ public class StartWorkflowServlet extends BaseHttpServlet
implements IHopServerP
if (useXML) {
out.println(
new WebResult(WebResult.STRING_OK, message,
workflow.getContainerId()).getXml());
+ } else if (useJson) {
+ out.println(
+ new WebResult(WebResult.STRING_OK, message,
workflow.getContainerId()).getJson());
} else {
-
out.println("<H1>" + Encode.forHtml(message) + "</H1>");
out.println(
"<a href=\""
@@ -183,7 +192,9 @@ public class StartWorkflowServlet extends BaseHttpServlet
implements IHopServerP
BaseMessages.getString(
PKG, "StartWorkflowServlet.Log.SpecifiedWorkflowNotFound",
workflowName);
if (useXML) {
- out.println(new WebResult(WebResult.STRING_ERROR, message));
+ out.println(new WebResult(WebResult.STRING_ERROR, message).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
message).getJson());
} else {
out.println("<H1>" + Encode.forHtml(message) + "</H1>");
out.println(
@@ -196,14 +207,15 @@ public class StartWorkflowServlet extends BaseHttpServlet
implements IHopServerP
}
}
} catch (Exception ex) {
+ String errorMsg =
+ BaseMessages.getString(
+ PKG,
+ "StartWorkflowServlet.Error.UnexpectedError",
+ Const.CR + Const.getStackTracker(ex));
if (useXML) {
- out.println(
- new WebResult(
- WebResult.STRING_ERROR,
- BaseMessages.getString(
- PKG,
- "StartWorkflowServlet.Error.UnexpectedError",
- Const.CR + Const.getStackTracker(ex))));
+ out.println(new WebResult(WebResult.STRING_ERROR, errorMsg).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR, errorMsg).getJson());
} else {
out.println("<p>");
out.println("<pre>");
@@ -213,7 +225,7 @@ public class StartWorkflowServlet extends BaseHttpServlet
implements IHopServerP
}
}
- if (!useXML) {
+ if (!useXML && !useJson) {
out.println("<p>");
out.println("</BODY>");
out.println("</HTML>");
diff --git a/engine/src/main/java/org/apache/hop/www/StopPipelineServlet.java
b/engine/src/main/java/org/apache/hop/www/StopPipelineServlet.java
index 6530af17be..5b7578acc6 100644
--- a/engine/src/main/java/org/apache/hop/www/StopPipelineServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/StopPipelineServlet.java
@@ -62,13 +62,20 @@ public class StopPipelineServlet extends BaseHttpServlet
implements IHopServerPl
String id = request.getParameter("id");
boolean inputOnly =
"Y".equalsIgnoreCase(request.getParameter("inputOnly"));
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
+ boolean useJson = isJsonRequest(request);
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
try {
if (useXML) {
response.setContentType("text/xml");
response.setCharacterEncoding(Const.XML_ENCODING);
out.print(XmlHandler.getXmlHeader(Const.XML_ENCODING));
+ } else if (useJson) {
+ response.setContentType("application/json");
+ response.setCharacterEncoding(Const.XML_ENCODING);
} else {
response.setContentType("text/html;charset=UTF-8");
out.println("<HTML>");
@@ -120,6 +127,8 @@ public class StopPipelineServlet extends BaseHttpServlet
implements IHopServerPl
if (useXML) {
out.println(new WebResult(WebResult.STRING_OK, message,
id).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_OK, message,
id).getJson());
} else {
out.println("<H1>" + Encode.forHtml(message) + "</H1>");
out.println(
@@ -139,6 +148,8 @@ public class StopPipelineServlet extends BaseHttpServlet
implements IHopServerPl
if (useXML) {
out.println(new WebResult(WebResult.STRING_ERROR, message,
id).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR, message,
id).getJson());
} else {
out.println("<H1>" + Encode.forHtml(message) + "</H1>");
out.println(
@@ -153,6 +164,8 @@ public class StopPipelineServlet extends BaseHttpServlet
implements IHopServerPl
} catch (Exception ex) {
if (useXML) {
out.println(new WebResult(WebResult.STRING_ERROR,
Const.getStackTracker(ex)).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
Const.getStackTracker(ex)).getJson());
} else {
out.println("<p>");
out.println("<pre>");
@@ -162,7 +175,7 @@ public class StopPipelineServlet extends BaseHttpServlet
implements IHopServerPl
}
}
- if (!useXML) {
+ if (!useXML && !useJson) {
out.println("<p>");
out.println("</BODY>");
out.println("</HTML>");
diff --git a/engine/src/main/java/org/apache/hop/www/StopWorkflowServlet.java
b/engine/src/main/java/org/apache/hop/www/StopWorkflowServlet.java
index 4688cc227a..b199f43ce9 100644
--- a/engine/src/main/java/org/apache/hop/www/StopWorkflowServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/StopWorkflowServlet.java
@@ -61,13 +61,20 @@ public class StopWorkflowServlet extends BaseHttpServlet
implements IHopServerPl
String workflowName = request.getParameter("name");
String id = request.getParameter("id");
boolean useXML = "Y".equalsIgnoreCase(request.getParameter("xml"));
+ boolean useJson = isJsonRequest(request);
- PrintWriter out = response.getWriter();
+ PrintWriter out = getSafeWriter(response);
+ if (out == null) {
+ return;
+ }
try {
if (useXML) {
response.setContentType("text/xml");
response.setCharacterEncoding(Const.XML_ENCODING);
out.print(XmlHandler.getXmlHeader(Const.XML_ENCODING));
+ } else if (useJson) {
+ response.setContentType("application/json");
+ response.setCharacterEncoding(Const.XML_ENCODING);
} else {
response.setContentType("text/html;charset=UTF-8");
out.println("<HTML>");
@@ -113,6 +120,8 @@ public class StopWorkflowServlet extends BaseHttpServlet
implements IHopServerPl
PKG, "WorkflowStatusServlet.Log.WorkflowStopRequested",
workflowName);
if (useXML) {
out.println(new WebResult(WebResult.STRING_OK, message).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_OK, message).getJson());
} else {
out.println("<H1>" + Encode.forHtml(message) + "</H1>");
out.println(
@@ -132,12 +141,14 @@ public class StopWorkflowServlet extends BaseHttpServlet
implements IHopServerPl
PKG, "StopWorkflowServlet.Log.CoundNotFindWorkflow",
workflowName);
if (useXML) {
out.println(new WebResult(WebResult.STRING_ERROR, message).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
message).getJson());
} else {
out.println("<H1>" + Encode.forHtml(message) + "</H1>");
out.println(
"<a href=\""
+ convertContextPath(GetStatusServlet.CONTEXT_PATH)
- + ">"
+ + "\">"
+ BaseMessages.getString(PKG,
"PipelineStatusServlet.BackToStatusPage")
+ "</a><p>");
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
@@ -146,6 +157,8 @@ public class StopWorkflowServlet extends BaseHttpServlet
implements IHopServerPl
} catch (Exception ex) {
if (useXML) {
out.println(new WebResult(WebResult.STRING_ERROR,
Const.getStackTracker(ex)).getXml());
+ } else if (useJson) {
+ out.println(new WebResult(WebResult.STRING_ERROR,
Const.getStackTracker(ex)).getJson());
} else {
out.println("<p>");
out.println("<pre>");
@@ -155,7 +168,7 @@ public class StopWorkflowServlet extends BaseHttpServlet
implements IHopServerPl
}
}
- if (!useXML) {
+ if (!useXML && !useJson) {
out.println("<p>");
out.println("</BODY>");
out.println("</HTML>");
diff --git a/engine/src/main/java/org/apache/hop/www/WebResult.java
b/engine/src/main/java/org/apache/hop/www/WebResult.java
index dc1c5a21e0..362295041e 100644
--- a/engine/src/main/java/org/apache/hop/www/WebResult.java
+++ b/engine/src/main/java/org/apache/hop/www/WebResult.java
@@ -17,8 +17,10 @@
package org.apache.hop.www;
+import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.hop.core.Const;
import org.apache.hop.core.exception.HopXmlException;
+import org.apache.hop.core.json.HopJson;
import org.apache.hop.core.xml.XmlHandler;
import org.apache.hop.i18n.BaseMessages;
import org.w3c.dom.Document;
@@ -66,6 +68,14 @@ public class WebResult {
return xml.toString();
}
+ public String getJson() {
+ try {
+ return
HopJson.newMapper().writerWithDefaultPrettyPrinter().writeValueAsString(this);
+ } catch (JsonProcessingException e) {
+ return "{\"result\":\"ERROR\",\"message\":\"Failed to serialize response
to JSON\",\"id\":null}";
+ }
+ }
+
@Override
public String toString() {
return getXml();
diff --git a/engine/src/main/java/org/apache/hop/www/WebServer.java
b/engine/src/main/java/org/apache/hop/www/WebServer.java
index a3c90552b3..273f0907ea 100644
--- a/engine/src/main/java/org/apache/hop/www/WebServer.java
+++ b/engine/src/main/java/org/apache/hop/www/WebServer.java
@@ -49,12 +49,12 @@ import org.eclipse.jetty.ee11.servlet.ServletHolder;
import org.eclipse.jetty.ee11.servlet.security.ConstraintMapping;
import org.eclipse.jetty.ee11.servlet.security.ConstraintSecurityHandler;
import org.eclipse.jetty.http.HttpVersion;
-import org.eclipse.jetty.jaas.JAASLoginService;
import org.eclipse.jetty.security.Authenticator;
import org.eclipse.jetty.security.Constraint;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.PropertyUserStore;
import org.eclipse.jetty.security.UserStore;
+import org.eclipse.jetty.security.jaas.JAASLoginService;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
diff --git a/engine/src/main/java/org/apache/hop/www/WebServiceServlet.java
b/engine/src/main/java/org/apache/hop/www/WebServiceServlet.java
index d35fa9ccf8..4807278f0f 100644
--- a/engine/src/main/java/org/apache/hop/www/WebServiceServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/WebServiceServlet.java
@@ -72,7 +72,15 @@ public class WebServiceServlet extends BaseHttpServlet
implements IHopServerPlug
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse
response)
throws ServletException, IOException {
- this.doGet(request, response);
+ try {
+ doGet(request, response);
+ } catch (Exception e) {
+ logError("Error handling web service POST request", e);
+ sendSafeError(
+ response,
+ HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+ "Unable to process web service request.");
+ }
}
@Override
diff --git a/lib/pom.xml b/lib/pom.xml
index 9770194ddb..935323e301 100644
--- a/lib/pom.xml
+++ b/lib/pom.xml
@@ -95,7 +95,6 @@
<jackson.version>2.21.1</jackson.version>
<jakarta.version>3.1.0</jakarta.version>
<javassist.version>3.30.2-GA</javassist.version>
- <jetty-jaas.version>11.0.26</jetty-jaas.version>
<jetty.version>12.1.7</jetty.version>
<jna.version>5.18.1</jna.version>
<joda-time.version>2.14.0</joda-time.version>
@@ -105,6 +104,7 @@
<json-smart.version>2.6.0</json-smart.version>
<json4s.version>3.7.0-M11</json4s.version>
<jsoup.version>1.22.1</jsoup.version>
+ <jspecify.version>1.0.0</jspecify.version>
<juniversalchardet.version>2.5.0</juniversalchardet.version>
<kafka-avro-serializer.version>7.6.1</kafka-avro-serializer.version>
<kafka-clients.version>3.9.2</kafka-clients.version>
@@ -674,8 +674,33 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-jaas</artifactId>
- <version>${jetty-jaas.version}</version>
+ <artifactId>jetty-alpn-client</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-client</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.compression</groupId>
+ <artifactId>jetty-compression-common</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.compression</groupId>
+ <artifactId>jetty-compression-gzip</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-http</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
+ <version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
@@ -712,6 +737,11 @@
<artifactId>jetty-xml</artifactId>
<version>${jetty.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.jspecify</groupId>
+ <artifactId>jspecify</artifactId>
+ <version>${jspecify.version}</version>
+ </dependency>
<dependency>
<groupId>org.glassfish.tyrus.bundles</groupId>
<artifactId>tyrus-standalone-client</artifactId>
diff --git a/plugins/engines/beam/src/assembly/assembly.xml
b/plugins/engines/beam/src/assembly/assembly.xml
index 147409ab8d..b053fef2b5 100644
--- a/plugins/engines/beam/src/assembly/assembly.xml
+++ b/plugins/engines/beam/src/assembly/assembly.xml
@@ -85,6 +85,7 @@
<exclude>org.apache.kafka::jar</exclude>
<exclude>org.xerial.snappy:snappy-java:jar</exclude>
<exclude>org.eclipse.jetty::jar</exclude>
+ <exclude>org.eclipse.jetty.compression::jar</exclude>
<exclude>com.google.cloud:google-cloud-storage:jar</exclude>
<exclude>io.grpc::jar</exclude>
<exclude>com.google.cloud:google-cloud-core-grpc:jar</exclude>
diff --git
a/plugins/misc/rest/src/main/java/org/apache/hop/metadata/rest/RestConnection.java
b/plugins/misc/rest/src/main/java/org/apache/hop/metadata/rest/RestConnection.java
index 6fa2f65890..08d76a7e2e 100644
---
a/plugins/misc/rest/src/main/java/org/apache/hop/metadata/rest/RestConnection.java
+++
b/plugins/misc/rest/src/main/java/org/apache/hop/metadata/rest/RestConnection.java
@@ -60,6 +60,8 @@ import
org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
documentationUrl = "/metadata-types/rest-connection.html",
hopMetadataPropertyType = HopMetadataPropertyType.REST_CONNECTION,
supportsGlobalReplace = true)
+// It is optional to disable SSL/TLS
+@SuppressWarnings({"java:S5527", "java:S4830", "java:S4423"})
public class RestConnection extends HopMetadataBase implements IHopMetadata {
public static final String BASIC = "Basic";
public static final String API_KEY = "API Key";
@@ -241,7 +243,7 @@ public class RestConnection extends HopMetadataBase
implements IHopMetadata {
response.close();
}
- public void disconnect() throws HopException {
+ public void disconnect() {
client.close();
}
diff --git a/plugins/tech/google/pom.xml b/plugins/tech/google/pom.xml
index 7eabddec53..87ebc665c0 100755
--- a/plugins/tech/google/pom.xml
+++ b/plugins/tech/google/pom.xml
@@ -37,7 +37,6 @@
<google-api-drive.version>v3-rev20250216-2.0.0</google-api-drive.version>
<google-api-sheets.version>v4-rev20250211-2.0.0</google-api-sheets.version>
<google-api-sqladmin.version>v1-rev20230721-2.0.0</google-api-sqladmin.version>
- <jetty-client.version>12.1.2</jetty-client.version>
</properties>
<dependencyManagement>
@@ -185,7 +184,6 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
- <version>${jetty-client.version}</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.jetty.ee11</groupId>
diff --git a/pom.xml b/pom.xml
index bff202c52b..962e2f5b1b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -110,6 +110,7 @@
<jandex.version>3.5.3</jandex.version>
<java-hamcrest.version>2.0.0.0</java-hamcrest.version>
<javadoc.failOnWarnings>false</javadoc.failOnWarnings>
+ <jetty.version>12.1.7</jetty.version>
<junit.version>6.0.3</junit.version>
<license.bundleLicenseFile>META-INF/LICENSE.txt</license.bundleLicenseFile>
<license.failOnLicenseCheck>false</license.failOnLicenseCheck>
@@ -165,6 +166,39 @@
<dependencyManagement>
<dependencies>
+ <!-- Jetty: transitive deps (e.g. jersey-jetty-connector) can pull
older patch lines (12.1.2).
+ hop-libs already pins Jetty for modules that import it; root
entries cover the rest of
+ the reactor without importing hop-libs (would cycle: hop ->
hop-libs -> parent hop). -->
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-alpn-client</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-client</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.compression</groupId>
+ <artifactId>jetty-compression-common</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.compression</groupId>
+ <artifactId>jetty-compression-gzip</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-http</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-io</artifactId>
+ <version>${jetty.version}</version>
+ </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>