Loading…
Loading…
Describes the IngestXmlErrorHandler, which replaces the default JAXP handler to prevent log flooding and securely log XML parsing errors from untrusted
The IngestXmlErrorHandler is a specialized error handler for XML parsing operations on the API ingest path. It is designed to be a drop-in replacement for the default Java API for XML Processing (JAXP) error handler.
The primary problem this component solves is noisy and uncontrollable logging from the default JAXP ErrorHandler. When a DocumentBuilder is not given a specific handler, it uses a default that writes all parsing errors, including fatal ones, directly to the System.err stream. On the ingest path, where the system processes untrusted traffic from API consumers, malformed XML is an ordinary and expected occurrence. The default handler's behavior turns these expected events into a high-volume stream of unformatted log messages that cannot be filtered or managed by standard logging configuration. This can lead to significant operational issues, such as rapid disk space consumption from log files.
IngestXmlErrorHandler resolves this by intercepting all parsing diagnostics and routing them through the standard SLF4J logging framework at the DEBUG level. This silences the noise during normal operation while preserving the ability to inspect parsing failures for diagnostic purposes by adjusting the log level.
IMPORTANT
Every DOM parse operation on the ingest path must be configured to use this ErrorHandler to prevent system log flooding and ensure stable operation.
The IngestXmlErrorHandler implements the standard org.xml.sax.ErrorHandler interface. It is a stateless singleton, accessible via the IngestXmlErrorHandler.INSTANCE static field, which can be shared across all XML parsers.
When an XML parser configured with this handler encounters a warning, error, or fatal error, it invokes the corresponding method on the handler instance.
flowchart TD
subgraph "Legacy Behavior (Default JAXP Handler)"
direction TD
A[Untrusted XML Payload] --> B{JAXP Parser};
B -- Parse Failure --> C[Default ErrorHandler];
C --> D["System.err Stream"];
D --> E[Unstructured Log Flood];
end
subgraph "Current Behavior (IngestXmlErrorHandler)"
direction TD
F[Untrusted XML Payload] --> G{JAXP Parser};
G -- Parse Failure --> H[IngestXmlErrorHandler];
H --> I["SLF4J Logger"];
I --> J["Structured DEBUG Log"];
endThe handler's behavior is designed to be a safe replacement for the JAXP default, ensuring that parsing control flow remains predictable.
warning(SAXParseException): Logs the event at DEBUG level and returns. The parser is allowed to continue processing.error(SAXParseException): Logs the event at DEBUG level and returns. This treats recoverable errors as non-fatal, allowing the parser to attempt to continue, mirroring the default handler's behavior.fatalError(SAXParseException): Logs the event at DEBUG level and immediately re-throws the SAXException. This is a deliberate design choice to guarantee that parsing is aborted. It prevents the system's behavior from changing based on underlying parser properties (like continue-after-fatal-error) that a calling component might not have set.To prevent sensitive data from API consumer payloads from appearing in logs, all error messages are sanitized before being written. This process ensures that the structural reason for the parse failure is logged, but any actual data from the XML document is masked.
The sanitization logic performs the following steps:
"...") or single ('...') quotes in the exception message and replaces it with an ellipsis (…). Parsers often quote element names, attribute values, or character content in error messages.For example, a raw parser message like The element type "user" must be terminated by the matching end-tag "</user>". is sanitized to mask the specific element name.
The IngestXmlErrorHandler is a stateless singleton and should be retrieved via its static INSTANCE field.
While the source does not provide a complete, self-contained code example, the handler is intended to be passed to a javax.xml.parsers.DocumentBuilder instance via its setErrorHandler method before parsing a document.
// Conceptual usage - not a complete, runnable example
import com.specaria.s2r.worker.service.IngestXmlErrorHandler;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.xml.sax.InputSource;
// 1. Obtain a DocumentBuilder instance
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
// 2. Set the custom error handler
builder.setErrorHandler(IngestXmlErrorHandler.INSTANCE);
// 3. Parse the document. Any errors will be handled by IngestXmlErrorHandler.
// A SAXException will be thrown for fatal errors.
try {
builder.parse(new InputSource(/* ... untrusted XML stream ... */));
} catch (SAXException e) {
// Handle fatal parse failure
}
The IngestXmlErrorHandler class is final and implements the org.xml.sax.ErrorHandler interface.
| Name | Type | Description |
|---|---|---|
INSTANCE | IngestXmlErrorHandler | A shared, stateless singleton instance of the handler. |
| Method | Description |
|---|---|
warning(SAXParseException ex) | Logs a recoverable XML parse warning at DEBUG level. The parser is permitted to continue. |
error(SAXParseException ex) | Logs a recoverable XML parse error at DEBUG level. The parser is permitted to continue. |
fatalError(SAXParseException ex) | Logs a non-recoverable XML parse error at DEBUG level and re-throws the exception to halt parsing. Throws SAXException. |
If the log level for com.specaria.s2r.worker.service.IngestXmlErrorHandler is set to DEBUG, you may see messages in the logs with the following format:
ingest XML parse warning at <line>:<column>: <sanitized_message>
ingest XML parse error at <line>:<column>: <sanitized_message>
ingest XML parse failed at <line>:<column>: <sanitized_message>
These messages indicate that the service received and attempted to parse a malformed XML document. This is expected behavior when processing untrusted traffic from API consumers and does not signify a fault in the service itself. The sanitized message provides a safe-to-log reason for the failure, such as Content is not allowed in prolog.
If you observe raw, unformatted XML parsing errors written to System.err or appearing directly in syslog (e.g., [Fatal Error] :3:1: Content is not allowed in prolog.), it indicates that an XML parser on the ingest path has not been configured with IngestXmlErrorHandler. This misconfiguration causes the parser to fall back to the problematic JAXP default handler. The component responsible for parsing the XML should be updated to correctly set the error handler.